Как я могу выровнять частотные элементы с величиной преобразования Фурье? - PullRequest
1 голос
/ 29 мая 2019

Я пытаюсь реализовать быстрое преобразование Фурье со связанной функцией комплексной величины на плате разработчика STM32F411RE Nucleo. Моя цель - разделить объединенный сигнал с несколькими синусоидальными элементами на отдельные частотные компоненты с правильной амплитудой.

Моя проблема в том, что я не могу правильно выровнять результаты частотных подборок из функции комплексной величины с частотами. Я также начинаю сомневаться в обоснованности этих результатов как таковых.

Я пытался использовать несколько различных реализаций, опубликованных людьми для алгоритма FFT с фиксированной величиной, в частности, примеры, перечисленные в StackoverFlow от SleuthEye и Блог от LB9MG .

AFAIK У меня похожий подход, но как-то их подходы дают желаемые результаты, а мой - нет. Ниже приведен мой код, который я изменил для работы с помощью реализации, созданной SleuthEye.

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);
        }
}

Ниже показаны результаты, которые я получаю из кода, перечисленного выше: хотя я получаю величину из алгоритмов (с правильным индексом 12), она не соответствует частоте или амплитуде входного массива signalCombined[].

results

Кто-нибудь имеет представление о том, почему это происходит? Как и многие из моих ошибок, это, вероятно, действительно тривиальная и глупая вещь, но я не могу понять для себя, почему это происходит.


РЕДАКТИРОВАТЬ: благодаря помощи SleuthEye поиск частот теперь возможен, поскольку первоначальный подход к генерации сигнала sin () был выполнен неправильно.

Появились некоторые новые проблемы, поскольку БПФ, по-видимому, дает только правильные частоты для 32 выборок, несмотря на соответствующее масштабирование размера ячейки для приспособления к скорректированному размеру выборки.

Я также не могу реализовать алгоритм фиксации амплитуды: согласно Ссылка SleuthEye с примером кода 2*(1/N)*abs(X(k))^2 Я сделал собственную реализацию 2 * powf(fabs(fftMagnitude[j]), 2) / fftLen, как показано в коде ниже, но это делает не дает результатов, которые даже близки к правильным.

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);
    }
}

1 Ответ

2 голосов
/ 30 мая 2019

При генерации тона не учитывается частота дискретизации 1600 Гц, поэтому вы эффективно генерируете тон на частоте 450*1600/(2*PI) ~ 114591Hz, которая получает псевдоним ~ 608 Гц.Эта частота 608 Гц приблизительно соответствует частотному индексу около 12 при использовании размера БПФ 32.

Генерация тона 450 Гц при частоте дискретизации 1600 Гц должна выполняться следующим образом:

for (int i = 0; i< fftLen; i++)
{
    signalCombined[i] = 40 * arm_sin_f32(2 * PI * 450 * i / sampleFreq);
}

Что касается согласования амплитуды, имейте в виду, что коэффициент масштабирования между временной и частотной областями составляет приблизительно 0.5*fftLen (см. этот другой мой пост ).

...