¿Existe un algoritmo para calcular la fase de una sola frecuencia?

17

Si tiene una función f(t)=Asin(ωt+ϕ) , y una onda referencia sin ( ω x ),sin(ωx) ¿cuál sería un algoritmo rápido para calcular ϕ ?

Estaba mirando el algoritmo de Goertzel , pero no parece tratar con la fase.

SamFisher83
fuente

Respuestas:

5

Use un DFT a la frecuencia específica. Luego calcule la amplitud y la fase de las partes real / imag. Le proporciona la fase referenciada al inicio del tiempo de muestreo.

En una FFT 'normal' (o una DFT calculada para todos los N armónicos), normalmente se calcula la frecuencia con f = k * (sample_rate) / N, donde k es un número entero. Aunque pueda parecer sacrílego (especialmente para los miembros de la Iglesia del Entero Entero), en realidad puede usar valores no enteros de k cuando hace un solo DFT.

Por ejemplo, suponga que ha generado (u obtenido) N = 256 puntos de una onda sinusoidal de 27 Hz. (digamos, sample_rate = 200). Sus frecuencias 'normales' para una FFT de 256 puntos (o DFT de punto N) corresponderían a: f = k * (frecuencia de muestreo) / N = k * (200) / 256, donde k es un número entero. Pero una 'k' no entera de 34.56 correspondería a una frecuencia de 27 Hz., Utilizando los parámetros enumerados anteriormente. Es como crear un 'contenedor' DFT que esté exactamente centrado en la frecuencia de interés (27 Hz.). Algunos códigos C ++ (compilador DevC ++) pueden tener el siguiente aspecto:

#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

(PD: Espero que lo anterior se traduzca bien en stackoverflow, algo de lo que podría envolver)

El resultado de lo anterior es una fase de -twopi / 4, como se muestra en los puntos reales generados (y el amplificador se duplica para reflejar la frecuencia pos / neg).

Algunas cosas a tener en cuenta: utilizo el coseno para generar la forma de onda de prueba e interpretar los resultados, debe tener cuidado con eso: la fase se refiere al tiempo = 0, que es cuando comenzó a muestrear (es decir, cuando recolectó r [0] ), y el coseno es la interpretación correcta).

El código anterior no es elegante ni eficiente (por ejemplo: use tablas de búsqueda para los valores sin / cos, etc.).

Sus resultados serán más precisos a medida que use N más grande, y hay un pequeño error debido al hecho de que la frecuencia de muestreo y N anteriores no son múltiplos entre sí.

Por supuesto, si desea cambiar su frecuencia de muestreo, N o f, tendría que cambiar el código y el valor de k. Puede colocar un contenedor DFT en cualquier lugar de la línea de frecuencia continua, solo asegúrese de estar usando un valor de k que corresponda a la frecuencia de interés.

Kevin McGee
fuente
Este enfoque puede mejorarse ajustando N para acercar k a un todo. Publiqué una respuesta por separado que mejora la precisión de este algoritmo.
mojuba
10

El problema se puede formular como problema de mínimos cuadrados (no lineal):

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

F(ϕ)ϕ

La derivada es muy simple:

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

F(ϕ)

Obviamente, la función objetivo anterior tiene mínimos mínimos debido a la periodicidad, por lo tanto, se puede agregar algún término de penalización para discriminar otros mínimos (por ejemplo, agregar a la ecuación del modelo). Pero creo que la optimización solo convergerá a los mínimos más cercana y se puede actualizar el resultado de restar . 2 π k , k Nϕ22πk,kN

Libor
fuente
No creo que debas penalizar por la periodicidad, ¿no? Puedes tomar cualquier mínimo en el espacio de fase al que converja y hacer un modulu , ¿no? 2π
Spacey
@Mohammad Sí, pero algunas técnicas de optimización pueden usar múltiples puntos de partida que deberían converger al mismo valor o asumir una función convexa con un minimizador global único que se puede aproximar bien con un cuadrático. El otro beneficio es que terminamos con el mismo resultado para cualquier punto de partida . ϕ0
Libor
Interesante. ¿Puedo invitarle a que también tome una decisión sobre esta pregunta relacionada ? :-)
Spacey
@Mohammad OK, he contribuido un poco allí :)
Libor
¿A dónde va la función fi (w)? fi (w) no es una constante, así que cuando tomas una derivada de una no constante, ¿cómo se convierte en cero?
SamFisher83
5

Hay varias formulaciones diferentes del algoritmo de Goertzel. Las que proporcionan 2 variables de estado (ortogonales o cercanas a), o una variable de estado compleja, como posibles salidas, a menudo se pueden usar para calcular o estimar la fase con referencia a algún punto de la ventana de Goertzel, como el centro. Los que proporcionan una sola salida escalar por lo general no pueden.

También necesitará saber dónde está su ventana de Goertzel en relación con su eje de tiempo.

Si su señal no es exactamente un número entero periódico en su ventana de Goertzel, la estimación de fase alrededor de un punto de referencia en el medio de la ventana puede ser más precisa que hacer referencia a la fase al principio o al final.

Una FFT completa es exagerada si conoce la frecuencia de su señal. Además, un Goertzel puede sintonizarse a una frecuencia no periódica en la longitud de la FFT, mientras que una FFT necesitará interpolación adicional o relleno de cero para frecuencias no periódicas en la ventana.

