This example is implementing a working example with FFT. The graph is:
The example is:
The new feature s compared to previous examples are:
It is like in example 2 where the constant was a float.
Now, the constant is an array:
hann=Constant("HANN")
In custom.h, this array is defined as:
extern const float32_t HANN[256];
The FFT node cannot be created using a Dsp node in Python because FFT is requiring specific initializations. So, a Python class and C++ class must be created :
class CFFT(GenericNode):
def __init__(self,name,inLength):
GenericNode.__init__(self,name)
self.addInput("i",floatType,2*inLength)
self.addOutput("o",floatType,2*inLength)
@property
def typeName(self):
return "CFFT"
Look at the definition of the inputs and outputs : The FFT is using complex number so the ports have twice the number of float samples. The argument of the constructor is the FFT length in complex sample.
We suggest to use as arguments of the blocks a number of samples which is meaningful for the blocks and use the lengths in standard data type (f32, q31 ...) when defining the IO.
So here, the number of complex samples is used as arguments. But the IO are using the number of floats required to encode those complex numbers.
The corresponding C++ class is:
template<typename IN, int inputSize,typename OUT,int outputSize>
class CFFT: public GenericNode<IN,inputSize,OUT,outputSize>
{
public:
CFFT(FIFOBase<IN> &src,FIFOBase<OUT> &dst):
GenericNode<IN,inputSize,OUT,outputSize>(src,dst){
arm_status status;
status=arm_cfft_init_f32(&sfft,inputSize>>1);
};
int run(){
IN *a=this->getReadBuffer();
OUT *b=this->getWriteBuffer();
memcpy((void*)b,(void*)a,outputSize*sizeof(IN));
arm_cfft_f32(&sfft,b,0,1);
return(0);
};
arm_cfft_instance_f32 sfft;
};
It is verbose but not difficult. The constructor is initializing the CMSIS-DSP FFT instance and connecting to the FIFO (through GenericNode).
The run function is applying the arm_cfft_f32. Since this function is modifying the input buffer, there is a memcpy. It is not really needed here. The read buffer can be modified by the CFFT. It will just make it more difficult to debug if you'd like to inspect the content of the FIFOs.
This node is provided in sdf/nodes/cpp so no need to define it. You can just use it by including the right headers.
It can be used by just doing in your AppNodes.h file :
#include "CFFT_F32.h"
From Python side it would be:
from sdf.nodes.py.CFFTF32 import *