Если у вас есть функция и эталонная волна что будет быстрым алгоритмом для вычисления ?
Я смотрел на алгоритм Гёртцела , но он не имеет отношения к фазе?
Если у вас есть функция и эталонная волна что будет быстрым алгоритмом для вычисления ?
Я смотрел на алгоритм Гёртцела , но он не имеет отношения к фазе?
Ответы:
Используйте ДПФ на определенной частоте. Затем вычислите амплитуду и фазу из реальной / воображаемой частей. Это дает вам фазу, относящуюся к началу времени выборки.
В «нормальном» БПФ (или ДПФ, рассчитанном для всех N гармоник) вы обычно вычисляете частоту с помощью f = k * (sample_rate) / N, где k - целое число. Хотя это может показаться кощунственным (особенно членам Церкви Полностью Целого), вы можете использовать нецелые значения k при выполнении одного ДПФ.
Например, предположим, что вы сгенерировали (или получили) N = 256 точек синусоиды 27 Гц. (скажем, sample_rate = 200). Ваши «нормальные» частоты для 256-точечного БПФ (или N-точечного БПФ) будут соответствовать: f = k * (sample_rate) / N = k * (200) / 256, где k - целое число. Но нецелое «k» 34,56 будет соответствовать частоте 27 Гц, используя параметры, перечисленные выше. Это похоже на создание «корзины» DFT, которая точно центрирована на интересующей частоте (27 Гц.). Некоторый код C ++ (DevC ++ компилятор) может выглядеть следующим образом:
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <cmath>
using namespace std;
// arguments in main needed for Dev-C++ I/O
int main (int nNumberofArgs, char* pszArgs[ ] ) {
const long N = 256 ;
double sample_rate = 200., amp, phase, t, C, S, twopi = 6.2831853071795865;
double r[N] = {0.}, i[N] = {0.}, R = 0., I = 0. ;
long n ;
// k need not be integer
double k = 34.56;
// generate real points
for (n = 0; n < N; n++) {
t = n/sample_rate;
r[n] = 10.*cos(twopi*27.*t - twopi/4.);
} // end for
// compute one DFT
for (n = 0; n < N; n++) {
C = cos(twopi*n*k/N); S = sin(twopi*n*k/N);
R = R + r[n]*C + i[n]*S;
I = I + i[n]*C - r[n]*S;
} // end for
cout<<"\n\ndft results for N = " << N << "\n";
cout<<"\nindex k real imaginary amplitude phase\n";
amp = 2*sqrt( (R/N)*(R/N) + (I/N)*(I/N) ) ;
phase = atan2( I, R ) ;
// printed R and I are scaled
printf("%4.2f\t%11.8f\t%11.8f\t%11.8f\t%11.8f\n",k,R/N,I/N,amp,phase);
cout << "\n\n";
system ("PAUSE");
return 0;
} // end main
//**** end program
(PS: я надеюсь, что вышеупомянутое хорошо транслируется в stackoverflow - некоторые из них могут обернуться)
Результатом вышеупомянутого является фаза -twopi / 4, как показано в сгенерированных реальных точках (и усиление удваивается для отражения частоты положительного / отрицательного частот).
Несколько вещей, на которые стоит обратить внимание - я использую косинус для генерации тестовой формы волны и интерпретации результатов - вы должны быть осторожны с этим - фаза ссылается на время = 0, то есть когда вы начали сэмплирование (т.е. когда вы собрали r [0] ), а косинус - правильная интерпретация).
Приведенный выше код не является ни элегантным, ни эффективным (например: используйте справочные таблицы для значений sin / cos и т. Д.).
Ваши результаты станут более точными, если вы будете использовать большее N, и есть небольшая ошибка из-за того, что частота дискретизации и N выше не кратны друг другу.
Конечно, если вы хотите изменить частоту дискретизации, N или f, вам придется изменить код и значение k. Вы можете вставить ячейку DFT в любое место на непрерывной частотной линии - просто убедитесь, что вы используете значение k, которое соответствует интересующей частоте.
Задача может быть сформулирована как (нелинейная) задача наименьших квадратов:
где - целевая функция для минимизации по отношению к .
Производная очень проста:
Выше целевая функция может быть сведена к минимуму итеративно с помощью метода градиентного спуска (приближение первого порядка), метод Ньютона , метод Гаусса-Ньютон или метод Левенберга-Marquardt (второй порядок аппроксимации - должна быть предоставлены в них).
Очевидно, что указанная выше целевая функция имеет несколько минимумов из-за периодичности, поэтому можно добавить некоторый штрафной член для различения других минимумов (например, добавив к модельному уравнению). Но я думаю , что оптимизация будет просто сходиться до ближайшего минимума , и вы можете обновить результат вычитания .
Существует несколько различных формулировок алгоритма Гёртцеля. Те, которые предоставляют 2 переменные состояния (ортогональные или близкие к) или комплексную переменную состояния, в качестве возможных выходных данных часто могут использоваться для вычисления или оценки фазы со ссылкой на некоторую точку в окне Гертцеля, например на середину. Те, которые обеспечивают один скалярный вывод, обычно не могут.
Вам также необходимо знать, где находится ваше окно Гертцеля относительно вашей временной оси.
Если ваш сигнал не является точно целочисленным периодом в вашем окне Гертцеля, оценка фазы вокруг контрольной точки в середине окна может быть более точной, чем привязка фазы к началу или концу.
Полное БПФ является избыточным, если вы знаете частоту вашего сигнала. Кроме того, Goertzel может быть настроен на частоту, непериодическую по длине БПФ, тогда как БПФ потребуется дополнительная интерполяция или заполнение нулями для непериодических в окне частот.
Комплексный Гертцель эквивалентен 1 бину ДПФ, который использует рекуррентность для векторов косинуса и синуса или коэффициентов твиндла БПФ.
Это зависит от того, что ваше определение «быстрый» является, насколько точным вы хотите , чтобы ваша оценка, хотите ли вы или фазу относительно ваших выборках, и как много шума есть на вашей функции и опорной синусоиды.
Один из способов сделать это - просто взять БПФ и просто посмотреть на корзину, ближайшую к . ω Однако это будет зависеть от того, что находится близко к центральной частоте бина.
Так:
PS: я предполагаю, что вы имели в виду , а не .
Начальная точка:
1) умножьте ваш сигнал и эталонную волну греха: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) )
2) найти интеграл по периоду :
3), который можно вычислить :
Задумайтесь:
как измерить А?
как определить в интервале ? (думать о «эталонный созе волны»)
Для дискретного сигнала измените интеграл на сумму и тщательно выберите T!
Это улучшение предложения @Kevin McGee об использовании одночастотного ДПФ с дробным индексом бина. Алгоритм Кевина не дает хороших результатов: хотя для половинок и целых бинов он очень точный, также близко к целым и половинкам, он также довольно хорош, но в противном случае ошибка может быть в пределах 5%, что, вероятно, неприемлемо для большинства задач. ,
Я предлагаю улучшить алгоритм Кевина, отрегулировав , то есть длину окна DFT, чтобы подходило как можно ближе к целому. Это работает, поскольку в отличие от FFT, DFT не требует, чтобы было степенью 2.
Код ниже написан на Swift, но должен быть интуитивно понятен:
let f = 27.0 // frequency of the sinusoid we are going to generate
let S = 200.0 // sampling rate
let Nmax = 512 // max DFT window length
let twopi = 2 * Double.pi
// First, calculate k for Nmax, and then round it
var k = round(f * Double(Nmax) / S)
// The magic part: recalculate N to make k as close to whole as possible
// We also need to recalculate k once again due to rounding of N. This is important.
let N = Int(k * S / f)
k = f * Double(N) / S
// Generate the sinusoid
var r: [Double] = []
for i in 0..<N {
let t = Double(i) / S
r.append(sin(twopi * f * t))
}
// Compute single-frequency DFT
var R = 0.0, I = 0.0
let twopikn = twopi * k / Double(N)
for i in 0..<N {
let x = Double(i) * twopikn
R += r[i] * cos(x)
I += r[i] * sin(x)
}
R /= Double(N)
I /= Double(N)
let amp = 2 * sqrt(R * R + I * I)
let phase = atan2(I, R) / twopi
print(String(format: "k = %.2f R = %.8f I = %.8f A = %.8f φ/2π = %.8f", k, R, I, amp, phase))