mikrocontroller.net

Forum: Digitale Signalverarbeitung / DSP Knacken trotz FIR Filter


Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo an alle,

ich habe einen VOIP Client entwickelt und tu mich gerade schwer mit der 
Implentierung der Sprache.
Ich zeichne die Sprache via Microphone auf und zwar unter DirectSound.

Dann gebe ich die ungefilterten Rohdaten an einen FIR Filter
    short* pTmpBuffer = (short*)pBuffer; //pBuffer = unbehandelte Rohdaten
    short* pTmpBuffer2 = new short[160];
    for(int i = 0; i < (size - m_nCoeffSize); i++)
    {
        pTmpBuffer[i] = 0;
        for(int y = 0; y < m_nCoeffSize; y++)
        {
            pTmpBuffer[i] += (pBuffer[y + i] * fCoeffs[y]);
        }
    }

Danach sample ich das ganze runter von 16kHz auf 8kHz indem ich jeden 
2ten Sample einfach wegwerfe.
pTmpBuffer2[0] = 0;
    int x = 0;
    for(int i = 0; i < size; i++)
    {
        
        if((i+1)%2 == 0)
        {
            pTmpBuffer2[x] = pTmpBuffer[i];
            x++;
        }
    }

Und encodiere das ganze dann noch mal ins uLaw Format
Am anderen Ende bekomme ich dann die Sprache leicht verzerrt mit einem 
störendem Knacken im Hintergrund.

Ich weiß gerade gar nicht mehr weiter. Kann mir evtl jemand helfen?

Die Filterkoeffizienten hole ich mir über dieses Programm
http://www.winfilter.20m.com

Gruß

Karsten

Autor: Unit* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Welche Bandbreite hat das Signal, das in den Kompressor reingeht?

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
16kHZ mit 16bit

