Scelta del filtro corretto per i dati dell'accelerometro


28

Sono abbastanza nuovo in DSP e ho fatto alcune ricerche su possibili filtri per rendere più fluidi i dati dell'accelerometro in Python. Un esempio del tipo di dati che si verificano potrebbero essere visualizzati nella seguente immagine:

Dati dell'accelerometro

In sostanza, sto cercando consigli su come lisciare questi dati per convertirli in velocità e spostamento. Capisco che gli accelerometri dai telefoni cellulari sono estremamente rumorosi.

Non credo di poter usare un filtro Kalman al momento perché non riesco a trovare il dispositivo per fare riferimento al rumore prodotto dai dati (ho letto che è essenziale posizionare il dispositivo piatto e trovare la quantità di rumore da quelle letture?)

FFT ha prodotto alcuni risultati interessanti. Uno dei miei tentativi è stato di FFT il segnale di accelerazione, quindi renderizzare le basse frequenze per avere un valore FFT assoluto di 0. Quindi ho usato l'aritmetica omega e la FFT inversa per ottenere un grafico per la velocità. I risultati sono stati i seguenti:

Segnale filtrato

È un buon modo di affrontare le cose? Sto cercando di rimuovere la natura generale rumorosa del segnale, ma è necessario identificare picchi evidenti come ad esempio circa 80 secondi.

Mi sono anche stancato di utilizzare un filtro passa-basso sui dati dell'accelerometro originale, che ha fatto un ottimo lavoro nel livellarlo, ma non sono sicuro di dove andare da qui. Qualsiasi consiglio su dove andare da qui sarebbe davvero utile!

EDIT: un po 'di codice:

for i in range(len(fz)): 
    testing = (abs(Sz[i]))/Nz

    if fz[i] < 0.05:
        Sz[i]=0

Velfreq = []
Velfreqa = array(Velfreq)
Velfreqa = Sz/(2*pi*fz*1j)
Veltimed = ifft(Velfreqa)
real = Veltimed.real

Quindi, essenzialmente, ho eseguito una FFT sui miei dati dell'accelerometro, dando a Sz, filtrate le alte frequenze usando un semplice filtro a muro di mattoni (so che non è l'ideale). Quindi uso omega aritmetica sulla FFT dei dati. Grazie anche a Datageist per l'aggiunta delle mie immagini al mio post :)


Benvenuti in DSP! La curva rossa nella tua seconda immagine è una versione "levigata" dei dati (verdi) originali?
Phonon,

La curva rossa è (si spera!) Una curva di velocità generata da fft seguita da filtro, seguita da omega aritmetica (che si divide per 2 * pi f j), seguita da inv. fft
Michael M,

1
Forse se includi un'espressione matematica o uno pseudocodice più precisi per quello che hai fatto, chiariresti un po 'le cose.
Phonon,

Aggiunto un po 'ora, questo è l'aspetto generale del codice ..
Michael M

1
La mia domanda sarebbe: cosa ti aspetti di vedere nei dati? Non saprai se hai un buon approccio se non sai qualcosa sul segnale sottostante che ti aspetti di vedere dopo il filtraggio. Inoltre, il codice che hai mostrato è confuso. Sebbene non mostri l'inizializzazione fzdell'array, sembra invece applicare un filtro passa-alto.
Jason R,

Risposte:


13

Come sottolineato da @JohnRobertson in Bag of Tricks for Denoising Signals Mentre Mantenendo Sharp Transitions , il denoising Total Variaton (TV) è un'altra buona alternativa se il segnale è costante a livello di pezzo. Questo può essere il caso dei dati dell'accelerometro, se il segnale continua a variare tra i diversi piani.

μρ

yXμX-y2+DX1D

function denoise()

f = [-1*ones(1000,1);3*ones(100,1);1*ones(500,1);-2*ones(800,1);0*ones(900,1)];
plot(f);
axis([1 length(f) -4 4]);
title('Original');
g = f + .25*randn(length(f),1);
figure;
plot(g,'r');
title('Noisy');
axis([1 length(f) -4 4]);
fc = denoisetv(g,.5);
figure;
plot(fc,'g');
title('De-noised');
axis([1 length(f) -4 4]);

function f = denoisetv(g,mu)
I = length(g);
u = zeros(I,1);
y = zeros(I,1);
rho = 10;

eigD = abs(fftn([-1;1],[I 1])).^2;
for k=1:100
    f = real(ifft(fft(mu*g+rho*Dt(u)-Dt(y))./(mu+rho*eigD)));
    v = D(f)+(1/rho)*y;
    u = max(abs(v)-1/rho,0).*sign(v);
    y = y - rho*(u-D(f));
end

function y = D(x)
y = [diff(x);x(1)-x(end)];

function y = Dt(x)
y = [x(end)-x(1);-diff(x)];

risultati:

inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


