Chapter 7: Creating Custom Blocks Part 1 Chapter 7: Creating Custom Blocks Part 1 ......................................................................... 1 Modeling an Echo Canceller using Simulink Primitive Blocks ......................................... 1 What is a Simulink Primitive? ............................................................................................ 1 Primitives in Action ............................................................................................................ 2 When to Use What? ............................................................................................................ 6 When to Use a Macro-based Approach? ........................................................................ 6 When to Use a Primitives-based Approach? .................................................................. 7 What About Other Approaches? ..................................................................................... 7 The S-Function Option ....................................................................................................... 8 Masking a Block ................................................................................................................. 9 Frame-Based Implementation using Simulink Primitives ................................................ 13 A More Efficient Frame-Based Approach ........................................................................ 18 Modeling an Echo Canceller using Simulink Primitive Blocks What is a Simulink Primitive? This chapter shows an alternative method to modeling an echo canceller using Simulink primitives. By Simulink primitives we mean building a subsystem out of basic building blocks like adders, multipliers, and delays instead of using for example a single FFT block. This model we refer to in this section is accessed via the “Simulink Primitives-Sample-based” link in the example selector. Primitives in Action This is the top-level view of our echo canceller model that uses Simulink primitive blocks. The top level model looks the same as we’ve seen in other chapters except the signal lines are single-wide. It’s a sample-based implementation of the echo canceller. This is a block diagram for the classic LMS algorithm. It’s fixed-point and it’s very easy to see what is happening. To contrast this primitive-based modeling approach with the Simulink macro approach, let’s take a brief look back at the macro approach. This is the LMS block that ships with the Signal Processing Blockset. We are using the term macro block to describe this type of block since its underlying functionality cannot be modified and cannot be directly viewed in Simulink. The user interacts with a macro block through its I/O ports and its user dialog. Macro blocks are called S-function blocks in Simulink terminology. S-functions are custom Simulink blocks implemented using compiled C or C++. You can think of these macro S-function blocks as canned solutions. They can be parameterized but you can’t change the internal wiring or add new components. Both the LMS algorithmic parameters and fixed point data parameters are setup via this user dialog. When to Use What? Both the macro (S-functions) and primitive (basic blocks) approaches come with their own set of advantages. The trick is know when to choose one over the other. When to Use a Macro-based Approach? 1. You must have the macro block at your disposal. Either it’s a shipping block from The Mathworks or you were able to get or create a custom S-function block that performs just the function you need. 2. You aren’t particularly picky about how the function is implemented. You are more interested in its performance from a black-box point of view and not for example how many multipliers it used. 3. Third, you don’t see the need to customize functionality any time soon because S-functions are not customizable unless you have the C/C++ source code and the patience to understand the block’s inner workings. When to Use a Primitives-based Approach? 1. You don’t have a macro block that does what you need. This is the most important reason. As we’ll see in other chapters, there are other techniques besides the primitives-based approach to creating your own custom blocks including using MATLAB and C code. 2. You are particular about the implementation of the function as you are thinking about the eventual hardware or firmware implementation. 3. You plan on changing the block frequently as you are still in experimentation mode. 4. You like the graphical convenience of being able to probe any node in the diagram with a scope, display, or logging indicator. 5. You like the debugging capability of viewing fixed point data types and frame sizes as they propagate through the system. 6. You want to maintain a scalable graphical hierarchy to your design. You can’t scale the details of a macro/S-function block. 7. You can continue to take advantage of the fixed-point auto-scaling tools. You can’t apply auto-scaling to an S-function block unless the author of that block allowed it and even then it will be in the limited way the author provided hooks into the individual signals. What About Other Approaches? It’s not just a two horse race between Simulink macros and Simulink primitive implementation of subsystems. In addition you can also create your subsystems from MATLAB code or from C code. The MATLAB approach using Embedded MATLAB and will be discussed in its own chapter. The C code approach we’ll illustrate involves using the Legacy Code Tool and it will have its own chapter as well. Both approaches have merit especially when you have proven legacy code in one of the two languages and simply want to use it. The catch is usually that the legacy code will have to undergo some kind of a rewrite anyway. How much of a rewrite is code dependent. There is no one answer to that question. The main point for this chapter is that if you want to work graphically and maintain a clear hierarchy to your design then the Simulink primitive approach to building subsystems should be your preferred method. The S-Function Option You can create your own Macro/S-function blocks out of your primitivebased implementation if you have the Real-Time Workshop. Right-click on the subsystem of interest and select Real-Time Workshop/Generate SFunction. This will create a new S-function block with the equivalent I/O behavior as the block from which it was based. However you won’t be able to see the implementation when you click into it now. S-function blocks are a handy feature if: 1. You want to share a certain capability with someone without necessarily showing them the implementation details. 2. You want to share a certain capability with someone without providing them the capability to alter the implementation. This would be very relevant in a hand-off situation from the development department to a testing station. The testers should not in general modify the developer’s implementation. 3. You need more simulation speed. The amount of speed up after going to an S-function will vary greatly but expect impressive speed-ups if the subsystem has a significant fixed-point component. Finally, you can also hand-craft your own S-function in C/C++ even without the Real-Time Workshop. This is an advanced technique not covered in this document but we will cover an alternate C-based approach using the Legacy Code Tool. Masking a Block Optionally you can create a masked dialog for your primitive-based echo canceller implementation. To do this, right-click on the subsystem and select “Mask Subsystem”. The finished result of masking the Echo Canceller subsystem is found in model ec_fixed_slp_sb_with_mask.mdl. The link is called “with masked dialogs” in the example selector. The Echo_Canceller subsystem is masked. . Right-click on the Echo Canceller subsystem and select “Edit Mask”. Enter the parameters you would like the user to be able to control under the dialog parameter tab. Also make sure to provide some documentation about what your block does under the documentation tab. Now when you left double-click on the Echo_Canceller block you see this dialog instead of the implementation. If you want to try creating a masked dialog from scratch, you can start with the ec_fixed_slm_16bit_tb1.mdl file accessible from the example selector. The motivation behind masked dialogs is convenience. It’s often more convenient to set parameters via a dialog than it is to search for them individually under separate dialogs possibly under a deep graphical hierarchy. Whenever you want to see the detailed block level implementation, right click on the block and select “Look Under Mask”. Frame-Based Implementation using Simulink Primitives The previous model used Simulink primitives but it was a sample-based model. The particular problem you are working on may require a frame-based implementation. As an example, the hands-free kit’s code base that shipped from Microchip for their dsPIC based evaluation board used 80 sample frames in their echo canceller. The sample rate was 8000 Hz so the frame rate was 8000/80 or 100 Hz. There are times where a frame-based simulation is preferred even when the eventual implementation is samplebased. This is true when simulation speed is an issue. Frame-based simulations generally provide a significant simulation speed-up over samplebased ones since proportionally more time gets spent on computations as compared to the simulation overhead. You can think of the simulation overhead as being a fixed quantity per simulation time step. If many samples are processed per time step, then you have effectively amortized or distributed the simulation overhead out over many samples rather than just one. In some cases however it may not be possible to re-cast the problem in terms of frames due to your algorithm requirements. This is particularly true in feedback control systems which many times must be sample-based in both simulation and implementation. The finished model for this section is accessed via the “Simulink PrimitivesFrame-based brute force” link. The echo canceller looks the same from the top level view with the exception that double-wide lines are feeding the echo canceller. Double-wide lines indicate frame-based signals, in this case, 80 sample frames. But one level down in the Echo_Canceller subsystem we see the primitivebased implementation. The implementation of the LMS algorithm is identical to before except that there are three red buffer/unbuffer blocks surrounding the algorithm. We un-buffer the input signals from frames to samples. We buffer the output signal from samples to frames. From an I/O perspective it’s frame-based but the internal processing is sample-based. This is the most brute-force method of making a frame-based implementation out of a sample-based one. Although it’s very simple to do in practice, there is a significant simulation speed penalty. This model still simulates sample-based at its computational core and therefore there is no frame-based speed advantage. In practice such a “pseudo frame-based” model will simulate a little slower than the previous “pure sample-based” model due to the overhead of buffering and unbuffering. Hint: If you ever get a frame-based model that appears to be simulating extremely slowly, poke down into the subsystems to see if the underlying computations are frame-based or not. A More Efficient Frame-Based Approach There is a more efficient way to simulate a frame-based echo canceller over the brute-force approach using buffer and unbuffer blocks. There is where for-iterator subsystems come to the rescue. Let’s take a closer look. The finished model for this section is accessed via the “Simulink PrimitivesFrame-based improved” link. The top level of the model is still frame-based as previously. But now we’ve encapsulated the echo canceller functionality inside a for { } iterator subsystem. Let’s go one more level down into the hierarchy. The blue blocks show the same implementation as in the previous two renditions of the LMS algorithm. The new part is colored in cyan/aqua. Whatever is inside a for-iterator subsystem is computed for N iterations before the output is updated. One could argue that the LMS algorithm is still sample-based but the for-iterator is a more efficient simulation methodology. The good news is that you don’t have to modify the original sample-based implementation. You merely add on four extra blocks to the inputs and outpus: two selectors, an assignment block, and a for-iterator block.