단일 주파수의 위상을 계산하는 알고리즘이 있습니까?


17

함수 이고 sin wave 참조 를 계산하는 빠른 알고리즘은 무엇 입니까?sin ( ω x ) ϕf(t)=Asin(ωt+ϕ)sin(ωx)ϕ

Goertzel 알고리즘 을보고 있었지만 단계를 다루지 않는 것 같습니다.

답변:


5

특정 주파수에서 DFT를 사용하십시오. 그런 다음 실수 / 이마 그 부품에서 진폭과 위상을 계산합니다. 샘플링 시간의 시작과 관련된 위상을 제공합니다.

'정상'FFT (또는 모든 N 고조파에 대해 계산 된 DFT)에서 일반적으로 f = k * (sample_rate) / N으로 주파수를 계산합니다. 여기서 k는 정수입니다. 희생적인 것처럼 보일 수 있지만 (특히 홀리 정수 교회 회원들에게) 단일 DFT를 수행 할 때 정수가 아닌 k 값을 실제로 사용할 수 있습니다.

예를 들어, 27Hz의 사인파의 N = 256 점을 생성 (또는 획득)했다고 가정합니다. (sample_rate = 200이라고합시다). 256 포인트 FFT (또는 N 포인트 DFT)에 대한 '정상적인'주파수는 f = k * (sample_rate) / N = k * (200) / 256에 해당합니다. 여기서 k는 정수입니다. 그러나 34.56의 정수가 아닌 'k'는 위에 나열된 매개 변수를 사용하여 27Hz의 주파수에 해당합니다. 관심 주파수 (27Hz)의 중심에 정확하게있는 DFT 'bin'을 만드는 것과 같습니다. 일부 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 : 위의 내용이 스택 오버 플로우로 잘 변환되기를 바랍니다. 일부는 래핑 될 수 있습니다)

위의 결과는 생성 된 실제 포인트와 같이 -twopi / 4의 위상입니다 (그리고 amp는 pos / neg 주파수를 반영하기 위해 두 배가됩니다).

몇 가지 알아 두어야 할 사항 – 테스트 파형을 생성하고 결과를 해석하기 위해 코사인을 사용합니다.주의해야 할 점 – 위상은 샘플링을 시작할 때인 시간 = 0을 기준으로합니다 (예 : r [0]을 수집 한 시점) ), 코사인은 올바른 해석입니다).

위 코드는 우아하지도 효율적이지 않습니다 (예 : sin / cos 값 등을 위해 룩업 테이블 사용).

더 큰 N을 사용할수록 결과가 더 정확 해지며, 샘플 속도와 N이 서로의 배수가 아니기 때문에 약간의 오류가 있습니다.

물론 샘플링 속도 N 또는 f를 변경하려면 코드와 k 값을 변경해야합니다. 연속 주파수 라인의 어느 곳에서나 DFT 출력 함을 꺼낼 수 있습니다. 관심 주파수에 해당하는 k 값을 사용하고 있는지 확인하십시오.


k를 전체에 더 가깝게 만들기 위해 N을 조정하면이 방법을 개선 할 수 있습니다. 이 알고리즘의 정확성을 떨어 뜨리는 별도의 답변을 게시했습니다.
mojuba '11. 15. 19.

10

문제는 (비선형) 최소 제곱 문제로 공식화 될 수 있습니다.

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

여기서 에 대해 최소화하는 목적 함수이다 .F(ϕ)ϕ

파생 상품은 매우 간단합니다.

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

그라디언트 하강 법 (1 차 근사), 뉴턴 법 , 가우스-뉴턴 법 또는 Levenberg-Marquardt 법을 사용하여 위의 목적 함수를 반복적으로 최소화 할 수 있습니다 (2 차 근사 는 여기에 제공되어야 함).F(ϕ)

분명히, 위의 목적 함수는 주기성으로 인해 여러 개의 최소값을 가지므로 다른 최소값을 식별하기 위해 일부 페널티 항을 추가 할 수 있습니다 (예 : 모델 방정식에 추가 ). 그러나 최적화가 가장 가까운 최소 점으로 수렴하고 빼는 결과를 업데이트 할 수 있다고 생각합니다 . 2 π k , k Nϕ22πk,kN


