Tek bir frekans için fazı hesaplamak için bir algoritma var mı?


17

Bir işlev varsa f(t)=Asin(ωt+ϕ) , ve referans sinüs sin(ωx) işlem hızlı algoritma olacağını ϕ ?

Goertzel algoritmasına bakıyordum , ama fazla ilgilenmiyor gibi görünüyor?

Yanıtlar:


5

Belirli bir frekansta bir DFT kullanın. Daha sonra gerçek / görüntü parçalarından genlik ve faz hesaplayın. Size örnekleme zamanının başlangıcına atıfta bulunulan fazı verir.

'Normal' bir FFT'de (veya tüm N harmonikleri için hesaplanan bir DFT'de) frekansı tipik olarak f = k * (örnek_ hızı) / N ile hesaplarsınız; burada k bir tamsayıdır. Her ne kadar kutsal görünebilir olsa da (özellikle Tamamen Tamsayı Kilisesi üyeleri için), tek bir DFT yaparken aslında tamsayı olmayan k değerlerini kullanabilirsiniz.

Örneğin, 27 Hz sinüs dalgasının N = 256 noktasını oluşturduğunuzu (veya kazandığınızı) varsayalım. (diyelim ki sample_rate = 200). 256 noktalı FFT (veya N noktası DFT) için 'normal' frekanslarınız aşağıdakilere karşılık gelir: f = k * (örnek_ hızı) / N = k * (200) / 256, burada k bir tamsayıdır. Fakat 34.56 tam sayı olmayan bir 'k', yukarıda listelenen parametreleri kullanarak 27 Hz'lik bir frekansa karşılık gelir. İlgilenilen frekansta (27 Hz.) Tam olarak merkezlenmiş bir DFT 'kutusu' oluşturmak gibidir. Bazı C ++ kodu (DevC ++ derleyicisi) aşağıdaki gibi görünebilir:

#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: Umarım yukarıdakiler stackoverflow'a iyi tercüme eder - bazıları etrafta dolanabilir)

Yukarıdakilerin sonucu, üretilen gerçek noktalarda gösterildiği gibi -twopi / 4'ün bir fazıdır (ve amp, negatif frekansı yansıtmak için amp iki katına çıkar).

Dikkat edilmesi gereken birkaç şey - Test dalga formunu oluşturmak ve sonuçları yorumlamak için kosinüs kullanıyorum - bu konuda dikkatli olmalısınız - faz, örneklemeye başladığınız zaman olan zaman = 0'a atıfta bulunur (yani: r [0] topladığınızda ) ve kosinüs doğru yorumdur).

Yukarıdaki kod ne zarif ne de etkilidir (ör. Sin / cos değerleri vb. İçin bir arama tabloları kullanın).

Daha büyük N kullandıkça sonuçlarınız daha doğru olacaktır ve yukarıdaki örnekleme hızı ve N'nin birbirinin katları olmaması nedeniyle küçük bir hata vardır.

Elbette, örnek oranınızı (N veya f) değiştirmek isterseniz, kodu ve k değerini değiştirmeniz gerekir. Bir DFT selesini sürekli frekans çizgisi üzerinde herhangi bir yere düşürebilirsiniz - sadece ilgili frekansa karşılık gelen bir k değeri kullandığınızdan emin olun.


Bu yaklaşım, k'nin bir bütüne daha yakın olması için N ayarlanarak geliştirilebilir. Bu algoritmanın doğruluğunu artıran ayrı bir cevap gönderdim.
mojuba

10

Sorun, (doğrusal olmayan) en küçük kareler sorunu olarak formüle edilebilir:

F(ϕ)=12i=1n[Asin(ωi+ϕ)fi(ω)]2

F(ϕ)ϕ

Türev çok basit:

F(ϕ)=i=1nAcos(ωi+ϕ)[Asin(ωi+ϕ)fi(ω)]

F(ϕ)

Açıkçası, yukarıdaki objektif fonksiyonun periyodiklik nedeniyle birden fazla minimasyonu vardır, bu nedenle diğer minimayı ayırt etmek için bir ceza süresi eklenebilir (örneğin, model denklemine eklenmesi ). Ancak, optimizasyonun sadece en yakın minima ile birleşeceğini düşünüyorum ve çıkararak sonucu güncelleyebilirsiniz .ϕ22πk,kN


