Determinazione della frequenza e del periodo di un'onda


11

Sto raccogliendo i dati di temperatura da un frigorifero. I dati sembrano un'onda. Vorrei determinare il periodo e la frequenza dell'onda (in modo da poter misurare se le modifiche al frigorifero hanno qualche effetto).

Sto usando R e penso di dover usare una FFT sui dati, ma non sono sicuro di dove andare da lì. Sono molto nuovo nell'analisi del segnale e di R, quindi qualsiasi aiuto sarebbe molto apprezzato!

Ecco l'onda che sto producendo:

La mia onda

Ecco il mio codice R finora:

require(graphics)
library(DBI)
library(RSQLite)

drv <- dbDriver("SQLite")
conn <- dbConnect(drv, dbname = "s.sqlite3")

query <- function(con, query) {
  rs <- dbSendQuery(con, query)
  data <- fetch(rs, n = -1)
  dbClearResult(rs)
  data
}

box <- query(conn, "
SELECT id,
       humidity / 10.0 as humidity,
       temp / 10.0 as temp,
       ambient_temp / 10.0 as ambient_temp,
       ambient_humidity / 10.0 as ambient_humidity,
       created_at
FROM measurements ORDER BY id DESC LIMIT 3600
")

box$x <- as.POSIXct(box$created_at, tz = "UTC")

box$x_n <- box$temp - mean(box$temp)
png(filename = "normalized.png", height = 750, width = 1000, bg = "white")
plot(box$x, box$x_n, type="l")

# Pad the de-meaned signal so the length is 10 * 3600
N_fft  <- 3600 * 10
padded <- c(box$x_n, seq(0, 0, length= (N_fft - length(box$x_n))))
X_f    <- fft(padded)
PSD    <- 10 * log10(abs(X_f) ** 2)

png(filename = "PSD.png", height = 750, width = 1000, bg = "white")
plot(PSD, type="line")

zoom <- PSD[1:300]

png(filename = "zoom.png", height = 750, width = 1000, bg = "white")
plot(zoom, type="l")

# Find the index with the highest point on the left half
index <- which(PSD == max(PSD[1:length(PSD) / 2]))

# Mark it in green on the zoomed in graph
abline(v = index, col="green")

f_s     <- 0.5 # sample rate in Hz
wave_hz <- index * (f_s / N_fft)
print(1 / (wave_hz * 60))

Ho pubblicato il codice R insieme al database SQLite qui .

Ecco un grafico del grafico normalizzato (con la media rimossa):

grafico normalizzato

Fin qui tutto bene. Ecco il diagramma della densità spettrale:

densità spettrale

Quindi ingrandiamo il lato sinistro del grafico e contrassegniamo l'indice più alto (che è 70) con una linea verde:

ingrandire la trama spettrale

Infine calcoliamo la frequenza dell'onda. Questa ondata è molto lenta, quindi la convertiamo in minuti per ciclo e stampiamo quel valore che è 17,14286.

Ecco i miei dati in formato delimitato da tabulazioni se qualcun altro vuole provare.

Grazie per l'aiuto! Questo problema è stato difficile (per me) ma mi sono divertito moltissimo!


Aaron, penso che la cosa migliore qui sia che tu metta un link al tuo file di dati (come un testo o qualcosa del genere) su un dropbox, in modo che io possa scaricarlo e darti la risposta. Altrimenti ci sarà molto da fare avanti e indietro. Non riesco a distinguere i numeri all'estremità sinistra. :-) (Fornisci anche una frequenza di campionamento, ovvero la frequenza con cui stai rilevando la temperatura).
Spacey,

Mi dispiace. I dati contengono la temperatura in gradi C, ho convertito in gradi F per il grafico. Tuttavia, sono i dati corretti (è la colonna "temp").
Aaron Patterson,

Il problema con la misurazione della frequenza in questo modo è che se si ottiene una notevole variabilità da un ciclo all'altro, sarà molto più difficile determinare la frequenza media - i picchi si spalanceranno insieme - mentre il semplice conteggio del tempo tra le escursioni ti permetterà di mediare bene le cose (e calcola anche dev dev standard, ecc.). L'uso dell'approccio FFT sarebbe più richiesto se ci fosse molto rumore, ma questo non sembra essere il caso qui.
Daniel R Hicks,

+1 per pubblicazione, codice, dati, grafici e un link a github.
nibot,

@DanielRHicks In questo caso particolare, non credo sia importante, ma sì, la FFT ti darà la media di tutti loro, mentre se facessimo qualcosa come un passaggio per lo zero, misureremmo la durata di ogni ciclo (frequenza), e quindi possiamo determinare se vogliamo prendere media, mediana, modalità, ecc.
Spacey,

Risposte:


7

Progetto interessante che stai portando avanti lì! :-)

