Knacken trotz FIR Filter

OP #1051188
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
1
    short* pTmpBuffer = (short*)pBuffer; //pBuffer = unbehandelte Rohdaten
2
    short* pTmpBuffer2 = new short[160];
3
    for(int i = 0; i < (size - m_nCoeffSize); i++)
4
    {
5
        pTmpBuffer[i] = 0;
6
        for(int y = 0; y < m_nCoeffSize; y++)
7
        {
8
            pTmpBuffer[i] += (pBuffer[y + i] * fCoeffs[y]);
9
        }
10
    }

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

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
OP #1051302
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?
Admin Persönliche Seite #1051353
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?
OP #1051369
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.
Admin Persönliche Seite #1051927
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).
#1052276
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.
Angehängte Dateien:
Admin Persönliche Seite #1052885
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.
OP #1053849
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?
OP #1053888
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.
1
for(int i = 0; i < size; i++)
2
{
3
     m_pAliasBuffer[0] = pBuffer[i];
4
     /* calc FIR */
5
     accum = 0;
6
     for (ii = 0; ii < m_nCoeffSize; ii++) 
7
     {
8
         accum += fCoeffs[ii] * m_pAliasBuffer[ii];
9
     }
10
     /* shift delay line */
11
     for (ii = m_nCoeffSize - 2; ii >= 0; ii--) 
12
     {
13
         m_pAliasBuffer[ii + 1] = m_pAliasBuffer[ii];
14
     }
15
     pTmpBuffer[i] = accum;
16
}

Ich bin echt langsam überfragt
Admin Persönliche Seite #1053976
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren