Подбор синусоидальной частоты - PullRequest
4 голосов
/ 21 января 2010

Этот вопрос основан на предыдущем аналогичном вопросе.

У меня есть следующее уравнение и скорректированные (некоторые случайные данные): 0,44 * sin (N * 2 * PI / 30)

Я пытаюсь использовать БПФ для получения частоты из сгенерированных данных. Однако частота оказывается близкой, но не равной частоте (что делает волну немного больше, чем предполагалось)

Максимальные частоты для БПФ составляют 7 Гц, однако ожидаемая частота составляет (30 / 2PI) 4,77 Гц.

Я включил график БПФ и нанесенные значения.

alt text

Код, который я использую:

[sampleFFTValues sFreq] = positiveFFT(sampledata, 1);
sampleFFTValues = abs(sampleFFTValues);
[v sFFTV]= max(sampleFFTValues)

Положительное БПФ может быть найдено здесь . В основном он центрирует график БПФ и отсекает отрицательные сигналы.

У меня вопрос, как я могу сделать БПФ более точным, не прибегая к наименьшим квадратам только для частоты?

Ответы [ 7 ]

5 голосов
/ 22 января 2010

Как уже упоминалось, вы неправильно интерпретируете частоту сигнала. Позвольте мне привести пример, чтобы прояснить несколько вещей:

Fs = 200;                        %# sampling rate
t = 0:1/Fs:1-1/Fs;               %# time vector of 1 second 
f = 6;                           %# frequency of signal
x = 0.44*sin(2*pi*f*t);          %# sine wave

N = length(x);                   %# length of signal
nfft = N;                        %# n-point DFT, by default nfft=length(x)
                                 %# (Note: it is faster if nfft is a power of 2)
X = abs(fft(x,nfft)).^2 / nfft;  %# square of the magnitude of FFT

cutOff = ceil((nfft+1)/2);       %# nyquist frequency
X = X(1:cutOff);                 %# FFT is symmetric, take first half
X(2:end -1) = 2 * X(2:end -1);   %# compensate for the energy of the other half
fr = (0:cutOff-1)*Fs/nfft;       %# frequency vector

subplot(211), plot(t, x)
title('Signal (Time Domain)')
xlabel('Time (sec)'), ylabel('Amplitude')

subplot(212), stem(fr, X)
title('Power Spectrum (Frequency Domain)')
xlabel('Frequency (Hz)'), ylabel('Power')

time_frequency_domain

Теперь вы можете видеть, что пик в БПФ соответствует исходной частоте сигнала при 6 Гц

[v idx] = max(X);
fr(idx)
ans = 
      6

Мы можем даже проверить, что Теорема Парсеваля справедлива:

( sum(x.^2) - sum(X) )/nfft < 1e-6

Вариант 2

В качестве альтернативы, мы можем использовать функции панели инструментов обработки сигналов:

%# estimate the power spectral density (PSD) using the periodogram
h = spectrum.periodogram;
hopts = psdopts(h);
set(hopts, 'Fs',Fs, 'NFFT',nfft, 'SpectrumType','onesided')

hpsd = psd(h, x, hopts);
figure, plot(hpsd)

Pxx = hpsd.Data;
fr = hpsd.Frequencies;
[v idx]= max(Pxx)
fr(idx)

avgpower(hpsd)

periodogram

Обратите внимание, что эта функция использует логарифмическую шкалу: plot(fr,10*log10(Pxx)) вместо plot(fr,Pxx)

4 голосов
/ 22 января 2010

Я не думаю, что БПФ подходит для измерения частоты с точным разрешением (квази) периодических сигналов - см. Ниже.

