Якщо у вас є функція та опорна син хвиля який би був швидкий алгоритм для обчислення ?
Я дивився алгоритм Ґерцеля , але він, схоже, не має відношення до фази?
Якщо у вас є функція та опорна син хвиля який би був швидкий алгоритм для обчислення ?
Я дивився алгоритм Ґерцеля , але він, схоже, не має відношення до фази?
Відповіді:
Використовуйте DFT на певній частоті. Потім обчисліть амплітуду та фазу з реальних / зображень частин. Це дає вам фазу, на яку посилається початок часу вибірки.
У нормальній FFT (або DFT, обчисленій для всіх N гармонік), ти зазвичай обчислюєш частоту з f = k * (sample_rate) / N, де k - ціле число. Хоча це може здатися божевільним (особливо для членів Церкви цілого цілого цілого), ви можете насправді використовувати не цілі значення k при виконанні однієї DFT.
Наприклад, припустимо, що ви створили (або отримали) N = 256 точок синусоїди в 27 Гц. (скажімо, sample_rate = 200). Ваші "звичайні" частоти для 256-кратної FFT (або N точки DFT) відповідали б: 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, як показано в генерованих реальних точках (а підсилювач подвоюється, щоб відображати частоту pos / neg).
Кілька речей, які слід зазначити - я використовую косинус для генерування форми тестової хвилі та інтерпретації результатів - ви повинні бути обережними з цього приводу - фаза посилається на час = 0, тобто коли ви почали вибірку (тобто: коли ви збирали r [0] ), а косинус - це правильне тлумачення).
Вищевказаний код не є ні елегантним, ні ефективним (наприклад: використовуйте оглядові таблиці для значень sin / cos тощо).
Ваші результати стануть більш точними, коли ви використовуєте більший N, і є невелика помилка через те, що частота вибірки та N вище не кратні один одному.
Звичайно, якщо ви хочете змінити швидкість вибірки, N або f, вам доведеться змінити код і значення k. Ви можете збивати бункер DFT в будь-якій точці лінії безперервної частоти - просто переконайтеся, що ви використовуєте значення k, яке відповідає частоті, що цікавить.
Задача може бути сформульована як (нелінійна) проблема найменших квадратів:
Похідна дуже проста:
Очевидно, що вищевказана цільова функція має декілька мінімумів через періодичність, отже, може бути доданий певний стягнення для розмежування інших мінімумів (наприклад, додавання до рівняння моделі). Але я думаю , що оптимізація буде просто сходитися до найближчого мінімуму , і ви можете оновити результат віднімання . 2 π k , k ∈ N
Існує кілька різних формулювань алгоритму Ґерцеля. Ті, що забезпечують 2 змінних стану (ортогональні або близькі до), або складну змінну стану, як можливі виходи, часто можуть бути використані для обчислення або оцінки фази з посиланням на деяку точку вікна Ґерцеля, наприклад середину. Ті, які забезпечують одиночний скалярний вихід, як правило, не можуть.
Вам також потрібно знати, де знаходиться ваше вікно Ґерцеля стосовно вашої часової осі.
Якщо ваш сигнал не є точно цілим періодичним періодом у вашому вікні Ґерцеля, фазова оцінка навколо опорної точки посередині вікна може бути точнішою, ніж посилання фази на початок чи кінець.
Повний FFT є надмірним, якщо ви знаєте частоту сигналу. Крім того, Ґерцель може бути налаштований на частоту, не періодичну по довжині FFT, тоді як для FFT знадобиться додаткова інтерполяція або нульове набивання для неперіодичних віконних частот.
Складний Ґерцель еквівалентний 1 бункеру DFT, який використовує повтор для косинусних і синусоїдних векторів або коефіцієнтів зміщення FFT.
Це залежить від того, яке ваше визначення "швидкий" - це, наскільки точна ви хочете оцінити, чи хочете ви або фазу відносно ваших вибірок, і скільки шуму є у вашої функції та опорної синусоїди.
Один із способів зробити це - просто взяти FFT і просто подивитися на бункер, найближчий до . ω Однак це залежатиме від наближення до частоти центрального біна.
Так:
PS: Я припускаю, що ви мали на увазі , а не .
Початкова точка:
1) помножте свій сигнал і опорну грішну хвилю: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0,5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) )
2) знайти інтеграл на період :
3) можна обчислити :
T = π / ω I ( ϕ ) = ∫ T 0 F ( t ) d t = 0,5 ⋅ A ⋅ c o s ( ϕ ) ⋅ T ϕ c o s ( ϕ ) = I ( t ) / ( 0,5 ⋅ A ⋅ T )
Подумайте:
як виміряти А?
як визначити через інтервал ? (подумайте про "еталонну хвилю cos ")0 .. ( 2 ⋅ π )
Для дискретного сигналу змініть інтеграл на суму і обережно виберіть T!
Це вдосконалення щодо пропозиції @Kevin McGee використовувати одночастотний DFT з індексом дробової бінки. Алгоритм Кевіна не дає великих результатів: в той час як на половині і цілих бункерах він дуже точний, також близький до цілих і половинок, це також досить добре, але в іншому випадку помилка може бути в межах 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))