I am attempting to implement a Fast Fourier Transform with associated complex magnitude function on the STM32F411RE Nucleo developer board. My goal is to separate a combined signal with multiple sinusoidal elements into their separate frequency components, with correct amplitude.
My issues is that I cannot correctly line up the frequency bins outcomes from the Complex magnitude function with the frequencies. I am also starting to question the validity of these outcomes as such.
I have tried to use a number of different implementations posted by people for the FFT algorithm with the magnitude fix, most notably the examples listed on StackoverFlow by SleuthEye and Blog by LB9MG.
AFAIK I have a similar approach, but somehow their approaches yield the desired results and mine do not. Below is my code that I have altered to work via the implementation that SleuthEye has created.
int main(void)
{
fftLen = 32; // can be 32, 64, 128, 256, 512, 1024, 2048, 4096
half_fftLen = fftLen/2;
volatile float32_t sampleFreq = 50 * fftLen; // Fs = binsize * fft length, desired binsize = 50 hz
arm_rfft_fast_instance_f32 inst;
arm_status status;
status = arm_rfft_fast_init_f32(&inst, fftLen);
float32_t signalCombined[fftLen] = {0};
float32_t fftCombined[fftLen] = {0};
float32_t fftMagnitude[fftLen] = {0};
volatile float32_t fftFreq[fftLen] = {0};
float32_t maxAmp;
uint32_t maxAmpInd;
while (1)
{
for (int i = 0; i< fftLen; i++)
{
signalCombined[i] = 40 * arm_sin_f32(450 * i); // 450 frequency at 40 amplitude
}
arm_rfft_fast_f32(&inst, signalCombined, fftCombined, 0); // perhaps switch to complex transform to allow for negative frequencies?
arm_cmplx_mag_f32(fftCombined, fftMagnitude, half_fftLen);
fftMagnitude[0] = fftCombined[0];
fftMagnitude[half_fftLen] = fftCombined[1];
arm_max_f32(fftMagnitude, half_fftLen, &maxAmp, &maxAmpInd); // We need the 3 max values
for (int k = 0; k < fftLen ; k++)
{
fftFreq[k] = ((k*sampleFreq)/fftLen);
}
}
Shown below are the results that I get out of the code listed above: whilst I do get a magnitude out of the algorithms (at the correct index 12), it does not correspond to the frequency or the amplitude of the input array signalCombined[]
.
Does anyone have an idea of why this is happening? Like so many of my errors it is probably a really trivial and stupid thing, but I cannot figure out for the life of me why this is happening.
EDIT: thanks to SleuthEye's help finding the frequencies is now possible, as the initial approach for generating the sin() signal was done incorrectly.
Some new issues popped up as the FFT only appears to yield the correct frequencies for the 32 samples, despite the bin size scaling accordingly to accommodate the adjusted sample size.
I am also unable to implement the amplitude fixing algorith: as per SleuthEye's Link with the example code 2*(1/N)*abs(X(k))^2
I have made my own implementation 2 * powf(fabs(fftMagnitude[j]), 2) / fftLen
as shown in the code below, but this does not yield results that are even close to correct.
while (1)
{
for (int i = 0; i < fftLen; i++)
{
signalCombined[i] = 400 * arm_sin_f32(2 * PI * 450 * i / sampleFreq); // Sin Alpha, 400 amp at 10 kHz
// 700 * arm_sin_f32(2 * PI * 33000 * i / sampleFreq) + // Sin Bravo, 700 amp at 33 kHz
// 300 * arm_sin_f32(2 * PI * 50000 * i / sampleFreq); // Sin Charlie, 300 amp at 50 kHz
}
arm_rfft_fast_f32(&inst, signalCombined, fftCombined, 0); // calculate the fourier transform of the time domain signal
arm_cmplx_mag_f32(fftCombined, fftMagnitude, half_fftLen); // calculate the magnitude of the fourier transform
fftMagnitude[0] = fftCombined[0];
fftMagnitude[half_fftLen] = fftCombined[1];
for (int j = 0; j < sizeof(fftMagnitude); j++)
{
fftMagnitude[j] = 2 * powf(fabs(fftMagnitude[j]), 2) / fftLen; // Algorithm to fix the amplitude of each unique frequency
}
arm_max_f32(fftMagnitude, half_fftLen, &maxAmp, &maxAmpInd); // We need the 3 max values
for (int k = 0; k < fftLen ; k++)
{
fftFreq[k] = ((k*sampleFreq)/fftLen);
}
}