跳转至

测试

tinyffttest.h

/**
 * @file tiny_fft_test.h
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief tiny_fft | test | header
 * @version 1.0
 * @date 2025-11-16
 * @copyright Copyright (c) 2025
 *
 */

#pragma once

/* DEPENDENCIES */
#include "tiny_fft.h"

#ifdef __cplusplus
extern "C"
{
#endif

void tiny_fft_test(void);

#ifdef __cplusplus
}
#endif

tinyffttest.c

/**
 * @file tiny_fft_test.c
 * @author SHUAIWEN CUI (SHUAIWEN001@e.ntu.edu.sg)
 * @brief tiny_fft | test | source
 * @version 1.0
 * @date 2025-11-16
 * @copyright Copyright (c) 2025
 *
 */

/* DEPENDENCIES */
#include "tiny_fft_test.h"
#include <math.h>
#include <stdio.h>
#include <string.h>

/**
 * @brief Generate a test signal with known frequency components
 */
static void generate_test_signal(float *signal, int len, float sample_rate)
{
    // Generate signal: 0.9*sin(2*pi*15*t) + 0.4*cos(2*pi*70*t) + 0.2*sin(2*pi*120*t)
    // Frequencies: 15 Hz, 70 Hz, and 120 Hz
    for (int i = 0; i < len; i++)
    {
        float t = (float)i / sample_rate;
        signal[i] = 0.9f * sinf(2.0f * M_PI * 15.0f * t) +
                    0.4f * cosf(2.0f * M_PI * 70.0f * t) +
                    0.2f * sinf(2.0f * M_PI * 120.0f * t);
    }
}

void tiny_fft_test(void)
{
    printf("========== TinyFFT Test ==========\n\n");

    const int fft_size = 256;
    const float sample_rate = 1000.0f; // 1 kHz sampling rate
    const int signal_len = fft_size;
    int fft_test_pass = 1;

    // Initialize FFT
    printf("1. FFT Initialization:\n");
    tiny_error_t ret = tiny_fft_init(fft_size);
    if (ret != TINY_OK)
    {
        printf("  ✗ FFT initialization failed: %d\n", ret);
        return;
    }
    printf("  ✓ FFT initialized (max size: %d)\n\n", fft_size);

    // Generate test signal
    float *input_signal = (float *)malloc(signal_len * sizeof(float));
    float *fft_result = (float *)malloc(signal_len * 2 * sizeof(float)); // Complex output
    float *magnitude = (float *)malloc(signal_len * sizeof(float));
    float *power = (float *)malloc(signal_len * sizeof(float));
    float *reconstructed = (float *)malloc(signal_len * sizeof(float));

    if (!input_signal || !fft_result || !magnitude || !power || !reconstructed)
    {
        printf("  ✗ Memory allocation failed\n");
        goto cleanup;
    }

    generate_test_signal(input_signal, signal_len, sample_rate);

    printf("2. Test Signal Generation:\n");
    printf("  Input: Signal with frequencies 15 Hz, 70 Hz, and 120 Hz\n");
    printf("  Sample rate: %.1f Hz\n", sample_rate);
    printf("  Signal length: %d samples\n", signal_len);
    printf("  First 10 samples: ");
    for (int i = 0; i < 10 && i < signal_len; i++)
    {
        printf("%.3f ", input_signal[i]);
    }
    printf("\n\n");

    // Test FFT without window
    printf("3. FFT (No Window):\n");
    printf("  Input: Test signal (length=%d)\n", signal_len);
    ret = tiny_fft_f32(input_signal, signal_len, fft_result, TINY_FFT_WINDOW_NONE);
    if (ret != TINY_OK)
    {
        printf("  ✗ FFT failed: %d\n", ret);
        goto cleanup;
    }
    printf("  ✓ FFT completed\n");

    // Calculate magnitude
    ret = tiny_fft_magnitude_f32(fft_result, signal_len, magnitude);
    if (ret != TINY_OK)
    {
        printf("  ✗ Magnitude calculation failed\n");
        goto cleanup;
    }

    // Calculate power spectrum
    ret = tiny_fft_power_spectrum_f32(fft_result, signal_len, power);
    if (ret != TINY_OK)
    {
        printf("  ✗ Power spectrum calculation failed\n");
        goto cleanup;
    }

    printf("  Output: FFT result (complex, length=%d)\n", signal_len);
    printf("  Magnitude spectrum: First 10 values: ");
    for (int i = 0; i < 10 && i < signal_len; i++)
    {
        printf("%.3f ", magnitude[i]);
    }
    printf("\n\n");

    // Find peak frequency
    printf("4. Peak Frequency Detection:\n");
    printf("  Input: Power spectrum (length=%d)\n", signal_len);
    float peak_freq, peak_power;
    ret = tiny_fft_find_peak_frequency(power, signal_len, sample_rate, &peak_freq, &peak_power);
    if (ret != TINY_OK)
    {
        printf("  ✗ Peak detection failed\n");
        goto cleanup;
    }
    printf("  Output: Peak frequency = %.2f Hz (power = %.3f)\n", peak_freq, peak_power);
    printf("  Expected: strongest peak near ~15 Hz\n\n");
    if (fabsf(peak_freq - 15.0f) > 5.0f)
    {
        fft_test_pass = 0;
    }

    // Find top frequencies
    printf("5. Top Frequencies Detection:\n");
    printf("  Input: Power spectrum (length=%d)\n", signal_len);
    const int top_n = 3;
    float *top_freqs = (float *)malloc(top_n * sizeof(float));
    float *top_powers = (float *)malloc(top_n * sizeof(float));
    if (!top_freqs || !top_powers)
    {
        printf("  ✗ Memory allocation failed\n");
        goto cleanup;
    }

    ret = tiny_fft_find_top_frequencies(power, signal_len, sample_rate, top_n, top_freqs, top_powers);
    if (ret != TINY_OK)
    {
        printf("  ✗ Top frequencies detection failed\n");
        goto cleanup;
    }
    printf("  Output: Top %d frequencies:\n", top_n);
    for (int i = 0; i < top_n; i++)
    {
        printf("    [%d] %.2f Hz (power = %.3f)\n", i + 1, top_freqs[i], top_powers[i]);
    }
    printf("  Expected: top frequencies should include ~15 Hz and ~70 Hz\n\n");
    if (top_freqs[0] <= 0.0f || top_freqs[1] <= 0.0f)
    {
        fft_test_pass = 0;
    }

    // Test IFFT
    printf("6. IFFT (Signal Reconstruction):\n");
    printf("  Input: FFT result (complex, length=%d)\n", signal_len);
    ret = tiny_fft_ifft_f32(fft_result, signal_len, reconstructed);
    if (ret != TINY_OK)
    {
        printf("  ✗ IFFT failed: %d\n", ret);
        goto cleanup;
    }
    printf("  Output: Reconstructed signal (length=%d)\n", signal_len);
    printf("  First 10 samples: ");
    for (int i = 0; i < 10 && i < signal_len; i++)
    {
        printf("%.3f ", reconstructed[i]);
    }
    printf("\n");

    // Verify reconstruction (should match original, accounting for window effects)
    float max_diff = 0.0f;
    for (int i = 0; i < signal_len; i++)
    {
        float diff = fabsf(reconstructed[i] - input_signal[i]);
        if (diff > max_diff)
        {
            max_diff = diff;
        }
    }
    printf("  Max difference from original: %.6f\n", max_diff);
    printf("  ✓ IFFT reconstruction completed\n\n");
    if (max_diff > 1e-3f)
    {
        fft_test_pass = 0;
    }

    // Test with window
    printf("7. FFT with Hanning Window:\n");
    printf("  Input: Test signal (length=%d) with Hanning window\n", signal_len);
    ret = tiny_fft_f32(input_signal, signal_len, fft_result, TINY_FFT_WINDOW_HANNING);
    if (ret != TINY_OK)
    {
        printf("  ✗ Windowed FFT failed\n");
        goto cleanup;
    }
    ret = tiny_fft_power_spectrum_f32(fft_result, signal_len, power);
    if (ret != TINY_OK)
    {
        printf("  ✗ Power spectrum calculation failed\n");
        goto cleanup;
    }
    ret = tiny_fft_find_peak_frequency(power, signal_len, sample_rate, &peak_freq, &peak_power);
    if (ret != TINY_OK)
    {
        printf("  ✗ Peak detection failed\n");
        goto cleanup;
    }
    printf("  Output: Peak frequency = %.2f Hz (power = %.3f)\n", peak_freq, peak_power);
    printf("  Note: Window reduces spectral leakage, improving frequency resolution\n\n");

    free(top_freqs);
    free(top_powers);

cleanup:
    if (input_signal)
        free(input_signal);
    if (fft_result)
        free(fft_result);
    if (magnitude)
        free(magnitude);
    if (power)
        free(power);
    if (reconstructed)
        free(reconstructed);

    // Deinitialize
    tiny_fft_deinit();
    printf("8. FFT Deinitialization:\n");
    printf("  ✓ FFT deinitialized\n");
    printf("  Result: %s\n", fft_test_pass ? "PASS" : "FAIL");

    printf("\n========================================\n");
}