Autor: Unit* (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nicht mal das analoge Signal wird gefiltert?
Das Antialiasing-Filter fehlt.

Autor: Anton2 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
... und das Weglassen jedes zweiten Bits ist auch nicht das WAHRE!

Du produzierst so unnötiges Rauschen - Knacken sollte es aber nicht. 
(???)

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich behandle direkt die Rohdaten nach dem sie über den ADC der 
Soundkarte abgetastet wurden. Also ganz normal PCM.
Was brauch ich für einen Antialiasing Filter?.

Ich muss dazu sagen ich bin absoluter Beginner auf dem Gebiet und froh, 
dass ich den FIR Filter verstanden habe.

@Anton2:
Wie kann man denn besser runtersamplen?

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist im Prinzip schon richtig. Erst mit Tiefpassfilter auf < 4 kHz 
begrenzen, dann jedes zweite Sample wegwerfen. Das Knacken kommt 
wahrscheinlich durch falsches Bufferhandling zustande (wie das bei 
DirectSound funktioniert weiß ich leider nicht), die "Verzerrungen" 
könnten Aliasing durch unzureichende Filterung sein.

Hat DirectSound keine Funktion zum Downsampling auf 8 kHz?

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab leider nichts dazu finden können ob es unter DirectSound eine 
Funktion zum runtersamplen gibt. In der SDK Dokumentation hab ich nichts 
gefunden und unter google ebensowenig.

Als Buffer hab ich einen Ringbuffer. Es wird immer eine Nachricht 
geschickt, wenn genügend Daten im Buffer vorhanden sind die bearbeitet 
werden können. Dann kann man mit den Signalen arbeiten.

Was heißt denn unzureichenden Filterung? Ich filtere derzewit mit 31 
Koeffizienten.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist der Eingangsbuffer gross genug dass er nicht ueberlaueft? Ist der 
Ausgangsbuffer gross genug dass er nicht leer laeuft? Fuellst du den 
Ausgangsbuffer am Anfang und nach einem Leerlaufen immer komplett voll? 
Ich bin sicher dass DirectSound Programmbeispiele bereitstellt die 
solche Fehlerquellen ausschliessen.

Wie hast du den Filter designt (Grenzfrequenz)? Du musst ueber 4 kHz 
eine moeglichst gute Daempfung haben (ich sag mal >30 dB als 
Hausnummer). Winfilter ist uebrigens etwas mit Vorsicht zu geniessen, 
verwende besser Scilab oder Octave (oder, falls vorhanden, MATLAB mit 
fdatool).

Autor: Roland Bumm (rolandb)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Müssen die Abtastwerte sich nicht überlappen? Sprich im Ringpuffer liegt 
ein Wert (der letzte vom vorherigen)? Oder mehr sogar?
Wenn das Stoss an Stoss liegt, dann kann es doch zum knacken kommen?

mfg

Autor: Roland Bumm (rolandb)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Roland Bumm wrote:
> Müssen die Abtastwerte sich nicht überlappen? Sprich im Ringpuffer liegt
> ein Wert (der letzte vom vorherigen)? Oder mehr sogar?
> Wenn das Stoss an Stoss liegt, dann kann es doch zum knacken kommen?
>
> mfg

Argh Sorry. Die Ausgangswerte müssen sich überlappen:

If the support of the impulse response, h(n), has length M
and the support of the k-th segment, xk(n), has length L,
then the discrete linear convolution of h and xk has support of length 
L+M-1

For example if  L = 125 and M = 26 then the support of the individual 
discrete linear convolutions each have length

N = L + K - 1
    = 125 + 26 - 1
    = 150

The first 25 elements of the k-th DLC overlap the last 25 elements of 
the previous DLC.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Andreas:
Wie errechne ich denn welche Werte ich für die Dämpfung benötige?

Warum ist der Winfilter mit Vorsicht zu genießen?

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der FIR-Filter muss am Anfang eines neuen Blocks auf die letzte Werte 
des alten Blocks zurueckgreifen. Am einfachsten geht das, indem die 
Filterfunktion einen eigenen Buffer fuer die letzten L-1 Samples 
bereithaelt, so dass sie nur mit einem Sample als Argument aufgerufen 
wird und ein Sample zurueckgibt.

Suche mal nach "Winfilter" im Forum. Alternativen fuer Filterdesign habe 
ich oben genannt, gibt aber natuerlich noch mehr.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieviele der letzten Werte des alten Blocks sind denn sinnvoll?

Also z.B. habe ich einen Buffer von 320Byte der gefiltert wird.
Kann ich hier berechnen wieviele genommen werden sollen???

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich schnall es gerade einfach nicht.
Hat irgendwer mal ein Beispiel für mich wie ich meinen Code(s.o.) 
anpassen könnte???

Pseudocode reicht ja schon nur nicht zu mathematisch bitte:D:D

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wieviele der letzten Werte des alten Blocks sind denn sinnvoll?

So viele wie der FIR-Filter braucht (Anzahl der Koeffizienten).

Beispielcode:
http://www.mikrocontroller.net/wikifiles/1/1e/FirAlgs.c

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Schwarz wrote:

> So viele wie der FIR-Filter braucht (Anzahl der Koeffizienten).

Das hatte ich mir schon fast gedacht, dass es die Anzahl er 
Koeffizienten sein muss. Aber sicher ist sicher:D Danke.
Was ich noch nicht so ganz klar verstanden habe, aus deiner Erklärung

> so dass sie nur mit einem Sample als Argument aufgerufen
> wird und ein Sample zurueckgibt

sprich ich arbeite nur mit einem Wert und rechne darauf die letzten 5 
Werte aus meinem Buffer?

Also
pTmpBuffer[0] = Sample[2] //bspw.
y += pTmpBuffer[0]*Coeffs[0];
pTmpBuffer[1] = y //pTmpBuffer wird immer der zuletzt berechnete Wert an
                  //erste Stelle gesetzt

Was mache ich während ich noch die ersten 5 Buffer bearbeite und somit 
vorher zwischen 0 und 4 Werte habe, womit rechne ich das auf?

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jetzt habe ich es mit dem Algorithmus des fir_basics aus deinem Beispiel 
ausprobiert. Die Sprache ist zwar besser aber es ist immer noch ein 
Knistern beim Sprechen und der Sound selbst ist noch ein wenig verzerrt.
for(int i = 0; i < size; i++)
{
     m_pAliasBuffer[0] = pBuffer[i];
     /* calc FIR */
     accum = 0;
     for (ii = 0; ii < m_nCoeffSize; ii++) 
     {
         accum += fCoeffs[ii] * m_pAliasBuffer[ii];
     }
     /* shift delay line */
     for (ii = m_nCoeffSize - 2; ii >= 0; ii--) 
     {
         m_pAliasBuffer[ii + 1] = m_pAliasBuffer[ii];
     }
     pTmpBuffer[i] = accum;
}

Ich bin echt langsam überfragt

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
OK, ich sehe gerade dass du mit Integern rechnest. Wenn du das machst, 
dann musst du fuer den Akkumulator eine groessere Wortbreite (z.B. long) 
verwenden und nach dem Aufaddieren einen Rechtsshift durchfuehren, 
entsprechend der Skalierung deiner Filterkoeffizienten. Bessere 
Alternative: lass dir die Koeffizienten in Floating Point ausgeben und 
rechne in Floating Point, dann must du dir darum keine Gedanken machen.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh sorry hätte ich vllt. mal anmerken können, die Koeffizienten sind in 
double
double fCoeffs[5] = { 
        -0.00112053738724361000,
        0.00112128133087145220,
        0.99999851211274415000,
        0.00112128133087145220,
        -0.00112053738724361000
    };
und accum ist ebenfalls vom Typ double

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
pBuffer ist der Eingang, pTmpBuffer der Ausgang (gib denen doch mal 
sinnvolle Namen)? Dann sollte das eigentlich funktionieren. Probier es 
am besten erst mal ohne DirectSound, Netzwerkuebertragung usw. aus, 
einfach von Buffer zu Buffer, und schau ob das funktioniert.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja pBuffer ist der Eingang und pTmpBuffer Ausgang.
Sorry für meine schlechte Namensgebung;)
Wie meinst du das genau von Buffer zu Buffer?
DirectSound liefert mir ja den Buffer oder soll ich den Filter einfach 
mal mit ner normalen WaveDatei, welche ich einlese austesten?

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah ok, danke.
Sorry für die dummen Fragen aber das Thema macht mich gerade ein wenig 
gar:D

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So habe jetzt noch mal ein paar unterschiedliche Koeffizienten 
ausprobiert.
Jetzt ist das Knacken fast weg.
Allerdings hört sich die Sprache noch sehr mechanisch an. Aber sie ist 
mittlerweile sehr deutlich zu verstehen.

Was kann man da noch machen?

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ein wav-Beispiel posten.

Autor: Karsten Asche (crazyplaya)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann muss ich erst mal ne Methode schreiben die mir ein Wave File 
ausspuckt.

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja. Oder zumindest die Rohdaten, in wav umwandeln kannst du sie mit 
Audacity o.ae.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.