2016-08-02 7 views
0

Guten Abend, Ich schreibe eine einfache Software in C, die eine WAV-Audiodatei mit libsndfile-Bibliothek (http://www.mega-nerd.com/libsndfile/api.html) liest, als die Proben zu einer Prozessfunktion gehen, wo ich einen Filter anwenden das Signal (Butterworth-Tiefpassfilter zweiter Ordnung, angewandt mit der transponierten direkten Form II). Danach schreibe ich das Ergebnis in eine neue WAV-Datei. Wenn ich anstelle des Filters einfache Operationen anwende (wie zum Beispiel Multiple Samples für eine Konstante), funktioniert es gut, aber wenn ich den Filter anwende, erzeugt es eine Menge Rauschen. Ich habe versucht, die Werte der Samples nach dem Filter zu drucken und bevor sie in die neue Datei geschrieben werden, und ich habe die gleichen Werte wie von Matlab (wo die Ausgabe ich perfekt ist), aber sie unterscheiden sich von den Werten Ich habe, wenn ich die Ausgabe von der Bibliothek geschrieben lesen.Verschiedene Ausgänge beim Anwenden eines Filters auf ein Audiosignal

static void processAudio (double *buffer, int length) 
{ 
    //arrays a and b are the coefficients 
    double a[] = { 1, 
        -1.799096409484668, 
        0.817512403384758}; 


    double b[] = { 0.004603998475022, 
        0.009207996950045, 
        0.004603998475022}; 

    //arrays a_ and b_ are the coefficients normalized 
    double a_[] = {1,a[1]/b[0],a[2]/b[0]}; 
    double b_[] = {1,b[1]/b[0],b[2]/b[0]}; 
    double gain = b[0]/a[0]; 

    double reg[] ={0,0}; //memory registers 

    for(int i = 0; i<length; i++) 
    { 
     if(i%2==0) //just left channel is changed 
     { 
      //TRANSPOSED DIRECT FORM II 
      double input = *(buffer+i); 
      double output =(input + reg[0])*gain; 

      reg[0] = reg[1]+b_[1]*input-a_[1]*output; 
      reg[1] = b_[2]*input - a_[2]*output; 

      *(buffer+i) = output; 

     } 
    } 
} 



//that function is called in the main method inside this cycle 
int main(void) 
{ 
    ... 

    while ((framesRead = sf_read_double(inputFile, buffer, BUFFER_LENGTH))) 
    { 

      processAudio(buffer, framesRead); 

      sf_write_double(outputFile, buffer, framesRead); 
    } 

    ... 
} 

Wenn ich die Ergebnisse direkt nach dem Filter drucke ich bekommen:

0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
0.00000000000000 
-0.00000014050288 
-0.00000025277823 
0.00000050310774 
0.00000209530885 
0.00000420138311 
0.00000725078112 
0.00001115570320 
0.00001554761090 
0.00002053775981 
0.00002550357112 
0.00002796948679 
0.00000727086200 
-0.00006401853354 
... 

Wenn ich die Ausgabedatei lesen die Ergebnisse sind

0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
0 
3.05175781250000e-05 
3.05175781250000e-05 
3.05175781250000e-05 
3.05175781250000e-05 
0 
-6.10351562500000e-05 
-0.000366210937500000 
-0.00183105468750000 
-0.00601196289062500 
-0.0140075683593750 
-0.0261840820312500 
-0.0421142578125000 
-0.0610656738281250 
-0.0820617675781250 
-0.104156494140625 
-0.126342773437500 
-0.147766113281250 
-0.167663574218750 
-0.185363769531250 
-0.200378417968750 
-0.212280273437500 
... 

Sie sind sehr unterschiedlich. Ich weiß nicht wirklich was los ist. Wenn Sie eine Idee haben, lassen Sie es mich wissen. Vielen Dank im Voraus!

+0

Bitte [bearbeiten] Sie Ihren Code, um ein tatsächlicher [mcve] zu sein. Welche Typen sind 'a' und' b'? –

+0

Ich habe die Koeffizienten, die ich verwende, hinzugefügt ... – thebesttony

+1

Scheint so, als ob diese ganze Frage ein großer Hering ist. Die Frage konzentriert sich auf den Filter, und Sie sind anscheinend mit der Ausgabe des Filters zufrieden. Es ist nur das Schreiben/Lesen der Datei, die das Problem zu sein scheint. Mit anderen Worten, das Problem hat etwas mit 'sf_write_double' zu ​​tun. Also würde ich den anderen Müll loswerden und einfach mit 'sf_write_double' experimentieren, um zu sehen, wie es funktioniert. – user3386109

Antwort

0

Sie erhalten unterschiedliche Ausgaben, weil Sie die Status des Filters nicht beibehalten. In jeder Iteration der Rahmenschleife setzen Sie den Filterstatus auf den Anfangszustand {0.0, 0.0} zurück. Normalisieren Sie die Koeffizienten auch nicht, da MATLAB dies für Sie erledigt. Nehmen Sie einfach die Koeffizienten von MATLAB und wenden Sie sie auf den Filter an.

würde ich eine Struktur bilden, die den Zustand des Filters zu halten, wie folgt aus:

struct biquad { 
    double b0, b1, b2, a1, a2; // Note: MATLAB will always normalize a0 to 1.0, so no need to process that. 
    double r0, r1; 
}; 

Dann habe ich eine Funktion wie biquad_process, so etwas wie dieses hinzufügen würde:

void process_biquad(struct biquad *self, double *buffer, int length) 
{ 
    int i; 

    for (i = 0; i < length; i++) { 
     double x = buffer[i]; 
     double y = (x * self->b0) + self->r0; 

     self->r0 = self->r1 + (x * self->b1) - (self->a1 * y); 
     self->r1 = (self->b2 * x) - (self->a2 * y); 

     buffer[i] = y; 
    } 
} 

Dann In Ihrer main() Funktion können Sie das Audio in den Puffer laden und jeden Chunk wie folgt verarbeiten:

int main(void) 
{ 
    struct biquad *bq = calloc(1, sizeof(struct biquad)); 

    // Take coefficients from MATLAB and put them here 
    bq->b0 = ... 
    bq->b1 = ... 

    // Set initial state to 0.0 
    bq->r0 = bq->r1 = 0.0; 
    ... 

    while ((framesRead = sf_read_double(inputFile, buffer, BUFFER_LENGTH))) 
    { 

      process_biquad(bq, buffer, framesRead); 

      sf_write_double(outputFile, buffer, framesRead); 
    } 

    ... 
} 

Hoffentlich hilft das.

Verwandte Themen