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 φ ?
Tôi đã xem xét thuật toán Goertzel , nhưng nó dường như không đối phó với pha?
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 φ ?
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:
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.
Vấn đề có thể được coi là vấn đề bình phương nhỏ nhất (phi tuyến):
Đạo hàm rất đơn giản:
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.
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.
Đâ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ụ .
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))