มีอัลกอริทึมในการคำนวณเฟสสำหรับความถี่เดี่ยวหรือไม่?


17

หากคุณมีฟังก์ชั่นและการอ้างอิงคลื่นของคลื่นอะไรจะเป็นวิธีที่รวดเร็วในการคำนวณ ?f(t)=Asin(ωt+ϕ)sin(ωx)ϕ

ฉันดูอัลกอริธึมของGoertzelแต่ดูเหมือนจะไม่เกี่ยวข้องกับเฟสเลยใช่ไหม

คำตอบ:


5

ใช้ DFT ที่ความถี่เฉพาะ จากนั้นคำนวณแอมพลิจูดและเฟสจากชิ้นส่วนจริง / จินตนา มันให้ระยะอ้างอิงถึงจุดเริ่มต้นของเวลาการสุ่มตัวอย่าง

ใน 'ปกติ' FFT (หรือ DFT คำนวณสำหรับ N ฮาร์มอนิกทั้งหมด) โดยทั่วไปคุณคำนวณความถี่ด้วย f = k * (sample_rate) / N โดยที่ k เป็นจำนวนเต็ม แม้ว่ามันอาจดูเป็นสิ่งศักดิ์สิทธิ์ (โดยเฉพาะอย่างยิ่งกับสมาชิกของ Church of the Wholly Integer) แต่คุณสามารถใช้ค่าที่ไม่ใช่จำนวนเต็มของ k เมื่อทำ DFT เดี่ยว

ตัวอย่างเช่นสมมติว่าคุณได้สร้าง (หรือรับ) N = 256 คะแนนของคลื่นไซน์ที่ 27 Hz (สมมุติว่า sample_rate = 200) ความถี่ 'ปกติ' ของคุณสำหรับ 256 จุด FFT (หรือ N point DFT) จะสอดคล้องกับ: f = k * (sample_rate) / N = k * (200) / 256 โดยที่ k เป็นจำนวนเต็ม แต่ค่าที่ไม่ใช่จำนวนเต็ม 'k' ของ 34.56 จะสอดคล้องกับความถี่ 27 Hz. โดยใช้พารามิเตอร์ที่ระบุไว้ข้างต้น มันเหมือนกับการสร้าง 'ถังขยะ' DFT ที่มีศูนย์กลางอยู่ที่ความถี่ของความสนใจ (27 Hz) โค้ด 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 ที่สอดคล้องกับความถี่ที่น่าสนใจ


วิธีการนี้สามารถปรับปรุงได้โดยการปรับ N เพื่อให้ k ใกล้เคียงกับภาพรวมทั้งหมด ฉันโพสต์คำตอบแยกต่างหากที่แสดงความแม่นยำของอัลกอริทึมนี้
mojuba

10

ปัญหาสามารถกำหนดเป็นปัญหาน้อยที่สุด (ไม่เชิงเส้น):

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

ที่เป็นฟังก์ชันวัตถุประสงค์เพื่อลดส่วนที่เกี่ยวกับ\ϕF(ϕ)ϕ

อนุพันธ์นั้นง่ายมาก:

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

ดังกล่าวข้างต้นฟังก์ชันวัตถุประสงค์สามารถลดซ้ำโดยใช้วิธีการไล่โทนสีโคตร (การสั่งซื้อครั้งแรกประมาณ) วิธีนิวตัน , วิธีเกาส์นิวตันหรือวิธี Levenberg-Marquardt (ลำดับที่สองประมาณ -จะต้องมีการระบุไว้ในเหล่านี้)F(ϕ)

เห็นได้ชัดว่าฟังก์ชันวัตถุประสงค์ข้างต้นมีหลายค่าน้อยที่สุดเนื่องจากเป็นช่วงเวลาดังนั้นจึงมีการเพิ่มเงื่อนไขการลงโทษเพื่อแยกแยะความแตกต่างของขนาดเล็ก (ตัวอย่างเช่นการเพิ่มเข้ากับสมการโมเดล แต่ผมคิดว่าการเพิ่มประสิทธิภาพก็จะมาบรรจบกับน้อยที่ใกล้ที่สุดและคุณสามารถปรับปรุงผลลบN 2 π k , k Nϕ22πk,kN


ฉันไม่คิดว่าคุณจะต้องลงโทษเพราะไม่มีช่วงเวลา? คุณสามารถเอา minima อะไรก็ตามในสเปซเฟสที่มันมาบรรจบกันและทำ modulu , ไม่? 2π
Spacey

@ โมฮัมหมัดใช่ แต่เทคนิคการปรับให้เหมาะสมบางอย่างอาจใช้จุดเริ่มต้นหลายจุดซึ่งควรมารวมกันเป็นค่าเดียวกันหรือสมมติว่าฟังก์ชั่นนูนมีตัวย่อขนาดเล็กทั่วโลกเดียวซึ่งสามารถประมาณได้ดีกับกำลังสอง ประโยชน์อื่น ๆ คือการที่เราจบลงด้วยผลเหมือนกันสำหรับจุดเริ่มต้นใด ๆ{0} ϕ0
Libor

น่าสนใจ ฉันขอเชิญคุณที่จะถามคำถามที่เกี่ยวข้องนี้ได้หรือไม่ :-)
Spacey

@Mohammad ตกลงฉันมีส่วนร่วมเล็ก ๆ น้อย ๆ มี :)
Libor

ฟังก์ชั่น fi (w) ไปไหน? fi (w) ไม่คงที่ดังนั้นเมื่อคุณหาอนุพันธ์ของค่าไม่คงที่มันจะกลายเป็นศูนย์ได้อย่างไร?
SamFisher83

5

มีสูตรที่แตกต่างกันหลายอย่างของอัลกอริทึม Goertzel คนที่มี 2 รัฐตัวแปร (orthogonal หรือใกล้เคียง) หรือตัวแปรรัฐที่ซับซ้อนที่สุดเท่าที่จะเป็นไปได้เอาท์พุทมักจะถูกนำมาใช้เพื่อคำนวณ คนที่ให้ผลลัพธ์สเกลาร์เดียวอย่างเดียวมักจะไม่สามารถทำได้

คุณจะต้องทราบว่าหน้าต่าง Goertzel ของคุณเกี่ยวข้องกับแกนเวลาของคุณอย่างไร

หากสัญญาณของคุณไม่ใช่จำนวนเต็มเป็นระยะในหน้าต่าง Goertzel ของคุณเฟสจะประมาณรอบจุดอ้างอิงที่อยู่ตรงกลางของหน้าต่างอาจมีความแม่นยำมากขึ้นดังนั้นการอ้างอิงเฟสถึงจุดเริ่มต้นหรือจุดสิ้นสุด

FFT เต็มจะ overkill ถ้าคุณรู้ความถี่ของสัญญาณของคุณ บวก Goertzel สามารถปรับให้เป็นความถี่ที่ไม่ได้เป็นระยะในความยาว FFT ในขณะที่ FFT จะต้องมีการแก้ไขเพิ่มเติมหรือเป็นศูนย์รองสำหรับความถี่ที่ไม่ใช่ระยะในหน้าต่าง

Goertzel ที่ซับซ้อนเทียบเท่ากับ 1 bin ของ DFT ที่ใช้การเกิดซ้ำสำหรับเวกเตอร์พื้นฐานไซน์และไซน์หรือปัจจัย FFT twiddle


ไม่ใช่การประมาณเฟสใด ๆ ภายในหน้าต่างที่มีความแม่นยำเดียวกันเพราะคุณเพียงแค่เพิ่มเข้ากับการประมาณเฟสที่จุดเริ่มต้นของหน้าต่างเพื่อคำนวณการประมาณเฟสที่ตัวอย่างภายในหน้าต่าง (เป็นจุดเริ่มต้นของหน้าต่าง) k k = 0ωkkk=0
Olli Niemitalo

