Modeling an Echo Canceller using Simulink Primitive Blocks

advertisement
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.
Download