You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CMSIS-DSP/ComputeGraph/examples/example2
Christophe Favergeon dfb67ee993 Started to rework the documentation for the ComputeGraph examples. 3 years ago
..
docassets Added a new simpler example for the compute graph. 3 years ago
generated Added a dynamic mode to the compute graph. 3 years ago
AppNodes.h Added a dynamic mode to the compute graph. 3 years ago
CMakeLists.txt Added a new simpler example for the compute graph. 3 years ago
README.md Started to rework the documentation for the ComputeGraph examples. 3 years ago
custom.h Renamed SDF to Compute Graph - Static Flow 3 years ago
graph.py Added a dynamic mode to the compute graph. 3 years ago
main.cpp Renamed SDF to Compute Graph - Static Flow 3 years ago
test.dot Improvement to the Python wrapper 3 years ago
test.pdf Renamed SDF to Compute Graph - Static Flow 3 years ago

README.md

Example 2

Please refer to the simple example to have an overview of how to define a graph and it nodes and how to generate the C++ code for the static scheduler.

In this example. we are just analyzing a much more complex example to see some new features:

  • Delay
  • CMSIS-DSP function
  • Constant node
  • SlidingBuffer

This example is not really using a MFCC or a TensorFlow Lite node. It is just providing some wrappers to show how such a nodes could be included in a graph:

The graph is:

graph2

It is much more complex:

  • First we have a stereo source delayed by 10 samples ;
  • Then this stereo source is split into left/right samples using the default block Unzip
  • The samples are divided by 2 using a CMSIS-DSP function
  • The node HALF representing a constant is introduced (constant arrays are also supported)
  • The two streams are added using a CMSIS-DSP function
  • Then we have a sliding buffer
  • A block representing a MFCC (a fake MFCC)
  • Another sliding buffer
  • An a block representing TensorFlow Lite for Micro (a fake TFLite node)

Note that those blocks (MFCC, TFLite) are doing nothing in this example. It is just to illustrate a more complex example typical of keyword spotting applications.

Examples 5 and 6 are showing how to use the CMSIS-DSP MFCC.

Let's look at the new features compared to example 1:

Delay

g.connectWithDelay(src.o, toMono.i,10)

To add a delay on a link between 2 nodes, you just use the connectWithDelay function. Delays can be useful for some graphs which are not schedulable. They are implemented by starting the schedule with a FIFO which is not empty but contain some 0 samples.

CMSIS-DSP function

Some CMSIS-DSP functions are automatically made available to the framework : mainly the functions with no state and which are pure stream based computation : Basic math functions etc ...

To create a CMSIS-DSP node, just use:

sa=Dsp("scale",floatType,blockSize)

The corresponding CMSIS-DSP function will be named: arm_scale_f32

The code generated in scheduler.cpp will not require any C++ class, It will look like:

{
    float32_t* i0;
    float32_t* i1;
    float32_t* o2;
    i0=fifo3.getReadBuffer(160);
    i1=fifo4.getReadBuffer(160);
    o2=fifo5.getWriteBuffer(160);
    arm_add_f32(i0,i1,o2,160);
    cgStaticError = 0;
}

Constant node

In the case of scaling, we need to connect the scaling factor to the node. So we need a constant node.

A constant node is defined as:

half=Constant("HALF")

In the C++ code, HALF is expected to be a value defined in custom.h

Constant values are not involved in the scheduling (they are ignored) and they have no IO. So, to connect to a constant node we do:

g.connect(half,sa.ib)

There is no "o", "oa" suffixes for the constant node half.

Constant nodes are just here to make it easier to use CMSIS-DSP functions.

SlidingBuffer

Sliding buffers and OverlapAndAdd are used a lot so they are provided in the cg/nodes/cppfolder of the ComputeGraph folder.

In Python, it can be used with:

audioWindow=SlidingBuffer("audioWin",floatType,640,320)

The first length (640) is the window size and the second length (320) is the overlap. So, in this case we have an overlap of 50%

There is no C++ class to write for this since it is provided by default by the framework.

It is named SlidingBuffer but not SlidingWindow because no multiplication with a window is done. It must be implemented with another block as will be demonstrated in the example 3

Expected outputs

Schedule length = 302
Memory usage 10720 bytes

And when executed:

Start
Nb = 40

Execution is running for 40 iterations without errors.