What is Embedded MATLAB?

advertisement
Chapter 8: Creating Custom Blocks Part 2
Chapter 8: Creating Custom Blocks Part 2 ......................................................................... 1
Modeling an Echo Canceller using Embedded MATLAB ................................................. 1
What is Embedded MATLAB? .......................................................................................... 1
Embedded MATLAB By Example..................................................................................... 1
The Code Breakdown ......................................................................................................... 4
MATLAB Fixed-Point Quickie ...................................................................................... 8
Eml.extrinsic and the Special (:) Notation .................................................................... 11
Simulink Fixed-Point vs MATLAB Fixed-Point.............................................................. 12
Dealing with FIMATH Mismatches ............................................................................. 13
Using the Ports and Data Manager ........................................................................... 14
What About EMLC as Opposed to EML? ........................................................................ 19
By Example................................................................................................................... 20
General Guidelines on Writing EML Code ...................................................................... 21
Appendix A: Generated C Code ....................................................................................... 22
Modeling an Echo Canceller using Embedded MATLAB
What is Embedded MATLAB?
This chapter shows an alternative approach to modeling an echo canceller
using Embedded MATLAB or EML for short. EML is the subset of the
MATLAB language that runs in Simulink and supports C code generation.
Embedded MATLAB By Example
This is the top-level view of our echo canceller that uses Embedded
MATLAB. The other subsystems are identical to that used in previous
renditions of this model. When you press the play button a compiled version
of the MATLAB code in the green block is running and not the MATLAB code
itself.
Run this model. If it’s the first time you’ve run this model you will see
something interesting in the MATLAB Command Window. The Embedded
MATLAB code gets converted to C code and compiled to a DLL before the
model runs. On subsequent runs won’t see these messages since the DLL is
already generated.
Command window display after hitting play button.
Embedded MATLAB parsing for model "ec_fixed_eml_simple"...Done
Embedded MATLAB code generation for model
"ec_fixed_eml_simple"....Done
Embedded MATLAB compilation for model "ec_fixed_eml_simple"...
file(s) copied.
Done
1
The Echo_Canceller subsystem is taking in frames and outputting vectors.
The output lines are single wide where as the inputs are double-wide.
Effectively there is no difference in the simulation between the frames and
vectors.
As a matter of bookkeeping, you can convert from vectors to frames using
the ToFrame block in the Signal Processing Blockset/Signal
Management/Signal Attributes library. However it is unnecessary to do so in
the model and has no impact on the validity of the simulation.
Even down one-level it still looks familiar to other echo canceller models that
used S-function blocks or Simulink primitive blocks.
The Code Breakdown
But down one more level, we see MATLAB code. This is a fixed-point framebased implementation of the LMS algorithm. The LMS algorithm is really
only the last 10 lines of code in this 53 line m-file function. The preceding
lines are responsible for variable initialization and fixed-point setup.
Function [Wts, sout] = lms_fixed(rin, sinp)
% Paramter
persistent
persistent
persistent
initialization and memory allocation
w;
fifo;
mu;
% Using Fixed
filter_length
Wl
= 16; %
Wb
= 14; %
Ws
= 1; %
Point arithmetics
= 32;
word length
fractional size
signed
% create a numeric TYPE for the processor data
fi_type = numerictype('WordLength',Wl,...
'FractionLength',Wb,...
'Signed',Ws);
% Define how math will be performed
M
= 16;
% 32 bit multiply output
A
= 16;
% 32 bit accumulator, so we can generate C code
fi_math= fimath('ProductMode','SpecifyPrecision',...
'ProductWordLength',M,...
'ProductFractionLength',M-2,...
'SumMode','SpecifyPrecision',...
'SumWordLength',A,...
'SumFractionLength',M-2,...
'RoundMode','nearest',...
'OverflowMode','wrap',...
'CastBeforeSum',true);
% comment start
sinp_fimath = fimath(sinp);
y = fi(0,1,16,14,sinp_fimath);
% comment end
N = int16(length(rin));
if isempty(w)
fifo = fi(zeros(filter_length,1),fi_type,fi_math);
%y = fi(0,1,16,14,fi_math);
mu = fi(300/32768,1,16,15,fi_math);
w = fi(zeros(1,filter_length),1,16,15,fi_math);
end
% must have this re-initialization of sout
sout = fi(zeros(N,1),fi_type,fi_math);
% end sout init
% Loop over input vector
for n = 1:N
% Update fifo
fifo(1:filter_length-1) = fifo(2:filter_length);
fifo(filter_length) = rin(n);
% Update filter
y(:) = w*fifo;
sout(n) = sinp(n) - y;
err = mu * sout(n);
w(:) = w + err*fifo';
end
Wts = w'; % output a column vector, not a row
This is the same code all over again in text you can copy and paste.
Notice that those last 10 lines of MATLAB code have no fixed-point
notation. It could have just as well be floating-point code as fixed-point
code. That is one of the unique features of EML. You can write your code
once as floating-point and then add the necessary surrounding boilerplate to
make it fixed point capable. The keypoint is: the algorithm code remains the
same. That translates to lower maintenance and fewer chances for
translation mistakes. Contrast that with floating-point C to fixed-point C
where the algorithm code would have to be modified for bit shifting and
masking. Basically in C you would have to maintain two separate versions of
the code and manually try to keep them in sync at all times.
Let’s take a run through the code to see how the LMS filter was
implemented.
The first line defines the function name, input arguments, and output
arguments just like any MATLAB function. The size of the input and output
arrays is ascertained from the Simulink model.
Lines 4, 5, and 6 define persistent variables. These act like static variables
in C in that they retain their value from call to call. They will be initialized in
code to follow.
Lines 9 to 12 initialize variables to be used in the fixed-point setup. It would
appear that these variables will be re-initialized unnecessarily to these
values on every call to lms_fixed. For instance, it looks like variable
filter_length gets set to 32 on each function call to lms_fixed. Fortunately
such redundancy does not occur in the generated C code. The C code
generation engine sees this redundancy and avoids it. It does so by replacing
every usage of filter_length with a hard-coded 32. As such, what looks like a
variable in M code becomes in-lined in the C code. The important observation
to make is that M to C translation is not line by line. It’s not a literal or
direct translation. The M code is analyzed first as a whole and then
translated to C code before compilation to an executable format. Your Mcode’s comments are preserved however in their original relative locations.
Lines 15 to 31 set up the fixed point characteristics. Each fixed point
variable must have its word length and number of fractional bits set. Also
how the adds and multiplies are to be performed must be completely
specified. If you don’t specify these characteristics, then the default
behaviors will be used. In general it’s a good idea to make the fixed point
settings explicit.
MATLAB Fixed-Point Quickie
Every fixed point variable in MATLAB has three key descriptors:
1. Value: e.g. my_var = 8.875;
2. Type: e.g. sfix16_En10, a signed number 16 bits wide with 10
fractional bits
3. Math: how the adds and multiplies are handled, e.g. do full precision
multiplies.
For example,
% Give me the value for 8.875 in signed two’s complement with a 16 bit word
% length and 10 fraction bits.
>> my_var = fi(8.875,1,16,10)
my_var =
8.875000000000000
DataTypeMode: Fixed-point: binary point scaling
Signed: true
WordLength: 16
FractionLength: 10
RoundMode: nearest
OverflowMode: saturate
ProductMode: FullPrecision
MaxProductWordLength: 128
SumMode: FullPrecision
MaxSumWordLength: 128
CastBeforeSum: true
Or in binary,
>> my_var_bin = bin(my_var)
ans =
0010001110000000
which is
001000.1110000000
with the binary point inserted.
The fixed point object my_var also has FIMATH properties associated with
it even though we didn’t specify it. These are the default FIMATH settings.
Alternatively you could have set it yourself explicitly.
fi_math= fimath('ProductMode','SpecifyPrecision',...
'ProductWordLength',16,...
'ProductFractionLength',15,...
'SumMode','SpecifyPrecision',...
'SumWordLength',16,...
'SumFractionLength',15,...
'RoundMode','nearest',...
'OverflowMode','wrap',...
'CastBeforeSum',true);
Now we create my_var specifying FIMATH as input argument to the fi
constructor.
>> my_var = fi(8.875,1,16,10,fi_math)
my_var =
8.875000000000000
DataTypeMode: Fixed-point: binary point scaling
Signed: true
WordLength: 16
FractionLength: 10
RoundMode: nearest
OverflowMode: wrap
ProductMode: SpecifyPrecision
ProductWordLength: 16
ProductFractionLength: 15
SumMode: SpecifyPrecision
SumWordLength: 16
SumFractionLength: 15
CastBeforeSum: true
If you create another fixed point object my_other_var, the FIMATH
properties for both my_var and my_other_var must be identical if you are
multiplying or adding my_var and my_other_var. The numeric types do not
have to be equal however.
You can extract just the fimath properties for an object via structure
notation:
>> my_var.fimath
Or just get both numeric type and fimath information at the same time:
>> my_var.fi
Or, just word length
>> my_var.wordlength
Lines 34 to 39 initialize fixed point variables conditionally. If the variable w
has not been set yet, then we initialize not just w but other variables as well.
Again, this code does not end up being placed exactly where it appears in the
M code. The corresponding C code ends up in an initialization function called
separately separate from the LMS algorithm function. This initialization
function is only called once.
Line 41 initializes the output array sout. It does get re-initialized on every
call to lms_fixed. Currently that is a limitation associated with output
variables in EML.
Eml.extrinsic and the Special (:) Notation
Lines 43 to 53 is the LMS algorithm itself implemented using elementary
operators like + and *. It is true that there exists an “lms” object creation
function and an “equalize” function as part of the communications toolbox.
However these functions are not supported by EML so they are best
avoided. You can use such non-EML supported functions in EML if you
preface such usage with an eml.extrinsic call. For example, you would need to
place
eml.extrinsic(‘equalizer’)
before the invocation of the equalizer function. No C code will be generated
for the equalizer but it will still simulate through the MATLAB interpreter.
If you want an EML block that you can both simulate and generate C code
for, then you would have to write the LMS algorithm yourself and that is
what we did here.
Line 51 deserves special attention.
w(:) = w + err*fifo';
The (:) notation indicates that w should retain its data type after the w+
err*fifo’ sequence. If you omit the (:) then the fimath for w*fifo is a Q2.14
number while w was specified to be Q1.15. Therefore we have a mismatch in
data types. The (:) says, “force w to retain its data type after the
multiply/add over-riding whatever data type the product of w*fifo is.
Simulink Fixed-Point vs MATLAB Fixed-Point
There are some differences between Simulink Fixed-Point and MATALB
Fixed-Point to be aware of when working with EML. In MATLAB all fixed
point behaviors are associated with each variable. Essentially each fixed
point object in MATLAB is a self-contained entity specifying sign, word
length, fraction length, rounding, saturation, addition and multiplication
behaviors, etc. The same is not true in Simulink Fixed-Point. In Simulink the
data (or in Simulink terminology: signal) only contains sign, word length, and
fraction length information. The operator being applied to the signal, let’s
say the addition block, specifies most of the fimath properties. So in
Simulink the data descriptor is separate from the math descriptor. In other
words, “fimath” in Simulink is essentially instance specific depending on the
settings for the particular operator block.
In MATLAB when you multiply two fixed-point numbers a * b, a must have
the same fimath properties as b, else an error will result when you attempt
the multiplication.
>> a*b
??? FIMATH of both operands must be equal.
This gets tricky with EML since you are now mixing Simulink Fixed-Point with
MATLAB Fixed-Point. In Simulink you cannot explicity set all of the fimath
properties for a given variable. Why is that important? Let’s revisit the EML
function definition.
function [Wts, sout] = lms_fixed(rin, sinp)
rin and sinp are Simulink fixed-point signals being passed into a MATLAB
function. At some point in the MATLAB code, Simulink fixed-point meets
MATLAB fixed-point, say line 49.
sout(n) = sinp(n) - y;
At this point unless you set up the EML block very judiciously, you’ll get a
code generation error something like this:
It says the FIMATH of both operands, sinp and y, must be equal. But wait,
how can you set FIMATH in Simulink Fixed-Point? First, in Simulink there is
really no such thing as “fimath” for signals. In Simulink “fimath” is operator
specific, and not associated with the sinp signal itself. It’s a fundamental
difference between MATLAB fixed-point and Simulink fixed-point. MATLAB
fixed-point has fimath associated with each fixed-point object or variable.
Simulink fixed-point has fixed-point math (carefully avoiding the term
fimath) associated with each operator, say an adder or a multiplier block.
You have to get this concept clear before you can make effective progress
mixing MATLAB and Simulink fixed-point.
Dealing with FIMATH Mismatches
There are two approaches to dealing with the fimath mismatch problem.
Approach 1. Force Simulink inputs to have a user-specified MATLAB
fimath. This is the recommended approach.
Approach 2. Force MATLAB to have Simulink “fimath”. We put “fimath” in
quotes for Simulink since it’s not the same fimath as we think of when
using MATLAB fixed-point.
Both approaches involve making the fimath the same. You can bring Simulink
over to MATLAB’s fimath or vice-versa just so they are the same.
Using the Ports and Data Manager
How-to for Approach 1:
Use the EML Ports and Data Manager to force the Simulink input signals to
the EML block to have MATLAB fimath. Unless you really go looking for this
utility there is a good chance you were not even aware this tool existed. To
access the Ports and Data Manager, click on the Edit Data/Ports icon in the
EML edit window next to the binoculars.
Here in the Ports and Data Manager you can set FIMATH for the fixedpoint input signals. You must click in the white space on the left-hand side of
the dialog to see this FIMATH settings on the right-hand side of the dialog.
The solution to this error is to set FIMATH on the inputs to the EML
function to match up with the FIMATH parameters for the MATLAB fixedpoint objects in the M code. That is exactly what we did here to resolve the
FIMATH mismatch error.
If you click on “Wts”, you will get a different context sensitive right-hand
side view.
You can also control these fixed-point parameters from the Model Explorer.
See the help on the Ports and Data Manager for an explanation of when you
might want to use one tool over the other. In general you can use either
approach as the two tools are linked and automatically synchronized.
This is the Model Explorer affecting the same parameters as does the Ports
and Data Manager.
How-to for Approach 2:
2. Another approach to resolving the fimath mismatch problem involves a
modification to the MATLAB code itself. You can inherit the fimath
associated with a Simulink signal and apply that same fimath to your
MATLAB variables. It’s important to recall that fimath is inherently a
MATLAB fixed-point concept, not a Simulink fixed-point one. In Simulink the
fixed-point math is not associated with the signal but with the operator
instead. Once that Simulink signal becomes an input to your EML block
however it takes on a certain default fimath properties because it’s now
entered the MATLAB domain. Confusing, yes, and that’s why we are spending
so much time going over it. Those default fimath properties are:
Default fimath properties for Simulink signals interfaced with MATLAB.
RoundMode: nearest
OverflowMode: saturate
ProductMode: FullPrecision
MaxProductWordLength: 128
SumMode: FullPrecision
MaxSumWordLength: 128
CastBeforeSum: true
The downside to Approach 2 is that you can’t control the fimath of Simulink
signals. You are stuck with the default properties. Therefore the
recommended approach is Approach 1 using the Ports and Data Manager. In
other words modify the fimath associated with Simulink inputs signals to be
whatever you want using the EML Ports and Data Manager.
Getting the fimath associated with one variable and passing it on to another
variable is a useful technique in its own right.
Defining MATLAB fimath in terms of Simulink “fimath”
function [Wts, sout] = lms_fixed(rin, sinp)
% get the fimath associated with the Simulink signal “sinp”
sinp_fimath = fimath(sinp);
% apply that fimath to the MATLAB fixed-point object “y”
y = fi(0,1,16,14,sinp_fimath);
It appears that everytime we call the function “lms_fixed” that “y” gets
unnecessarily re-initialized to 0. Fortunately, that doesn’t happen. It is true
that in the interpreted MATLAB code it executes this y =
fi(0,1,16,14,sinp_fimath) statement every time “lms_fixed” is called.
However, the code generation engine is intelligent enough to see that this
initialization is redundant and omits it.
To find the fimath associated with a Simulink signal you can write the signal
to the MATLAB workspace and inspect it. That’s easy to do with a
ToWorkspace block.
Here we write the “Sin” signal to the MATLAB workspace and inspect it to
find the fimath associated with Simulink signals.
Make sure to check off Log fixed-point data as a fi object or else the data
will be written to the workspace as doubles regardless of the type in the
Simulink model.
What About EMLC as Opposed to EML?
EML stands for Embedded MATLAB and as we said it’s the subset of the
MATLAB language that supports C code generation. Prior to R2007B the only
way to use EML was inside an Embedded MATLAB Function block in Simulink.
That has changed now. In R2007B we introduced a command called EMLC to
generate C code from MATLAB code from the MATLAB command line. In
other words you don’t need to use the EML block in Simulink to get the C
code. To see the complete documentation on EMLC, use the doc EMLC
command. Here is quick example however to get your feet wet.
By Example
Let’s say you wanted to take the MATLAB code we have been using and
generate C from it without using Simulink. Here is what you would do. A few
steps in preparation must be done first. No modifications to the M-code are
required however.
1. Copy the M-code we have been using from the EML block into a separate
M-file. Let’s say we call that file lms_fixed_use_emlc.m.
2. In MATLAB, define the input signals. You must define the input signals
manually now. Previously with the EML block, the inputs inherited their
characteristics from the Simulink signal. Parameters like the input variable’s
size, numeric type, and fimath must be defined. Here is one way to do it.
>> fi_math= fimath('ProductMode','SpecifyPrecision',...
'ProductWordLength',16,...
'ProductFractionLength',14,...
'SumMode','SpecifyPrecision',...
'SumWordLength',16,...
'SumFractionLength',14,...
'RoundMode','nearest',...
'OverflowMode','wrap',...
'CastBeforeSum',true);
% this line sets the size, numeric type, and fimath for “rin”
>> rin = fi(rand(80,1),1,16,14,fi_math);
% setting sinp equal to rin forces sinp to inherit all of rin’s characteristics
>> sinp = rin;
3. Generate C code
>> emlc -T rtw:lib -c -eg {rin, sinp} lms_fixed_use_emlc.m
The generated code is listed in Appendix A.
-T specifies the target. In this case it says generate embeddable C code and
compile it to a library.
-c says generate code, but do not invoke the make command. In other words
we only want the source code, not the object code. The –c here essentially
overrides the compile step in the –T option.
-eg says the function inputs are described “by example”. In this case the
examples variables that describe the inputs are rin and sinp. Don’t use “sin”
as a MATLAB variable since “sin” is a keyword for the trigonometric sine
function. If you ever do over-ride a MATLAB function with a MATLAB
variable by the same name, you can undo the effect by clearing the
offending variable from the workspace.
>> sin = rand(1,5) % bad practice but you can do it
sin =
0.5752
0.0598
0.2348
0.3532
0.8212
>> sin(pi/2) % Oops, won’t work now! Can be nasty to debug.
??? Subscript indices must either be real positive integers or
logicals.
>> clear sin % let’s fix it
>> sin(pi/2) % now we’re good again
ans =
1
General Guidelines on Writing EML Code
We’ve only skimmed across of the surface of EML but enough to get the
general idea of its usage and capabilities. You can do a “doc eml” to learn
even more about EML. However, here are some key features and limitations
associated with EML that you should be aware of.
1. Dynamic memory allocation is not supported. Your M code must be
written such that all arrays are of a fixed and known size at compile
time. Yes, compile time! Your EML code gets compiled to what is
effectively a DLL before it runs. Making their M code use static
memory allocation is probably the biggest and most common challenge
new users to EML face.
2. Structures are supported. Cell arrays are not supported.
3. The majority of the toolbox functions, e.g. image, signal,
communications, are not supported. Keep in mind that the list of
supported EML functions is growing with each release.
4. Fixed-point is supported.
5. Write your MATLAB code to be as elementary as possible, e.g. write
the MATLAB code to look more C code.
6. You can run your EML block in what is effectively debug mode where
you can do things like setting breakpoints and single-stepping. In this
case, the M code is executing through the MATLAB interpreter and
as such the simulation speed is slower. See Debug/Enable Debugging.
Unselect it for maximum simulation speed.
7. The fimath must agree or your code will error out at compilation time.
The one key exception is the use of (:) notation discussed previously.
Appendix A: Generated C Code
This table shows the ec_eml.c file generated for the Embedded MATLAB
function block.
/*
* File: ec_eml.c
*
* Real-Time Workshop code
*
* Model version
* Real-Time Workshop file
* Real-Time Workshop file
* TLC version
* C source code generated
*/
generated for Simulink model ec_eml.
: 1.507
version
: 7.0 (R2007b) 02-Aug-2007
generated on : Fri Dec 21 00:54:41 2007
: 7.0 (Jul 26 2007)
on
: Fri Dec 21 00:54:41 2007
#include "ec_eml.h"
#include "ec_eml_private.h"
/* Block states (auto storage) */
D_Work_ec_eml ec_eml_DWork;
/* External outputs (root outports fed by signals with auto storage) */
ExternalOutputs_ec_eml ec_eml_Y;
/* Real-time model */
RT_MODEL_ec_eml ec_eml_M_;
RT_MODEL_ec_eml *ec_eml_M = &ec_eml_M_;
/* Model step function */
void ec_eml_step(void)
{
/* local block i/o variables */
int16_T rtb_DelayEqualizer[80];
int16_T rtb_Wts[32];
{
int16_T i;
/* Output: Signal Processing Blockset Delay (sdspdelay) '<S1>/Delay Equalizer' */
{
/* Single channel input (Delay = 2, Samples per channel = 80) */
const int_T bytesInBuffer = 2 * sizeof(int16_T);
const int_T bytesNotInBuffer = 80 * sizeof(int16_T) bytesInBuffer;
memcpy((byte_T *)rtb_DelayEqualizer, (byte_T *)
&ec_eml_DWork.DelayEqualizer_IC_BUFF[0], bytesInBuffer);
memcpy((byte_T *)rtb_DelayEqualizer + bytesInBuffer, (const
byte_T *)
&rin_linear[0], bytesNotInBuffer);
}
/* Embedded MATLAB: '<S1>/ec' incorporates:
*
Inport: '<Root>/Sin'
*/
{
int16_T eml_k;
int16_T eml_n;
int16_T eml_iv0[31];
int16_T eml_c;
int32_T eml_i1;
int32_T eml_i2;
int16_T eml_iv1[32];
int16_T eml_i3;
int32_T eml_i4;
int16_T eml_iv2[32];
/* Paramter initialization and memory allocation */
/* Using Fixed Point arithmetics */
/* word length */
/* fractional size */
/* signed */
/* create a numeric TYPE for the processor data */
/* Define how math will be performed */
/* 32 bit multiply output */
/* 32 bit accumulator, so we can generate C code */
if (!ec_eml_DWork.w_not_empty) {
ec_eml_DWork.w_not_empty = true;
}
/* initializing the array sout also sets its data type */
for (eml_k = 0; eml_k < 80; eml_k++) {
sout_linear[eml_k] = 0;
}
/* Loop over input vector */
for (eml_n = 0; eml_n < 80; eml_n++) {
/* Update fifo */
for (eml_k = 0; eml_k < 31; eml_k++) {
eml_iv0[eml_k] = ec_eml_DWork.fifo[1 + eml_k];
}
for (eml_k = 0; eml_k < 31; eml_k++) {
ec_eml_DWork.fifo[eml_k] = eml_iv0[eml_k];
}
ec_eml_DWork.fifo[31] = rtb_DelayEqualizer[eml_n];
/* Update filter */
eml_c = 0;
for (eml_k = 0; eml_k < 32; eml_k++) {
eml_i1 = (int32_T)ec_eml_DWork.w[eml_k] * (int32_T)
ec_eml_DWork.fifo[eml_k];
eml_c += (int16_T)((eml_i1 >> 15) + (int32_T)((eml_i1 &
16384L) !=
(int32_T)0));
}
sout_linear[eml_n] = sin_linear[eml_n] - eml_c;
eml_i2 = (int32_T)ec_eml_DWork.mu *
(int32_T)sout_linear[eml_n];
eml_c = (int16_T)((eml_i2 >> 15) + (int32_T)((eml_i2 & 16384L)
!=
(int32_T)0));
for (eml_k = 0; eml_k < 32; eml_k++) {
eml_iv1[eml_k] = eml_k;
}
for (eml_k = 0; eml_k < 32; eml_k++) {
eml_i3 = ec_eml_DWork.w[eml_k];
eml_i4 = (int32_T)eml_c * (int32_T)ec_eml_DWork.fifo[eml_k];
eml_iv2[eml_k] = (((eml_i3 >> 1) + ((eml_i3 & 1) != 0)) +
(int16_T)
((eml_i4 >> 14) + (int32_T)((eml_i4 &
8192L) !=
(int32_T)0))) << 1;
}
for (eml_k = 0; eml_k < 32; eml_k++) {
ec_eml_DWork.w[eml_iv1[eml_k]] = eml_iv2[eml_k];
}
}
for (eml_k = 0; eml_k < 32; eml_k++) {
rtb_Wts[eml_k] = ec_eml_DWork.w[eml_k];
}
/*
}
output a column vector, not a row */
for (i = 0; i < 32; i++) {
/* Outport: '<Root>/Wts' */
ec_eml_Y.Wts[i] = rtb_Wts[i];
}
/* Update: Signal Processing Blockset Delay (sdspdelay) '<S1>/Delay Equalizer' */
{
/* Single channel input (Delay = 2, Samples per channel = 80) */
const int_T bytesInBuffer = 2 * sizeof(int16_T);
const int_T bytesNotInBuffer = 80 * sizeof(int16_T) bytesInBuffer;
memcpy((byte_T *)&ec_eml_DWork.DelayEqualizer_IC_BUFF[0], (const
byte_T *)
&rin_linear[0] + bytesNotInBuffer, bytesInBuffer);
}
}
}
/* Model initialize function */
void ec_eml_initialize(void)
{
/* Registration code */
/* initialize error status */
rtmSetErrorStatus(ec_eml_M, (const char_T *)0);
/* Initialization: Signal Processing Blockset Delay (sdspdelay) '<S1>/Delay Equalizer' */
{
/* copy ICs from edit box to IC buffer */
{
int_T i = 0;
for (i=0; i<2; i++) {
ec_eml_DWork.DelayEqualizer_IC_BUFF[i] =
rtcP_DelayEqualizer_IC;
}
}
}
/* Initialize code for chart: '<S1>/ec' */
{
int16_T eml_i0;
ec_eml_DWork.w_not_empty = false;
ec_eml_DWork.mu = 300;
for (eml_i0 = 0; eml_i0 < 32; eml_i0++) {
ec_eml_DWork.fifo[eml_i0] = 0;
ec_eml_DWork.w[eml_i0] = 0;
}
}
}
Generated C Code using EMLC
/*
* lms_fixed.c
*
* Embedded MATLAB Coder code generation for M-function
'lms_fixed_use_emlc'
*
* C source code generated on: Sat Jan 05 15:15:01 2008
*
*/
/* Include files */
#include "lms_fixed.h"
/* Type Definitions */
/* Variable Declarations */
/* Variable Definitions */
static int16_T w[32];
static boolean_T w_not_empty;
static int16_T fifo[32];
static boolean_T fifo_not_empty;
static int16_T mu;
static boolean_T mu_not_empty;
/* Function Declarations */
/* Function Definitions */
void lms_fixed(int16_T *eml_rin, int16_T *eml_sinp,
int16_T
*eml_sout)
{
int32_T eml_k;
int16_T eml_n;
int16_T eml_iv0[31];
int16_T eml_c;
int32_T eml_i0;
int32_T eml_i1;
int32_T eml_iv1[32];
int32_T eml_i2;
int16_T eml_i3;
int16_T eml_iv2[32];
/* Paramter initialization and memory allocation
/* Using Fixed Point arithmetics */
/* word length */
/* fractional size */
/* signed */
/* create a numeric TYPE for the processor data
/* Define how math will be performed */
/* 32 bit multiply output */
/* 32 bit accumulator, so we can generate C code
if(!w_not_empty) {
fifo_not_empty = true;
mu = 300;
mu_not_empty = true;
int16_T *eml_Wts,
*/
*/
*/
for(eml_k = 0; eml_k < 32; eml_k++) {
fifo[eml_k] = 0;
w[eml_k] = 0;
}
w_not_empty = true;
}
/* must have this re-initialization of sout */
for(eml_k = 0; eml_k < 80; eml_k++) {
eml_sout[eml_k] = 0;
}
/* end sout init */
/* Loop over input vector */
for(eml_n = 1; eml_n < 81; eml_n++) {
/* Update fifo */
for(eml_k = 0; eml_k < 31; eml_k++) {
eml_iv0[eml_k] = fifo[1 + eml_k];
}
for(eml_k = 0; eml_k < 31; eml_k++) {
fifo[eml_k] = eml_iv0[eml_k];
}
fifo[31] = eml_rin[eml_n - 1];
/* Update filter */
eml_c = 0;
for(eml_k = 0; eml_k < 32; eml_k++) {
eml_i0 = w[eml_k] * fifo[eml_k];
eml_c += (int16_T)((eml_i0 >> 15) + ((eml_i0 & 16384) != 0));
}
eml_sout[eml_n - 1] = (int16_T)(eml_sinp[eml_n - 1] - eml_c);
eml_i1 = mu * eml_sout[eml_n - 1];
eml_c = (int16_T)((eml_i1 >> 15) + ((eml_i1 & 16384) != 0));
for(eml_k = 0; eml_k < 32; eml_k++) {
eml_iv1[eml_k] = eml_k;
eml_i2 = eml_c * fifo[eml_k];
eml_i3 = w[eml_k];
eml_iv2[eml_k] = (int16_T)((int16_T)((int16_T)((eml_i3 + 1) >> 1)
+
(int16_T)((eml_i2 >> 14) + ((eml_i2 & 8192) != 0)))
<< 1);
}
for(eml_k = 0; eml_k < 32; eml_k++) {
w[eml_iv1[eml_k]] = eml_iv2[eml_k];
}
}
for(eml_k = 0; eml_k < 32; eml_k++) {
eml_Wts[eml_k] = w[eml_k];
}
/* output a column vector, not a row */
}
void lms_fixed_initialize(void)
{
rt_InitInfAndNaN(8U);
mu_not_empty = false;
fifo_not_empty = false;
w_not_empty = false;
}
void lms_fixed_terminate(void)
{
}
/* End of Embedded MATLAB Coder code generation (lms_fixed.c) */
Download