Periyodiklik nedeniyle cezalandırmanız gerektiğini düşünmüyorum hayır mı? Faz alanına yakınlaştığı minimaları alabilir ve modulu , değil mi? 2π
Spacey

@Mohammad Evet, ancak bazı optimizasyon teknikleri aynı değere yaklaşması veya tek bir küresel minimizer ile ikinci dereceden iyi bir şekilde tahmin edilebilen dışbükey bir fonksiyon üstlenmesi gereken birden fazla başlangıç ​​noktası kullanabilir. Diğer bir faydası da herhangi bir başlangıç ​​noktası için aynı sonuca . ϕ0
Libor

İlginç. Sizi bu ilgili soruda bir çatlamaya davet edebilir miyim ? :-)
Spacey

@Mohammad OK, orada biraz katkıda bulundum :)
Libor

Fi (w) işlevi nereye gider? fi (w) sabit değildir, dolayısıyla sabit olmayan bir türevi aldığınızda nasıl sıfır olur?
SamFisher83

5

Goertzel algoritmasının birkaç farklı formülasyonu vardır. Olası çıktılar olarak 2 durum değişkeni (dik veya yakın) veya karmaşık bir durum değişkeni sağlayanlar genellikle Goertzel penceresindeki orta gibi bir noktaya referansla fazı hesaplamak veya tahmin etmek için kullanılabilir. Tek başına tek bir skaler çıktı sağlayanlar genellikle yapamazlar.

Ayrıca Goertzel pencerenizin zaman ekseninize göre nerede olduğunu da bilmeniz gerekir.

Sinyaliniz Goertzel pencerenizde tam olarak periyodik değilse, pencerenin ortasındaki bir referans noktasının etrafındaki faz tahmini, fazı başlangıç ​​veya bitişe göre daha doğru olabilir.

Sinyalinizin frekansını biliyorsanız, tam bir FFT aşırıya kaçar. Ayrıca bir Goertzel, FFT uzunluğunda periyodik olmayan bir frekansa ayarlanabilirken, FFT'nin penceresiz olmayan frekanslar için ek enterpolasyon veya sıfır dolguya ihtiyacı olacaktır.

Karmaşık bir Goertzel, kosinüs ve sinüs bazlı vektörler veya FFT twiddle faktörleri için bir nüks kullanan bir DFT'nin 1 bölmesine eşdeğerdir.


Pencerenin içindeki faz tahmini tam olarak aynı doğrulukta değil mi, çünkü pencerenin içindeki örneğindeki faz tahminini hesaplamak için pencerenin başlangıcındaki faz tahminine eklersiniz ( pencerenin başlangıcı olmak)? k k = 0ωkkk=0
Olli Niemitalo

Hayır, çünkü wk eklemek, pencerenin sonunda, tamsayı olmayan bir periyodik diyafram açıklığı sinüzoid için başlangıçtan farklı bir faz ile sonuçlanır. Ancak 1 bölmeli DFT aynı noktada tek bir dairesel faz hesaplar. Böylece 3 değerin hepsi farklı olacaktır. Ancak merkez faz, ne olursa olsun, her zaman tek / çift fonksiyon oranıyla ilişkilidir.
hotpaw2

Deniyorum, ama anlamıyorum.
Olli Niemitalo

Bir kosinüs kullanın (k = 0'da sıfır fazı), frekansı hafifçe ayarlayın (küçük bir irrasyonel sayı ile, ancak k = 0'daki fazı değiştirmeden). Bir DFT aşamanın değiştiğini bildiriyor! Aynısını tam olarak k = N / 2 merkezli bir kosinüs ile deneyin. Herhangi bir df için k = N / 2'de değişiklik yok. Günah veya herhangi bir karışım için aynı. Faz referans noktasının ortalanması, f0'daki değişikliklerle ölçülen fazda daha az değişiklik gösterir. örneğin, frekans hatası faz ölçüm hatalarının artmasına katkıda bulunmaz.
hotpaw2

1
Evet, sinüsoid ve Goertzel filtresinin farklı frekanslarda olması durumunda, faz tahmin hatası pencerenin merkezinde daha azdır. Bu durumda, pencerenin sonundaki faz tahmini, merkez ile pencerenin sonu arasındaki mesafenin ve sinüsoid ve Goertzel filtre frekansları arasındaki farkın ürünü olan bir sabit tarafından önyargılıdır. Bu yanlılığın çıkarılması, merkez tahminiyle aynı boyutta hata verir, ancak sinüzoidin sıklığını bilmeyi gerektirir.
Olli Niemitalo