ไม่เพราะการเพิ่ม wk ส่งผลให้เกิดเฟสที่แตกต่างกันที่ส่วนท้ายของหน้าต่างมากกว่าตอนเริ่มต้นสำหรับไซน์ไซด์ที่ไม่ใช่จำนวนเต็มเป็นระยะในช่องรับแสง แต่ DFT 1-bin คำนวณเฟสแบบวงกลมเดียวที่จุดเดียวกัน ดังนั้นค่าทั้ง 3 จะต่างกัน แต่ระยะศูนย์กลางนั้นสัมพันธ์กับอัตราส่วนของฟังก์ชั่นคี่ / คู่เสมอไม่ว่า f0 จะเป็นอะไรก็ตาม
hotpaw2

พยายาม แต่ฉันไม่เข้าใจ
Olli Niemitalo

ใช้โคไซน์ (เฟสของศูนย์ที่ k = 0) ปรับความถี่เล็กน้อย (ด้วยจำนวนอตรรกยะเล็กน้อย แต่ไม่เปลี่ยนเฟสที่ k = 0) DFT รายงานว่าเฟสมีการเปลี่ยนแปลง! ลองทำเช่นเดียวกันกับโคไซน์ตรงกลางที่ k = N / 2 ไม่มีการเปลี่ยนแปลงที่ k = N / 2 สำหรับ df ใด ๆ เช่นเดียวกับบาปหรือส่วนผสมใด ๆ จุดศูนย์กลางการอ้างอิงเฟสแสดงการเปลี่ยนแปลงน้อยลงในเฟสที่วัดได้ด้วยการเปลี่ยนแปลงใน f0 เช่นข้อผิดพลาดความถี่ไม่ได้มีส่วนทำให้เกิดข้อผิดพลาดในการวัดเพิ่มขึ้น
hotpaw2

1
ใช่ข้อผิดพลาดในการประมาณเฟสน้อยกว่าที่กึ่งกลางของหน้าต่างทำให้รู้สึกว่าไซนัสและตัวกรอง Goertzel มีความถี่แตกต่างกัน ในกรณีดังกล่าวการประมาณระยะบอกว่าในตอนท้ายของหน้าต่างนั้นมีความเอนเอียงโดยค่าคงที่ซึ่งเป็นผลคูณของระยะทางระหว่างจุดกึ่งกลางและจุดสิ้นสุดของหน้าต่างและความแตกต่างระหว่างความถี่ตัวกรองไซนัสและ Goertzel การลบอคตินี้ให้ข้อผิดพลาดขนาดเดียวกันกับการประมาณกึ่งกลาง แต่ต้องรู้ความถี่ของไซนัส
Olli Niemitalo

4

หากสัญญาณของคุณปราศจากสัญญาณรบกวนคุณสามารถระบุการข้ามศูนย์ทั้งในและกำหนดความถี่และเฟสสัมพัทธ์


3

ขึ้นอยู่กับความหมายของคำว่า "เร็ว" ความแม่นยำที่คุณต้องการประมาณการของคุณไม่ว่าคุณต้องการหรือเฟสที่สัมพันธ์กับตัวอย่างของคุณϕ

วิธีหนึ่งที่จะทำเช่นนี้คือการใช้เวลาเพียงแค่ FFT ของและดูเพียงแค่ในถังที่ใกล้เคียงกับ\โอห์มf(t)ω อย่างไรก็ตามสิ่งนี้จะขึ้นอยู่กับที่อยู่ใกล้กับความถี่ศูนย์ช่องเก็บω

ดังนั้น:

  • คุณหมายถึงอะไรโดย "เร็ว"
  • คุณต้องการประมาณการที่แม่นยำแค่ไหน?
  • คุณต้องการ (เฟสสัมพันธ์กับการอ้างอิง) หรือเฟสที่เกี่ยวข้องกับการเริ่มต้นการสุ่มตัวอย่างหรือไม่? มันสำคัญไหมϕ
  • สัญญาณรบกวนแต่ละสัญญาณมีระดับเสียงเท่าใด?