Каждое дискретное БПФ имеет расширение на нецелочисленных частотах бина (то есть на любой частоте, которая точно не соответствует одному из шагов частоты конкретного БПФ); эти «промежуточные» частоты будут размазаны / размазаны вокруг ближайшего целочисленного бина. Форма этого расширения («функция расширения») зависит от оконной функции, используемой для БПФ. Эта функция распределения - для упрощения и обобщения - либо очень узкая, но очень-очень рваная (очень высокие пики / очень низкие долины), либо шире, но менее рваная. Теоретически, вы можете выполнить очень тонкую частотную развертку синусоидальных волн и рассчитать БПФ для каждого из них, а затем «калибровать» форму и поведение функции, сохранив выходные данные всех БПФ вместе с частотой, которая привела к этому выходу, а затем путем сравнения выходного сигнала БПФ измеряемого сигнала с ранее сохраненными результатами и нахождения «ближайшего» находим более точную частоту.

Много усилий.

Но не делайте этого, если вам нужно только измерить частоту одного сигнала.

Вместо этого попробуйте измерить длину волны. Это может быть так же просто, как измерение расстояния между нулевыми пересечениями (возможно, для нескольких циклов, чтобы получить большую точность - черт, измерить 1000 циклов, если у вас их столько) в выборках и разделить частоту выборки на эту, чтобы получить частоту. Гораздо проще, быстрее и точнее.

Пример: частота дискретизации 48000 Гц, сигнал 4,77 Гц дает разрешение ~ 0,0005 Гц, просто измеряя длину цикла один с самым грубым подходом. (Если вы берете n циклов, разрешение по частоте умножается также на n .)

1 голос
/ 18 апреля 2012

То, что вы ищете, это метод оценки частоты, и их много. БПФ является одним из компонентов нескольких методов оценки. Простое использование бина пиковой величины, как в вашем примере, дает вам худшее разрешение (но наибольшую помехоустойчивость к любым другим точно периодическим синусоидам). В ситуациях с низким уровнем шума вы можете интерполировать. Параболическая интерполяция логарифмической величины является одной общей оценкой, но синхронная интерполяция результатов FFT может быть лучше для прямоугольного окна. Нулевое заполнение и выполнение более длинного БПФ в основном эквивалентно интерполяции.

Для точной синусоиды с нулевым шумом забудьте о БПФ и просто решите уравнение с 3 неизвестными, которые могут включать всего 3 или 4 точки выборки без наложения, алгоритмы для этого здесь и здесь .

Я перечислю несколько других методов оценки частоты на моей DSP веб-странице .

1 голос
/ 22 января 2010

Предполагая, что N - это время в секундах, ваша частота равна 1/30 Гц (y=A * sin( 2* PI * f * t))

Разрешение по частоте = Частота дискретизации / Точки FFT

Частота дискретизации определяется по критерию Найквиста, частота дискретизации (выборок / секунда) должна быть как минимум в два раза больше максимальной частоты, подлежащей анализу, например 48 кГц для анализа до 24 кГц. (Для данных «реальной жизни» хорошо иметь немного буфера).

Итак, вам может потребоваться увеличить размер вашего БПФ.

0 голосов
/ 22 января 2010

Во-первых, исправление вашего вопроса: (30 / 2PI) не частота. Частота вашего сигнала составляет 1/30 * независимо от частоты дискретизации, которую вы использовали. Во-вторых, можете ли вы сказать мне, какова была длина вектора сэмплированных данных? Когда FFT возвращает вектор значений, i-е значение будет соответствовать f_i = i / N, где N - длина вектора и i \ in [0, N-1] Вы хотите, чтобы i / N было точно равно 1/30 для некоторого целого числа i. Другими словами, N должно равняться 30 * i, т. Е. N должно быть кратным 30. Теперь, была ли длина вектора, который вы использовали, кратной 30? Если не попытаться сделать это, и это должен решить проблему.

0 голосов
/ 22 января 2010

Если вы генерируете из функции, в отличие от работы с выборками, вы можете сгенерировать МНОГО точек и выполнить БОЛЬШОЕ БПФ, чтобы частотные бины были очень малы для высокой точности. Но это не решит основную проблему.

0 голосов
/ 22 января 2010

Попробуйте оконную функцию ?

...