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) */