Domanda

Ho creato un semplice filtro a basso passaggio di Chebyshev basato su coefficienti generati da questo sito: http://www-users.cs.york.ac.uk/~fisher/mkfilter/, che sto usando per filtrare le frequenze superiori a 4kHz in un segnale audio di velocità di campionamento a 16kHz prima di downsampling a 8kHz. Ecco il mio codice (che è C#, ma questa domanda non è specifica per C#, non esitare a usare altre lingue in lingue diverse).

/// <summary>
/// Chebyshev, lowpass, -0.5dB ripple, order 4, 16kHz sample rte, 4kHz cutoff
/// </summary>
class ChebyshevLpf4Pole
{
    const int NZEROS = 4;
    const int NPOLES = 4;
    const float GAIN = 1.403178626e+01f;

    private float[] xv = new float[NZEROS+1];
    private float[] yv = new float[NPOLES + 1];

    public float Filter(float inValue)
    {
        xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4];
        xv[4] = inValue / GAIN;
        yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4];
        yv[4] = (xv[0] + xv[4]) + 4 * (xv[1] + xv[3]) + 6 * xv[2]
                     + (-0.1641503452f * yv[0]) + (0.4023376691f * yv[1])
                     + (-0.9100943707f * yv[2]) + (0.5316388226f * yv[3]);
        return yv[4];
    }
}

Per testarlo ho creato un'onda sinusoidale "Chirp" da 20Hz a 8kHz usando Audacity. Il segnale di prova sembra questo:

test signal

Dopo averlo filtrato ottengo:

filtered spectrum

La forma d'onda mostra che il filtro sta effettivamente riducendo l'ampiezza delle frequenze superiori a 4kHz, ma ho un carico di rumore aggiunto al mio segnale. Questo sembra essere il caso di qualsiasi tipo di filtro che provo a implementare (ad esempio Butterworth, alzato coseno ecc.).

filtered waveform

Sto facendo qualcosa di sbagliato o questi filtri introducono semplicemente artefatti ad altre frequenze? Se downample usando l'approccio ingenuo della media di ogni coppia di campioni, non ottengo affatto questo rumore (ma ovviamente l'aliasing è molto peggio).

È stato utile?

Soluzione

Ok, sono stato davvero stupido. La creazione del mio LPF stava accadendo all'interno di un ciclo di elaborazione anziché all'esterno, il che significa che ogni 512 campioni ne stavo creando uno nuovo che significa che stavo perdendo lo stato salvato. Con una sola istanza del mio filtro che esegue l'intero file, il rumore scompare e, come previsto, ottengo frequenze alias poiché il filtro non può rimuovere completamente tutto sopra il taglio.

correctly using filter

Altri suggerimenti

Ho controllato il tuo codice filtro in Mathematica e funziona bene qui senza introdurre rumore, quindi probabilmente il rumore proviene da un'altra parte del tuo codice.

Chirp after filtering

È possibile avere problemi di stabilità numerica, in particolare se uno qualsiasi dei poli è vicino al cerchio unitario. Prova a fare tutti i tuoi termini intermedi a doppia precisione e quindi riconditi alla singola precisione alla fine. Non ho troppo familiarità con C# ma in C questo sarebbe:

yv[4] = (float)(((double)xv[0] + (double)xv[4]) + 4.0 * ((double)xv[1] + (double)xv[3]) + 6.0 * xv[2]
             + (-0.1641503452 * (double)yv[0]) + (0.4023376691 * (double)yv[1])
             + (-0.9100943707 * (double)yv[2]) + (0.5316388226 * (double)yv[3]));

Non hai inizializzato correttamente il tuo xv e yv Array prima di usarli per la prima volta. Nella maggior parte delle lingue questo significa che i loro valori non sono definiti, il che può portare a risultati inaspettati come i tuoi. Inizializzarli a un valore adeguato (come 0) può risolvere il tuo problema.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top