PS: ฉันสมมติว่าคุณหมายถึงมากกว่าφ)f(t)=Asin(ωt+ϕ)f(t)=Asin(ωx+ϕ)


2

จุดเริ่มต้น:
1) ทวีคูณสัญญาณและการอ้างอิงคลื่นบาปของคุณ: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) ) 2) ค้นหาอินทิกรัลตามช่วงเวลา : 3) คุณสามารถคำนวณ :
T = π / ω ฉัน( φ ) = T 0 F ( T ) d T = 0.5 o s ( φ ) T φ o s ( φ ) = ฉัน( T ) / ( 0.5 A T )F(t)
T=π/ω
I(ϕ)=0TF(t)dt =0.5Acos(ϕ)T
ϕ
cos(ϕ)=I(t)/(0.5AT)

คิดอย่างไร:
จะวัดได้อย่างไร
วิธีการตรวจสอบในช่วงเวลา? (คิดเกี่ยวกับ "การอ้างอิงคลื่นคอส ")0 .. ( 2 เธ)ϕ0..(2π)

สำหรับสัญญาณไม่ต่อเนื่องเปลี่ยนอินทิกรัลเป็นผลรวมและเลือก T!


1

คุณสามารถทำเช่นนี้ (ในสัญกรณ์ numpy):

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

โดยที่สัญญาณคือสัญญาณที่เปลี่ยนเฟสของคุณ cos และ sin เป็นสัญญาณอ้างอิงและคุณสร้างการประมาณของอินทิกรัลในช่วงเวลาหนึ่งผ่านการสรุปผลรวมของผลิตภัณฑ์ทั้งสอง


0

นี่คือการปรับปรุงคำแนะนำของ @Kevin McGee เพื่อใช้ DFT ความถี่เดียวกับดัชนีถังเศษส่วน อัลกอริทึมของ Kevin ไม่ได้ผลลัพธ์ที่ยอดเยี่ยม: ในขณะที่ครึ่งถังขยะและถังขยะทั้งหมดนั้นแม่นยำมากใกล้กับ wholes และครึ่งหนึ่งก็ค่อนข้างดี แต่ข้อผิดพลาดอาจอยู่ใน 5% ซึ่งอาจไม่เป็นที่ยอมรับสำหรับงานส่วนใหญ่ .

ฉันแนะนำให้ปรับปรุงอัลกอริทึมของ Kevin โดยปรับนั่นคือความยาวของหน้าต่าง DFT เพื่อให้ใกล้เคียงกับภาพรวมมากที่สุด การทำงานนี้แตกต่างจาก FFT DFT ไม่ต้องการให้เป็นพลังของ 2NkN

รหัสด้านล่างเป็นแบบ 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))

FFT เป็นเพียงวิธีการคำนวณ DFT อย่างมีประสิทธิภาพ ด้วยห้องสมุดสมัยใหม่พลังแห่งการ จำกัด สองข้อไม่ได้อยู่ที่นั่นอีกต่อไป หากคุณต้องการเพียงหนึ่งหรือสองค่าถังขยะจะเป็นการดีกว่าที่จะคำนวณค่าเหล่านั้นโดยตรงเหมือนกับที่คุณทำ สำหรับเสียงบริสุทธิ์เดียว (จริงหรือซับซ้อน) ต้องใช้ค่า bin สองค่าเท่านั้นในการคำนวณความถี่เฟสและแอมพลิจูด ดูdsprelated.com/showarticle/1284.php คณิตศาสตร์ค่อนข้างซับซ้อน แต่มีลิงก์ไปยังบทความที่อธิบายถึงการสืบทอด พีชคณิตเชิงเส้นเป็นข้อกำหนดเบื้องต้นสำหรับความเข้าใจที่แท้จริง
Cedron Dawg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.