Có một thuật toán để tính toán pha cho một câu đố không?


17

Nếu bạn có một hàm , và sóng tham khảo tội lỗi tội lỗi ( ω x ) những gì sẽ được tính toán một thuật toán nhanh φ ?f(t)=Asin(ωt+ϕ)sin(ωx)ϕ

Tôi đã xem xét thuật toán Goertzel , nhưng nó dường như không đối phó với pha?

Câu trả lời:


5

Sử dụng DFT ở tần số cụ thể. Sau đó tính biên độ và pha từ các phần thực / tưởng tượng. Nó cung cấp cho bạn giai đoạn được tham chiếu khi bắt đầu thời gian lấy mẫu.

Trong FFT 'bình thường' (hoặc DFT được tính cho tất cả các sóng hài N), bạn thường tính tần số với f = k * (sample_rate) / N, trong đó k là số nguyên. Mặc dù nó có vẻ đặc biệt (đặc biệt là với các thành viên của Church of the Wholly Integer), nhưng bạn thực sự có thể sử dụng các giá trị không nguyên của k khi thực hiện một DFT duy nhất.

Chẳng hạn, giả sử bạn đã tạo (hoặc thu được) N = 256 điểm của sóng hình sin 27 Hz. (giả sử, sample_rate = 200). Tần số 'bình thường' của bạn cho FFT 256 điểm (hoặc DFT điểm N) sẽ tương ứng với: f = k * (sample_rate) / N = k * (200) / 256, trong đó k là số nguyên. Nhưng một số nguyên 'k' 34,56 sẽ không tương ứng với tần số 27 Hz., Sử dụng các tham số được liệt kê ở trên. Nó giống như tạo ra một 'thùng' DFT chính xác tập trung ở tần số quan tâm (27 Hz.). Một số mã C ++ (trình biên dịch DevC ++) có thể trông như sau:

#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: Tôi hy vọng những điều ở trên có thể chuyển dịch tốt sang stackoverflow - một số có thể bao quanh)

Kết quả của phần trên là một pha của -twopi / 4, như thể hiện trong các điểm thực được tạo (và amp được nhân đôi để phản ánh tần số pos / neg).

Một vài điều cần lưu ý - Tôi sử dụng cosine để tạo dạng sóng thử nghiệm và diễn giải kết quả - bạn phải cẩn thận về điều đó - pha được tham chiếu đến time = 0, đó là khi bạn bắt đầu lấy mẫu (tức là: khi bạn thu thập r [0] ), và cosine là giải thích chính xác).

Đoạn mã trên không thanh lịch cũng không hiệu quả (ví dụ: sử dụng bảng tra cứu cho các giá trị sin / cos, v.v.).

Kết quả của bạn sẽ chính xác hơn khi bạn sử dụng N lớn hơn và có một chút lỗi do thực tế là tỷ lệ mẫu và N ở trên không phải là bội số của nhau.

Tất nhiên, nếu bạn muốn thay đổi tỷ lệ mẫu, N hoặc f, bạn phải thay đổi mã và giá trị của k. Bạn có thể đặt thùng DFT xuống bất cứ nơi nào trên đường tần số liên tục - chỉ cần đảm bảo rằng bạn đang sử dụng giá trị k tương ứng với tần suất quan tâm.


Cách tiếp cận này có thể được cải thiện bằng cách điều chỉnh N để làm cho k gần hơn với tổng thể. Tôi đã đăng một câu trả lời riêng biệt mà thiếu tính chính xác của thuật toán này.
mojuba

10

Vấn đề có thể được coi là vấn đề bình phương nhỏ nhất (phi tuyến):

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

F(ϕ)ϕ

Đạo hàm rất đơn giản:

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

F(ϕ)

ϕ22πk,kN


2π

ϕ0

Hấp dẫn. Tôi có thể mời bạn cũng có một vết nứt tại câu hỏi liên quan này ? :-)
Spacey

@Mohammad OK, tôi đã đóng góp một chút ở đó :)
Libor

Hàm fi (w) đi đâu? fi (w) không phải là hằng số vì vậy khi bạn lấy đạo hàm của một hằng số, làm thế nào để nó trở thành số không?
SamFisher83

5

Có một số công thức khác nhau của thuật toán Goertzel. Các biến cung cấp 2 biến trạng thái (trực giao hoặc gần) hoặc biến trạng thái phức, thường có thể được sử dụng để tính toán hoặc ước tính pha với tham chiếu đến một số điểm trong cửa sổ Goertzel, chẳng hạn như ở giữa. Những cái cung cấp một đầu ra vô hướng một mình thường không thể.

Bạn cũng sẽ cần biết cửa sổ Goertzel của bạn ở đâu so với trục thời gian của bạn.

Nếu tín hiệu của bạn không chính xác là định kỳ nguyên trong cửa sổ Goertzel của bạn, ước tính pha xung quanh một điểm tham chiếu ở giữa cửa sổ có thể chính xác hơn sau đó tham chiếu pha đến đầu hoặc cuối.