나는 당신이 주기성 때문에 벌칙을 낼 필요가 없다고 생각합니까? 위상 공간에서 수렴하고 모듈러스 수행하는 최소값을 취할 수 있습니다 . 2π
Spacey

@Mohammad 예. 그러나 일부 최적화 기법은 여러 개의 시작점을 사용하여 동일한 값으로 수렴하거나 단일 글로벌 최소화기로 2 차로 근사 할 수있는 볼록 함수를 가정 할 수 있습니다. 다른 장점은 시작점 대해 동일한 결과로 끝나는 것입니다 . ϕ0
Libor

흥미 롭군 이 관련 질문에 균열을 가져 오도록 권유 할 수 있습니까? :-)
Spacey

@Mohammad 좋아, 나는 약간의 기여를했다 :)
Libor

fi (w) 함수는 어디로 갑니까? fi (w)는 상수가 아니므로 상수가 아닌 도함수를 취하면 어떻게 0이됩니까?
SamFisher83

5

Goertzel 알고리즘에는 몇 가지 다른 공식이 있습니다. 2 개의 상태 변수 (직교 또는 가까운) 또는 복잡한 상태 변수를 가능한 출력으로 제공하는 것은 종종 중간과 같은 Goertzel 창의 특정 지점을 참조하여 위상을 계산하거나 추정하는 데 사용될 수 있습니다. 단일 스칼라 출력 만 제공하는 것은 보통 불가능합니다.

또한 Goertzel 창이 시간 축과 관련하여 어디에 있는지 알아야합니다.

신호가 Goertzel 윈도우에서 정확히 정수주기가 아닌 경우, 윈도우 중간의 기준점 주변의 위상 추정치가 위상을 시작 또는 끝을 참조하는 것보다 정확할 수 있습니다.

신호의 주파수를 알고 있으면 전체 FFT가 과도합니다. 또한 Goertzel은 FFT 길이에서 주기적이 아닌 주파수로 조정할 수 있지만, FFT는 비주기적인 주파수에 대해서는 추가 보간 또는 제로 패딩이 필요합니다.

복잡한 Goertzel은 코사인 및 사인 기반 벡터 또는 FFT 트위들 인자에 대한 반복을 사용하는 DFT의 1 bin에 해당합니다.


윈도우 내 샘플 에서 위상 추정치를 계산하기 위해 윈도우 시작 부분의 위상 추정치에 를 추가하기 때문에 정확히 동일한 정확도의 위상 추정치가 아닙니다. ( 창의 시작)? k k = 0ωkkk=0
Olli Niemitalo

아니요, wk를 추가하면 창 끝에서 정수가 아닌 기간 동안 정현파에 대한 시작과 다른 단계가 발생하기 때문입니다. 그러나 1-bin DFT는 같은 지점에서 단일 원형 위상을 계산합니다. 따라서 3 개의 값이 모두 다릅니다. 그러나 중심 위상은 f0에 관계없이 항상 홀수 / 짝수 함수의 비율과 관련이 있습니다.
hotpaw2

노력하고 있지만 이해가되지 않습니다.
Olli Niemitalo

코사인 (k = 0에서 0의 위상)을 사용하고, 주파수를 약간 (비이성적 인 수만큼 조정하지만 k = 0에서 위상을 변경하지 않음) 조정하십시오. DFT는 단계가 변경되었다고보고합니다! k = N / 2에 정확히 중심을 둔 코사인으로 동일하게 시도하십시오. df에 대해 k = N / 2에서 변화가 없습니다. 죄 또는 그 혼합에 대해서도 동일합니다. 위상 기준점을 중심으로하면 f0의 변화와 함께 측정 된 위상의 변화가 적습니다. 예를 들어 주파수 오류는 위상 측정 오류 증가에 기여하지 않습니다.
hotpaw2

