Incorrect FFT Outputs with CMSIS DSP Library on STM32F4
The issue at hand involves incorrect Fast Fourier Transform (FFT) results when using the ARM CMSIS DSP library on an STM32F4 Discovery board. The user is attempting to compute the FFT of a sinusoidal signal using both the Complex FFT (CFFT) and Real FFT (RFFT) functions provided by the CMSIS DSP library. Despite following the library’s API and setting up the FFT parameters correctly, the computed FFT outputs do not match the expected results. This discrepancy suggests potential issues in the configuration, signal generation, or FFT processing pipeline.
The user’s code includes the generation of a 120 Hz sinusoidal signal sampled at 5 kHz, with 128 samples being processed through the FFT. The expected output should show a peak at the 120 Hz frequency bin, but the observed results are incorrect. Additionally, there is confusion regarding how the sampling frequency is handled within the CMSIS DSP library, as it is not explicitly specified in the library’s API.
Misconfigured FFT Parameters and Signal Generation Issues
The incorrect FFT results can be attributed to several potential causes, primarily revolving around misconfigured FFT parameters, improper signal generation, and misunderstandings of the CMSIS DSP library’s requirements.
Misconfigured FFT Parameters
The user has defined the FFT size as half the number of samples (FFT_SIZE = SAMPLES / 2
), which is incorrect for real FFT computations. The FFT size should match the number of samples for real FFTs, as the library internally handles the conversion from real to complex data. For complex FFTs, the size should also match the number of complex samples, which is typically the same as the number of real samples divided by two. This misconfiguration can lead to incorrect FFT outputs.
Improper Signal Generation
The sinusoidal signal generation in the code uses a fixed time step (t = k * 0.0002
) for each sample, which corresponds to a sampling interval of 0.2 ms (5 kHz sampling rate). However, the signal generation loop does not account for the correct phase continuity or the exact time steps required for accurate FFT computation. Additionally, the imaginary part of the input signal is set to zero, which is correct for real FFTs but may not be handled properly in the complex FFT implementation.
Misunderstanding of CMSIS DSP Library Requirements
The CMSIS DSP library does not explicitly require the user to specify the sampling frequency. Instead, the sampling frequency is implicitly defined by the time interval between samples and the total number of samples. The user’s confusion arises from the need to manually calculate the frequency bins based on the sampling rate and FFT size. This calculation is critical for interpreting the FFT results correctly but is not directly handled by the library.
Correcting FFT Configuration and Signal Generation
To resolve the issues and obtain correct FFT results, the following steps should be taken:
Correct FFT Size Configuration
For real FFTs, the FFT size should match the number of samples. Update the FFT_SIZE
definition to:
#define FFT_SIZE SAMPLES
For complex FFTs, ensure that the input array contains both real and imaginary parts, and the FFT size should match the number of complex samples:
#define FFT_SIZE SAMPLES / 2
Accurate Signal Generation
Ensure that the sinusoidal signal is generated with the correct time steps and phase continuity. Use a loop to generate the signal with the exact sampling interval:
for (int k = 0; k < SAMPLES; k++) {
t = k * (1.0 / SAMPLING_RATE);
Input[k] = 0.7 * sin(2 * 3.14159 * 120 * t);
}
For complex FFTs, populate both the real and imaginary parts of the input array:
for (int k = 0; k < SAMPLES; k += 2) {
t = k * (1.0 / SAMPLING_RATE);
Input[k] = 0.7 * sin(2 * 3.14159 * 120 * t); // Real part
Input[k + 1] = 0.0; // Imaginary part
}
Proper FFT Initialization and Execution
Ensure that the FFT instance is correctly initialized and executed. For real FFTs:
arm_rfft_fast_instance_f32 fft_handler;
arm_rfft_fast_init_f32(&fft_handler, SAMPLES);
arm_rfft_fast_f32(&fft_handler, Input, Output, 0);
For complex FFTs:
arm_cfft_radix4_instance_f32 S;
arm_cfft_radix4_init_f32(&S, FFT_SIZE, 0, 1);
arm_cfft_radix4_f32(&S, Input);
Frequency Bin Calculation
Calculate the frequency bins correctly based on the sampling rate and FFT size:
float ratio = (float)SAMPLING_RATE / SAMPLES;
for (int i = 0; i < FFT_SIZE; i++) {
frequencybin[i] = ratio * i;
}
Debugging and Validation
To validate the FFT results, compare the computed frequency bins with the expected frequency of the input signal. Use debugging tools such as breakpoints, watchpoints, and serial output to inspect intermediate values and ensure that the FFT computation is correct.
Example Code for Real FFT
Here is the corrected and complete example code for real FFT computation:
#include "arm_math.h"
#include "arm_const_structs.h"
#define SAMPLES 128
#define FFT_SIZE SAMPLES
#define SAMPLING_RATE 5000
float32_t Input[SAMPLES];
float32_t Output[FFT_SIZE];
float32_t frequencybin[FFT_SIZE];
float32_t maxValue, peakfrequency, ratio;
uint32_t maxIndex;
int main(void) {
arm_rfft_fast_instance_f32 fft_handler;
arm_rfft_fast_init_f32(&fft_handler, SAMPLES);
for (int k = 0; k < SAMPLES; k++) {
float t = k * (1.0 / SAMPLING_RATE);
Input[k] = 0.7 * sin(2 * 3.14159 * 120 * t);
}
arm_rfft_fast_f32(&fft_handler, Input, Output, 0);
arm_cmplx_mag_f32(Output, frequencybin, FFT_SIZE / 2);
arm_max_f32(frequencybin, FFT_SIZE / 2, &maxValue, &maxIndex);
ratio = (float)SAMPLING_RATE / SAMPLES;
peakfrequency = ratio * maxIndex;
while (1) {
// Main loop
}
}
Example Code for Complex FFT
Here is the corrected and complete example code for complex FFT computation:
#include "arm_math.h"
#include "arm_const_structs.h"
#define SAMPLES 128
#define FFT_SIZE SAMPLES / 2
#define SAMPLING_RATE 5000
float32_t Input[SAMPLES];
float32_t Output[FFT_SIZE];
float32_t frequencybin[FFT_SIZE];
float32_t maxValue, peakfrequency, ratio;
uint32_t maxIndex;
int main(void) {
arm_cfft_radix4_instance_f32 S;
arm_cfft_radix4_init_f32(&S, FFT_SIZE, 0, 1);
for (int k = 0; k < SAMPLES; k += 2) {
float t = k * (1.0 / SAMPLING_RATE);
Input[k] = 0.7 * sin(2 * 3.14159 * 120 * t); // Real part
Input[k + 1] = 0.0; // Imaginary part
}
arm_cfft_radix4_f32(&S, Input);
arm_cmplx_mag_f32(Input, Output, FFT_SIZE);
arm_max_f32(Output, FFT_SIZE, &maxValue, &maxIndex);
ratio = (float)SAMPLING_RATE / SAMPLES;
peakfrequency = ratio * maxIndex;
while (1) {
// Main loop
}
}
By following these steps and correcting the FFT configuration, signal generation, and frequency bin calculation, the user should be able to obtain accurate FFT results using the CMSIS DSP library on the STM32F4 Discovery board.