测试结果

========== TinyFFT Test ==========

1. FFT Initialization:
  ✓ FFT initialized (max size: 256)

2. Test Signal Generation:
  Input: Signal with frequencies 15 Hz, 70 Hz, and 120 Hz
  Sample rate: 1000.0 Hz
  Signal length: 256 samples
  First 10 samples: 0.400 0.584 0.623 0.505 0.281 0.056 -0.065 -0.016 0.194 0.498 

3. FFT (No Window):
  Input: Test signal (length=256)
  ✓ FFT completed
  Output: FFT result (complex, length=256)
  Magnitude spectrum: First 10 values: 4.801 5.603 8.669 20.017 111.409 16.176 9.060 6.401 4.987 4.095 

4. Peak Frequency Detection:
  Input: Power spectrum (length=256)
  Output: Peak frequency = 15.61 Hz (power = 48.484)
  Expected: strongest peak near ~15 Hz

5. Top Frequencies Detection:
  Input: Power spectrum (length=256)
  Output: Top 3 frequencies:
    [1] 15.61 Hz (power = 48.484)
    [2] 70.32 Hz (power = 10.440)
    [3] 120.99 Hz (power = 1.998)
  Expected: top frequencies should include ~15 Hz and ~70 Hz

6. IFFT (Signal Reconstruction):
  Input: FFT result (complex, length=256)
  Output: Reconstructed signal (length=256)
  First 10 samples: 0.400 0.584 0.623 0.505 0.281 0.056 -0.065 -0.016 0.194 0.498 
  Max difference from original: 0.000002
  ✓ IFFT reconstruction completed

7. FFT with Hanning Window:
  Input: Test signal (length=256) with Hanning window
  Output: Peak frequency = 15.29 Hz (power = 12.439)
  Note: Window reduces spectral leakage, improving frequency resolution

8. FFT Deinitialization:
  ✓ FFT deinitialized
  Result: PASS

========================================