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.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *