Se hai una funzione e riferimento sin wave quale sarebbe un algoritmo veloce da calcolare ?
Stavo guardando l' algoritmo di Goertzel , ma non sembra affrontare la fase?
Se hai una funzione e riferimento sin wave quale sarebbe un algoritmo veloce da calcolare ?
Stavo guardando l' algoritmo di Goertzel , ma non sembra affrontare la fase?
Risposte:
Utilizzare un DFT alla frequenza specifica. Quindi calcola l'ampiezza e la fase dalle parti real / imag. Ti dà la fase riferita all'inizio del tempo di campionamento.
In una FFT "normale" (o una DFT calcolata per tutte le armoniche N), in genere si calcola la frequenza con f = k * (frequenza_campione) / N, dove k è un numero intero. Sebbene possa sembrare sacrilego (specialmente ai membri della Chiesa del Numero intero), puoi effettivamente utilizzare valori non interi di k quando esegui un singolo DFT.
Ad esempio, supponiamo di aver generato (o ottenuto) N = 256 punti di un'onda sinusoidale di 27 Hz. (diciamo, sample_rate = 200). Le frequenze "normali" per un FFT a 256 punti (o N punto DFT) corrisponderebbero a: f = k * (sample_rate) / N = k * (200) / 256, dove k è un numero intero. Ma una "k" non intera di 34,56 corrisponderebbe a una frequenza di 27 Hz., Utilizzando i parametri sopra elencati. È come creare un 'bin' DFT esattamente centrato sulla frequenza di interesse (27 Hz.). Alcuni codici C ++ (compilatore DevC ++) potrebbero apparire come segue:
#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: spero che quanto sopra si traduca bene in StackOverflow - alcuni potrebbero andare in giro)
Il risultato di quanto sopra è una fase di -twopi / 4, come mostrato nei punti reali generati (e l'amplificatore viene raddoppiato per riflettere la frequenza pos / neg).
Alcune cose da notare - Uso il coseno per generare la forma d'onda di prova e interpretare i risultati - Devi stare attento a questo - la fase è riferita al tempo = 0, che è quando hai iniziato il campionamento (cioè: quando hai raccolto r [0] ) e il coseno è l'interpretazione corretta).
Il codice sopra riportato non è né elegante né efficiente (ad esempio: utilizzare una tabella di ricerca per i valori sin / cos, ecc.).
I tuoi risultati diventeranno più precisi quando usi N più grande e c'è un po 'di errore dovuto al fatto che la frequenza di campionamento e N sopra non sono multipli l'una dell'altra.
Naturalmente, se si desidera modificare la frequenza di campionamento, N o f, è necessario modificare il codice e il valore di k. Puoi inserire un bin DFT in qualsiasi punto della linea di frequenza continua: assicurati di utilizzare un valore di k che corrisponda alla frequenza di interesse.
Il problema può essere formulato come problema dei minimi quadrati (non lineari):
La derivata è molto semplice:
Ovviamente, la funzione obiettivo sopra ha più minimi a causa della periodicità, quindi un certo termine di penalità può essere aggiunto per discriminare altri minimi (ad esempio, aggiungendo all'equazione del modello). Ma penso che l'ottimizzazione sarà solo convergere i minimi più vicino e si può aggiornare il risultato sottraendo . 2 π k , k ∈ N
Esistono diverse formulazioni dell'algoritmo di Goertzel. Quelle che forniscono 2 variabili di stato (ortogonali o vicine), o una variabile di stato complessa, come possibili uscite spesso possono essere utilizzate per calcolare o stimare la fase con riferimento a un punto della finestra di Goertzel, come il centro. Quelli che forniscono un singolo output scalare da soli di solito non possono.
Dovrai anche sapere dove si trova la finestra di Goertzel in relazione al tuo asse temporale.
Se il segnale non è esattamente periodico intero nella finestra di Goertzel, la stima della fase attorno a un punto di riferimento al centro della finestra potrebbe essere più accurata della fase di riferimento all'inizio o alla fine.
Un FFT completo è eccessivo se si conosce la frequenza del segnale. Inoltre un Goertzel può essere sintonizzato su una frequenza non periodica nella lunghezza FFT, mentre un FFT avrà bisogno di interpolazione aggiuntiva o riempimento di zero per frequenze non periodiche nella finestra.
Un Goertzel complesso equivale a 1 bin di un DFT che utilizza una ricorrenza per i vettori di coseno e seno base o i fattori di twiddle FFT.
Dipende da quale sia la tua definizione di "veloce", quanto preciso vuoi la tua stima, se vuoi o la fase relativa ai tuoi campionamenti, e quanto rumore c'è sulla tua funzione e sull'onda sinusoidale di riferimento.
Un modo per farlo è semplicemente prendere la FFT di e guardare il cestino più vicino a . ω Tuttavia, ciò dipenderà dal fatto che sia vicino alla frequenza centrale del contenitore.
Così:
PS: che intendevi , piuttosto che .
Punto iniziale:
1) moltiplica il segnale e l'onda sin di riferimento: = A⋅sin (ωt + ϕ) ⋅sin (ωt) = 0.5⋅A⋅ (cos (ϕ) - cos (2⋅ωt + ϕ) )
2) trova integrale sul periodo :
3) puoi calcolare :
Pensa a:
come misurare A?
come determinare nell'intervallo ? (pensa a "riferimento cos wave")
Per un segnale discreto, cambiare l'integrale da sommare e scegliere attentamente T!
Questo è un miglioramento rispetto al suggerimento di @Kevin McGee di utilizzare un DFT a singola frequenza con un indice bin binario frazionario. L'algoritmo di Kevin non produce grandi risultati: mentre a metà bin e interi bin è molto preciso, anche vicino agli interi e alle metà è anche abbastanza buono, ma altrimenti l'errore può essere all'interno del 5%, il che probabilmente non è accettabile per la maggior parte delle attività .
Suggerisco di migliorare l'algoritmo di Kevin regolando , cioè la lunghezza della finestra DFT in modo che si avvicini il più possibile all'intero. Questo funziona poiché, diversamente da FFT, DFT non richiede che abbia una potenza di 2.
Il codice seguente è in Swift, ma dovrebbe essere intuitivamente chiaro:
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))