4

Sinyalleriniz parazitsizse, her ikisinde de sıfır geçişi tanımlayabilir ve frekansı ve bağıl fazı belirleyebilirsiniz.


3

Bu, "hızlı" tanımınızın ne olduğuna, tahmininizin ne kadar doğru olmasını istediğinize, veya örneklemlerinizle ilgili faza bağlı olup olmadığınıza ve işlev ve referans sinüs dalgası üzerinde ne kadar gürültü olduğuna bağlıdır.ϕ

Bunu yapmanın bir yolu sadece nin FFT'sini almak ve en yakın bakmaktır . ωf(t)ω Ancak, bu çöp kutusu merkez frekansına yakın olmasına bağlı olacaktır .ω

Yani:

  • Ne demek "hızlı"?
  • Tahmine ne kadar doğru ihtiyacınız var?
  • Eğer istiyor musunuz örnekleme başlamasından (referansına faz relatif) veya faz relatif? Önemli mi?ϕ
  • Her sinyaldeki gürültü seviyesi nedir?

PS: yerine demek istediğinizi varsayıyorum .f(t)=Asin(ωt+ϕ)f(t)=Asin(ωx+ϕ)


2

Başlangıç ​​noktası:
1) sinyalinizi ve referans sinüs dalgınızı çarpın: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) ) 2) dönemindeki integrali bul : 3) hesaplayabilirsiniz :
T = π / ω I ( ϕ ) = T 0 F ( t ) d t = 0.5 A c o s ( ϕ ) T ϕ c o s ( ϕ ) = I ( t ) / ( 0,5 A T )F(t)
T=π/ω
I(ϕ)=0TF(t)dt =0.5Acos(ϕ)T
ϕ
cos(ϕ)=I(t)/(0.5AT)

Bir düşünün:
A nasıl ölçülür?
belirlemek için olarak aralığı? ("referans cos dalgası" nı düşünün )0 .. ( 2 π )ϕ0..(2π)

Ayrık sinyal için integrali toplamla değiştirin ve T'yi dikkatlice seçin!


1

Bunu da yapabilirsiniz (numpy gösterimde):

np.arctan( (signal*cos).sum() / (signal*sin).sum() ))

burada sinyalin faz kayması sinyali, cos ve sin referans sinyalleridir ve iki ürün üzerinden toplanarak belirli bir zaman diliminde bir integralin yaklaşık bir üretimini elde edersiniz.


0

Bu, Kevin McGee'nin kesirli bir çöp kutusu endeksi ile tek frekanslı DFT kullanma önerisindeki bir gelişmedir. Kevin'in algoritması harika sonuçlar vermez: yarım kutularda ve tüm kutularda çok hassas olsa da, wholes ve yarılara yakın da oldukça iyidir, ancak aksi takdirde hata% 5 içinde olabilir, bu muhtemelen çoğu görev için kabul edilemez .

Kevin'in algoritmasını , yani DFT penceresinin uzunluğunu ayarlayarak geliştirmeyi öneriyorum , böylece mümkün olduğunca bir bütüne yaklaşıyor. Bu, FFT'den farklı olarak çalışır, DFT, 2 gücü olmasını gerektirmez .NkN

Aşağıdaki kod Swift'te, ancak sezgisel olarak açık olmalıdır:

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

FFT, bir DFT'yi verimli bir şekilde hesaplamanın bir yoludur. Modern kütüphanelerde, iki kısıtlamanın gücü artık orada değildir. Yalnızca bir veya iki kutu değerine ihtiyacınız varsa, bunları doğrudan sizin yaptığınız gibi hesaplamak daha iyidir. Tek bir saf ton için (gerçek veya karmaşık), frekansı, fazı ve genliği tam olarak hesaplamak için sadece iki kutu değerine ihtiyaç vardır. Bkz. Dsprelated.com/showarticle/1284.php . Matematik oldukça sofistike, ancak türetmelerin açıklandığı makalelere bağlantılar var. Doğrusal Cebir, gerçek bir anlayış için bir ön koşuldur.
Cedron Dawg
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.