Un Goertzel complejo es equivalente a 1 contenedor de un DFT que utiliza una recurrencia para los vectores de coseno y seno seno o factores twiddle FFT.

hotpaw2
fuente
¿No es la estimación de fase en cualquier lugar dentro de la ventana exactamente de la misma precisión, porque simplemente agregaría a la estimación de fase al comienzo de la ventana para calcular la estimación de fase en la muestra dentro de la ventana ( siendo el comienzo de la ventana)? k k = 0ωkkk=0
Olli Niemitalo
No, porque agregar wk da como resultado una fase diferente al final de la ventana que al principio para una sinusoide de apertura periódica no entera. Pero un DFT de 1 contenedor calcula una sola fase circular en ese mismo punto. Por lo tanto, los 3 valores serán todos diferentes. Pero la fase central siempre está relacionada con la relación de función impar / par, sin importar qué f0.
hotpaw2
Intentando, pero no entiendo eso.
Olli Niemitalo
Use un coseno (fase de cero en k = 0), modifique la frecuencia ligeramente (por un pequeño número irracional, pero sin cambiar la fase en k = 0). ¡Un DFT informa que la fase ha cambiado! Pruebe lo mismo con un coseno exactamente centrado en k = N / 2. Ningún cambio en k = N / 2 para cualquier df. Lo mismo para el pecado o cualquier mezcla. Centrar el punto de referencia de fase muestra menos cambios en la fase medida con cambios en f0. Por ejemplo, el error de frecuencia no contribuye a aumentar los errores de medición de fase.
hotpaw2
1
Sí, el error de estimación de fase es menor en el centro de la ventana tiene sentido si la sinusoide y el filtro Goertzel están en diferentes frecuencias. En ese caso, la estimación de fase al final de la ventana está sesgada por una constante que es el producto de la distancia entre el centro y el final de la ventana y la diferencia entre las frecuencias de filtro sinusoide y Goertzel. Restar este sesgo da el mismo error de tamaño que para la estimación central, pero requiere conocer la frecuencia de la sinusoide.
Olli Niemitalo el
4

Si sus señales no tienen ruido, puede identificar cruces por cero en ambos y determinar la frecuencia y la fase relativa.

Juancho
fuente
3

Eso depende de cuál sea su definición de "rápido", qué tan precisa desea su estimación, si desea o la fase relativa a sus muestreos, y cuánto ruido hay en su función y onda sinusoidal de referencia.ϕ

Una forma de hacerlo es tomar la FFT de y mirar el contenedor más cercano a . ωf(t)ω Sin embargo, esto dependerá de que esté cerca de la frecuencia central del contenedor.ω

Entonces:

  • ¿Qué quieres decir con "rápido"?
  • ¿Qué tan precisa necesita la estimación?
  • ¿Desea (fase relativa a la referencia) o fase relativa al inicio del muestreo? ¿Importa?ϕ
  • ¿Cuál es el nivel de ruido en cada señal?

PD: Supongo que quisiste decir , en lugar de .f ( t ) = A sin ( ω x + ϕ )f(t)=Asin(ωt+ϕ)f(t)=Asin(ωx+ϕ)

Peter K.
fuente
2

Punto de inicio:
1) multiplique su señal y la onda sin de referencia: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) ) 2) encuentre integral en el período : 3) puede calcular :
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)

Piensa en:
¿cómo medir A?
¿Cómo determinar en intervalo? (piense en " onda cos de referencia ")0 .. ( 2 π )ϕ0..(2π)

Para una señal discreta, cambie la integral a suma y elija cuidadosamente T!

SergV
fuente
1

También podría hacer esto (en notación numpy):

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

donde la señal es su señal de fase desplazada, cos y sin son las señales de referencia, y usted genera una aproximación de una integral durante un cierto tiempo mediante la suma de los dos productos.

M529
fuente
0

Esta es una mejora en la sugerencia de @Kevin McGee de usar un DFT de frecuencia única con un índice de bin fraccionario. El algoritmo de Kevin no arroja grandes resultados: mientras que en medias bandejas y bandejas enteras es muy preciso, también cerca de las mitades y mitades también es bastante bueno, pero de lo contrario el error puede estar dentro del 5%, lo que probablemente no sea aceptable para la mayoría de las tareas .

Sugiero mejorar el algoritmo de Kevin ajustando , es decir, la longitud de la ventana DFT para que se acerque lo más posible a un todo. Esto funciona ya que a diferencia de FFT, DFT no requiere que sea ​​una potencia de 2.NkN

El siguiente código está en Swift, pero debe ser intuitivamente claro:

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))
mojuba
fuente
El FFT es simplemente una forma de calcular un DFT de manera eficiente. Con las bibliotecas modernas, el poder de dos restricciones ya no existe. Si solo necesita uno o dos valores bin, es mejor calcularlos directamente como lo hizo. Para un solo tono puro (real o complejo), solo se necesitan dos valores bin para calcular la frecuencia, fase y amplitud exactamente. Ver dsprelated.com/showarticle/1284.php . La matemática es bastante sofisticada, pero hay enlaces a los artículos donde se explican las derivaciones. El álgebra lineal es un requisito previo para una verdadera comprensión.
Cedron Dawg