1
예. 정현파와 Goertzel 필터의 주파수가 서로 다른 경우에는 창 중앙에서 위상 추정 오차가 작을 수 있습니다. 이 경우, 창 끝에서의 위상 추정값은 창 중심과 끝 사이의 거리와 정현파와 Goertzel 필터 주파수의 차이의 곱인 상수에 의해 바이어스됩니다. 이 바이어스를 빼면 중심 추정값과 동일한 크기 오류가 발생하지만 정현파의 주파수를 알아야합니다.
Olli Niemitalo

4

신호에 노이즈가없는 경우 두 교차 모두에서 제로 크로싱을 식별하고 주파수와 상대 위상을 결정할 수 있습니다.


3

이는 "빠른"의 정의가 무엇인지, 를 원하는지 또는 샘플링과 관련된 위상 을 원하는지 , 함수 및 기준 사인파에 얼마나 많은 노이즈가 있는지에 대한 추정치의 정확성에 달려 있습니다 .ϕ

이를 수행하는 한 가지 방법은 의 FFT를 취하고 가장 가까운 bin을 보는 것 입니다. ωf(t)ω 그러나 이것은 가 빈 중심 주파수에 가깝다 는 것에 달려 있습니다.ω

그래서:

  • "빠른"은 무슨 뜻입니까?
  • 견적이 얼마나 정확합니까?
  • 당신이 하시겠습니까 샘플링의 시작 (참고로 위상 기준) 또는 위상 상대? 상관이 있나?ϕ
  • 각 신호의 노이즈 레벨은 무엇입니까?

추신 : 나는 당신 이 대신 을 의미한다고 가정합니다 .f(t)=Asin(ωt+ϕ)f(t)=Asin(ωx+ϕ)


2

시작점 :
1) 신호와 기준 사인파를 곱하십시오 : = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ)-cos (2⋅ωt + ϕ) ) 2) 기간에 통합 찾을 : 3) 수 계산 :
F(t)
T=π/ω
I(ϕ)=0TF(t)dt =0.5Acos(ϕ)T
ϕ
cos(ϕ)=I(t)/(0.5AT)

생각해보십시오 :
A를 측정하는 방법? 간격 에서
를 결정하는 방법은 무엇입니까? ( 「기준 코스 웨이브」에 대해 생각 )ϕ0..(2π)

불연속 신호의 경우 적분을 합하여 T를 신중하게 선택하십시오!


1

당신은 또한 이것을 할 수 있습니다 (numpy 표기법으로) :

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

여기서 신호는 위상 편이 신호이고 cos 및 sin은 기준 신호이며 두 제품에 대한 합산을 통해 특정 시간 동안 적분의 근사값을 생성합니다.


0

이것은 @Kevin McGee의 분수 빈 지수와 함께 단일 주파수 DFT를 사용하도록 개선 된 것입니다. Kevin의 알고리즘은 큰 결과를 얻지 못합니다. 반 빈과 전체 빈은 매우 정확하지만 전체와 가까우며 반은 꽤 좋지만 그렇지 않으면 오류가 5 % 이내에있을 수 있습니다. .

가 가능한 한 전체에 가까워 지도록 , 즉 DFT 창의 길이를 조정하여 Kevin의 알고리즘을 개선하는 것이 좋습니다 . FFT와 달리 DFT는 을 2의 거듭 제곱으로 요구하지 않기 때문에 작동합니다 .NkN

아래 코드는 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를 효율적으로 계산하는 방법입니다. 현대 도서관에서는 두 가지 제한의 힘이 더 이상 존재하지 않습니다. 하나 또는 두 개의 구간 값만 필요한 경우 직접 수행 한 것과 같이 직접 계산하는 것이 좋습니다. 단일 순수 톤 (실제 또는 복합)의 경우 주파수, 위상 및 진폭을 정확하게 계산하기 위해 두 개의 빈 값만 필요합니다. dsprelated.com/showarticle/1284.php를 참조하십시오 . 수학은 매우 정교하지만 파생이 설명 된 기사에 대한 링크가 있습니다. 선형 대수는 진정한 이해를위한 전제 조건입니다.
Cedron Dawg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.