Da un POV di analisi del segnale, questa è in realtà una semplice domanda - e sì, hai ragione a utilizzare la FFT per questo problema di stima della frequenza.

real2+imag2

Quindi, molto semplicemente, trova il massimo di dove si trova il tuo PSD. L'ascissa di quel massimo corrisponderà alla tua frequenza.

Caveat Emptor, ti sto dando una visione generale e sospetto che il risultato della FFT in R sarà una frequenza normalizzata, nel qual caso dovresti conoscere la frequenza di campionamento, (che fai), per riconvertirla in Hz. Ci sono molti altri dettagli importanti che sto tralasciando, come la risoluzione della frequenza, la dimensione della FFT e il fatto che probabilmente vorrai de-significare prima il tuo segnale, ma sarà bello vedere prima un grafico.

MODIFICARE:

Lasciaci prendere in considerazione il tuo segnale. Dopo che lo intendo, sembra così:

inserisci qui la descrizione dell'immagine

x[n]

Nfft=103600=36000.

fs=0.5Hz

x[n]X(f)10log10(|X(f)|2)

inserisci qui la descrizione dell'immagine

Puoi vedere come è simmetrico. Se ignori l'ultima metà e guardi solo la prima metà e ingrandisci te stesso, puoi vedere questo:

inserisci qui la descrizione dell'immagine

FsNfft=1.3889e005Hz01.3889e005=0Hz11.3889e005=1.3889e005Hz701.3889e005=9.7222e004Hz

1(9.7222e004)60=17.14


@AaronPatterson Ho modificato il post, per favore vedi. Inoltre, puoi aggiungere le tue foto direttamente al tuo post originale. :-). Aggiungi un'immagine del risultato PSD che ottieni.
Spacey,

1
Non esattamente corretto se la frequenza risulta essere tra i bin dei risultati FFT.
hotpaw2

@ hotpaw2 Questo è il motivo per cui ho avvertito OP che sto dando una visione generale e perché ho bisogno di vedere la trama. Tuttavia, ho modificato per aggiungere ulteriori avvertenze.
Spacey,

1
@AaronPatterson Nessun problema, felice di aiutarti. Per quanto riguarda i libri, dai un'occhiata a "Understanding DSP" di Richard Lyons - questo è un libro veloce per iniziare.
Spacey,

1
1.3x105

4

Per una forma d'onda così regolare e stazionaria, il conteggio dei punti di campionamento tra incroci in corso positivi di un valore di soglia medio fornirà una stima del periodo. Guarda diversi periodi di superamento della soglia per ottenere una stima più media o rilevare qualsiasi tendenza.


3

Non è necessario fare nulla di complicato: basta misurare la durata tra i picchi della forma d'onda. Questo è il periodo. La frequenza è solo 1 divisa per il periodo.

Con circa 8 cicli nell'arco di 2 ore, la frequenza è di 4 cicli all'ora o circa 1 mHz.


3
Come posso farlo a livello di codice?
Aaron Patterson il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.