Một FFT đầy đủ là quá mức nếu bạn biết tần số tín hiệu của mình. Ngoài ra, một Goertzel có thể được điều chỉnh theo tần số không định kỳ theo độ dài FFT, trong khi đó FFT sẽ cần nội suy bổ sung hoặc phần đệm bằng 0 cho các tần số không định kỳ trong cửa sổ.

Một Goertzel phức tạp tương đương với 1 thùng DFT sử dụng sự tái phát cho các vectơ cơ sở cosin và sin hoặc các yếu tố twiddle FFT.


ωkkk=0

Không, bởi vì việc thêm wk dẫn đến một pha khác ở cuối cửa sổ so với lúc bắt đầu cho một hình sin không nguyên số định kỳ trong khẩu độ. Nhưng DFT 1 thùng tính toán một pha tròn tại cùng một điểm. Do đó, 3 giá trị sẽ khác nhau. Nhưng pha trung tâm luôn liên quan đến tỷ lệ của hàm lẻ / chẵn, không có vấn đề gì.
hotpaw2

Cố gắng, nhưng tôi không hiểu điều đó.
Olli Niemitalo

Sử dụng cosin (pha 0 tại k = 0), điều chỉnh tần số một chút (bằng một số vô tỷ nhỏ, nhưng không thay đổi pha ở k = 0). Một DFT báo cáo giai đoạn đã thay đổi! Thử tương tự với một cosin chính xác tập trung tại k = N / 2. Không thay đổi tại k = N / 2 cho bất kỳ df. Tương tự cho tội lỗi hoặc bất kỳ hỗn hợp. Căn giữa điểm tham chiếu pha cho thấy ít thay đổi hơn trong pha đo với thay đổi trong f0. ví dụ lỗi tần số không góp phần làm tăng sai số đo pha.
hotpaw2

1
Có, lỗi ước tính pha ít hơn ở trung tâm của cửa sổ có ý nghĩa nếu hình sin và bộ lọc Goertzel ở các tần số khác nhau. Trong trường hợp đó, ước tính pha nói ở cuối cửa sổ bị sai lệch bởi hằng số là tích của khoảng cách giữa tâm và cuối cửa sổ và sự khác biệt giữa tần số của bộ lọc hình sin và Goertzel. Trừ đi độ lệch này cho sai số kích thước tương tự như ước tính trung tâm, nhưng nó đòi hỏi phải biết tần số của hình sin.
Olli Niemitalo

4

Nếu tín hiệu của bạn không có nhiễu, bạn có thể xác định các điểm giao nhau bằng 0 ở cả hai và xác định tần số và pha tương đối.


3

ϕ

f(t)ωω

Vì thế:

  • "Nhanh" nghĩa là gì?
  • Làm thế nào chính xác để bạn cần ước tính?
  • ϕ
  • Mức độ nhiễu trên mỗi tín hiệu là gì?

f(t)=Asin(ωt+ϕ)f(t)=Asin(ωx+ϕ)


2



F(t)
T=π/ω
I(ϕ)=0TF(t)dt =0.5Acos(ϕ)T
ϕ
cos(ϕ)=I(t)/(0.5AT)



ϕ0..(2π)

Đối với tín hiệu rời rạc, thay đổi tích phân thành tổng và cẩn thận chọn T!


1

Bạn cũng có thể làm điều này (theo ký hiệu numpy):

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

trong đó tín hiệu là tín hiệu chuyển pha của bạn, cos và sin là tín hiệu tham chiếu và bạn tạo ra một xấp xỉ của một tích phân trong một thời gian nhất định thông qua tổng hợp hai sản phẩm.


0

Đây là một cải tiến về đề xuất của @Kevin McGee để sử dụng một DFT tần số duy nhất với chỉ số bin phân đoạn. Thuật toán của Kevin không mang lại kết quả tuyệt vời: trong khi ở một nửa thùng và toàn bộ thùng thì nó rất chính xác, cũng gần với các wholes và một nửa, nó cũng khá tốt, nhưng nếu không thì lỗi có thể ở mức 5%, có thể không chấp nhận được đối với hầu hết các nhiệm vụ .

NkN

Mã dưới đây là trong Swift, nhưng phải rõ ràng bằng trực giác:

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 đơn giản là một cách để tính toán DFT hiệu quả. Với các thư viện hiện đại, sức mạnh của hai hạn chế không còn nữa. Nếu bạn chỉ cần một hoặc hai giá trị bin, thì tốt hơn là tính toán chúng trực tiếp như bạn đã làm. Đối với một âm thuần đơn (thực hoặc phức), chỉ cần hai giá trị bin để tính chính xác tần số, pha và biên độ. Xem dsprelated.com/showarticle/1284.php . Toán học khá phức tạp, nhưng có các liên kết đến các bài báo trong đó các dẫn xuất được giải thích. Đại số tuyến tính là một điều kiện tiên quyết cho một sự hiểu biết thực sự.
Cedron Dawg
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.