Mi piace davvero questa risposta, andrò avanti e la proverò. Scusa, mi ci è voluto tanto tempo per rispondere!
Michael M,

Risposta eccellente. Grazie per i dettagli Sto cercando la versione C di questo codice. Qualcuno qui ha portato questo codice matlab su C che vorrebbe condividere? Grazie.
Rene Limberger,

Cosa significa costante saggia?
tilaprimera,

6

Il problema è che il tuo rumore ha uno spettro piatto. Se si assume il rumore gaussiano bianco (che risulta essere un buon presupposto) la sua densità dello spettro di potenza è costante. In parole povere, significa che il tuo rumore contiene tutte le frequenze. Ecco perché qualsiasi approccio in frequenza, ad esempio filtri DFT o passa-basso, non è un buon approccio. Quali sarebbero le tue frequenze di taglio poiché il tuo rumore è su tutto lo spettro?

Una risposta a questa domanda è il filtro Wiener, che richiede la conoscenza delle statistiche del rumore e del segnale desiderato. Fondamentalmente, il segnale rumoroso (segnale + rumore) viene attenuato sulle frequenze in cui si prevede che il rumore sia più grato del tuo segnale, e viene amplificato dove ci si aspetta che il tuo segnale sia più grato del tuo rumore.

Tuttavia, suggerirei approcci più moderni che utilizzano l'elaborazione non lineare, ad esempio il denoising wavelet. Questi metodi forniscono risultati eccellenti. Fondamentalmente, il segnale rumoroso viene prima decomposto in wavelet e quindi azzerati piccoli coefficienti. Questo approccio funziona (e DFT no) a causa della natura multi-risoluzione delle wavelet. Cioè, il segnale viene elaborato separatamente in bande di frequenza definite dalla trasformata wavelet.

In MATLAB, digita "wavemenu" e quindi "SWT denoising 1-D". Quindi 'File', 'Esempio di analisi', 'Segnali rumorosi', 'con Haar a livello 5, blocchi rumorosi'. In questo esempio viene utilizzato il wavelet Haar, che dovrebbe funzionare bene per il problema.

Non sono bravo in Python, ma credo che tu possa trovare alcuni pacchetti NumPy che eseguono il denoising wavelet di Haar.


1
Non sarei d'accordo con la tua prima affermazione. Stai assumendo che il segnale di interesse copra l'intera larghezza di banda della sequenza di input, il che è improbabile. In questo caso è ancora possibile ottenere un rapporto segnale-rumore migliorato utilizzando un filtro lineare, eliminando il rumore fuori banda. Se il segnale è fortemente sovracampionato, è possibile ottenere un grande miglioramento con un approccio così semplice.
Jason R,

È vero, e questo è ottenuto dal filtro Wiener, quando conosci le statistiche del tuo segnale e del tuo rumore.
Daniel R. Pipa,

Sebbene la teoria alla base del denoising wavelet sia complicata, l'implementazione è semplice come l'approccio che hai descritto. Implica solo banchi di filtri e soglie.
Daniel R. Pipa,

1
Sto indagando su questo ora, pubblicherò i miei progressi sopra, grazie a entrambi e Phonon per tutto il vostro aiuto finora!
Michael M,

@DanielPipa Non ho accesso ai pacchetti matlab in questione. Potete fornire un documento o altro riferimento che descriva il metodo che corrisponde al codice matlab.
John Robertson,

0

Come suggerito da Daniel Pipa, ho dato un'occhiata al denoising wavelet e ho trovato questo eccellente articolo di Francisco Blanco-Silva.

Qui ho modificato il suo codice Python affinché l'elaborazione delle immagini funzioni con i dati 2D (accelerometro) anziché 3D (immagine).

Nota , la soglia è "compensata" per la soglia minima nell'esempio di Francisco. Consideralo e modificalo per la tua applicazione.

def wavelet_denoise(data, wavelet, noise_sigma):
    '''Filter accelerometer data using wavelet denoising

    Modification of F. Blanco-Silva's code at: https://goo.gl/gOQwy5
    '''
    import numpy
    import scipy
    import pywt

    wavelet = pywt.Wavelet(wavelet)
    levels  = min(15, (numpy.floor(numpy.log2(data.shape[0]))).astype(int))

    # Francisco's code used wavedec2 for image data
    wavelet_coeffs = pywt.wavedec(data, wavelet, level=levels)
    threshold = noise_sigma*numpy.sqrt(2*numpy.log2(data.size))

    new_wavelet_coeffs = map(lambda x: pywt.threshold(x, threshold, mode='soft'),
                             wavelet_coeffs)

    return pywt.waverec(list(new_wavelet_coeffs), wavelet)

Dove:

  • wavelet- nome stringa della forma wavelet da utilizzare (vedere pywt.wavelist(), ad es. 'haar')
  • noise_sigma - deviazione standard del rumore dai dati
  • data - matrice di valori da filtrare (ad es. dati dell'asse x, y o z)
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.