Warum bekomme ich dieses Knistern beim Nullstellen der hohen Frequenzen?

8

Ich habe kürzlich angefangen, mit der Fourier-Transformation zu spielen (nachdem ich einige Wochen damit verbracht hatte, etwas über die Mathematik dahinter zu lernen). Ich habe mich entschlossen, einen Tiefpassfilter für den folgenden Soundbite zusammen zu hacken:

Insbesondere nahm ich die Fourier-Transformation, stellte die höchste Hälfte der Frequenzen auf Null und nahm dann die inverse Fourier-Transformation. Das habe ich bekommen

Warum gibt es dieses knisternde Geräusch?

JeremyKun
quelle
Außerdem sollte ich erwähnen, dass ich keine Ahnung habe, warum ich einen Tiefpassfilter auf einen Soundclip anwende. Es ist rein experimentell. Ist diese Operation für einen Soundclip überhaupt sinnvoll?
JeremyKun
Sie sollten diese Beispiele zum Herunterladen
bereitstellen

Antworten:

11

Zwei mögliche Probleme:

  1. Das Filtern im Frequenzbereich (unter Verwendung einer FFT) erfordert das Hinzufügen von Überlappungen, das Speichern von Überlappungen oder einen verwandten Algorithmus. Dies wird durch den Unterschied zwischen linearer und kreisförmiger Faltung verursacht. Andernfalls erhalten Sie ein Zeitdomänen-Aliasing
  2. Einige der Geräusche klingen wie einfaches Abschneiden. Durch Filtern kann die Zeitbereichsamplitude für einige Samples tatsächlich erhöht werden. Wenn dies den verfügbaren Bereich überschreitet, wird entweder abgeschnitten oder umbrochen.
Hilmar
quelle
1
Es klang für mich wie Clipping / Wrapping.
Heltonbiker
Was kann ich tun, um das Abschneiden / Umwickeln zu stoppen? Sollte ich diese Operation überhaupt nicht durchgeführt haben?
JeremyKun
Es ist definitiv ein Ausschnitt. Ich habe die Amplitude des Eingangssignals verkleinert und die Knackgeräusche verschwanden.
JeremyKun
7

Zunächst nur eine Anmerkung: Fourier-Transformationen sind nicht ideal für Tief- / Hochpassfilter. Butterworth-Filter sind ein guter Ausgangspunkt und folgen diesen Chebyshev / Elliptical-Filtern, wenn Sie ehrgeiziger werden.

Es sieht so aus, als würden Sie versuchen, einen idealen Filter zu implementieren. Es gibt keine Möglichkeit, diese "Brick-Wall" -Filter zu implementieren, bei denen wir alle Frequenzen über / unter einem bestimmten Wert abschneiden. Alle gut entwickelten Filter verjüngen sich um unsere Grenzfrequenz von 1 auf 0.

Ideale Filter sind nur theoretisch möglich, und wenn Sie eine kontinuierliche Fourier-Transformation hätten, würde Ihre obige Methode funktionieren.

Aber wir machen diskrete Fourier-Transformationen, also gibt es mehr zu befürchten. Da ich mir bei der Methode Ihrer Implementierung nicht sicher bin, gehe ich davon aus, dass Sie ein Fenster erstellen, da das Herausziehen von Frequenzen ein sicherer Weg ist, um in einer DFT mit Fenster zu knistern.

Beim Fenstern in einer DFT könnte man denken, dass die Frequenzamplituden zwischen Fenstern relativ kontinuierlich sind. Wenn beispielsweise die 400-Hz-Frequenz im aktuellen Fenster eine Amplitude von 0,5 hat, liegt die Amplitude im nächsten Fenster nahe bei 0,5. Dies ist leider nicht der Fall. Wenn wir also einfach die 400-Hz-Frequenz aus unserer DFT entfernen, hören wir möglicherweise laute Knackgeräusche oder Risse zwischen den Fenstern.

Ein kleines Beispiel: Die Cut-Off-Rate beträgt 600 Hz. Fenster 1 spielt einen Sinus von 800 Hz. Fenster 2 verbindet sich 'kontinuierlich' mit Fenster 1 und spielt 400 Hz. Dann hören wir ein Knallen zwischen den Fenstern, weil Fenster 1 still ist und Fenster 2 sich sofort einschaltet.

Eine andere Sache, die zu beachten ist, ist, dass wir mit einer DFT nur eine begrenzte Anzahl von Frequenzen darstellen können. Wenn wir eine Audiodatei mit einer Sinuswelle einer Frequenz zwischen zwei unserer diskreten Frequenzen in unserer DFT haben, dann repräsentieren wir sie tatsächlich mit vielen unserer diskreten Frequenzen. Obwohl eine Beispiel-Audiodatei eine Sinuswelle enthalten kann, die niedriger als unser Grenzwert ist, können wir, wenn ihre Frequenz zwischen unseren DFT-Frequenzen liegt, einen Teil davon ausschneiden und mit der obigen Methode verzerren, da höhere Frequenzen erforderlich sind, um das Audio darzustellen Datei.

Ich hoffe, das hilft

Matt Tytel
quelle
Ah, ich ziehe meinen Fensterkommentar zurück (es ist eher ein Echtzeit-DFT-Problem). Hilmars Antwort scheint genauer zu sein.
Matt Tytel
4

s(t)=slow(t)+shigh(t)

slow(t)=cos(2πf0t)+cos(2πf1t+π3)

shigh(t)=12cos(2πf2t+0.2)

f0,f1fcutf0<f1<fcutf2>fcut

Nfs>2f2fs2f2

Ich habe ein kleines Python-Programm kombiniert, um einige der Konzepte zu veranschaulichen - der Code ist ziemlich schrecklich, aber ich habe nur alten Code genommen, den ich für ähnliche Probleme hatte. Obwohl es kaum Kommentare gibt, sollte es aufgrund der kleinen Module ziemlich einfach sein, diesen zu folgen. Das sind zwei dft / idft- Funktionen; zwei Funktionen fshiftn / fshiftp zur Frequenzverschiebung des Signals i DFT-Domäne zum Filtern; eine Funktion dftlpass zum Durchführen der Filterung in der DFT-Domäne; eine Funktion zpblpass , um die Filterung unter Verwendung eines Butterworth-Filters durchzuführen ; eine Funktion bbdftsig , um das Testsignal zu bilden und die Filterung durchzuführen; und schließlich eine kleine Funktion Plotsigsum die Signale zu zeichnen. Am Ende des Skripts werden die verschiedenen Parameter festgelegt und die verschiedenen Zahlen erstellt.

"""
   Test of DFT versus scipy.signal.butter filtering with respect to
   signal reconstruction.

"""

# import ############################################################ import #
import matplotlib as mpl;   mpl.rcParams['backend'] = 'Agg'
import matplotlib.pyplot as mplpp
import matplotlib.mlab as mplml
import numpy as np
import scipy.signal as sps


# initialize #################################################### initialize #
try:
    mpl.rc('text', usetex=False)
    mpl.rc('font', family='serif')
    mpl.rc('font', serif='STIXGeneral')
    mpl.rc('font', size=8)
except AttributeError:
    None


# dft ################################################################## dft #
def dft(xt, fs, t0):
    N, d = len(xt), -2j*np.pi/len(xt)
    w = np.arange(N, dtype=np.float).reshape((N,1))
    c = np.exp(d*t0*fs*w)
    W = np.exp(d*np.dot(w,np.transpose(w)))
    xf = np.multiply(c,np.dot(W,xt)) / float(N)
    f = w*fs/float(N)
    return xf, f


# idft ################################################################ idft #
def idft( X, FS, T0 ):
    N, d = len(X), 2j*np.pi/len(X)
    w = np.arange(N, dtype=float).reshape((N,1))
    cc = np.exp(d*T0*FS*w)
    Wc = np.exp(d*np.dot(w, np.transpose(w)))
    Y = np.dot(Wc, np.multiply(cc, X))
    return Y



# fshiftn ########################################################## fshiftn #
def fshiftn( xf, f ):
    assert type(f) == np.ndarray, "f must be a np.ndarray"
    assert f.shape[1] == 1, "f must be a column array"
    assert xf.shape[1] == 1, "xf must be a column array"
    assert sum(f<0) == 0, "All frequency components must be 0 or positive"

    # Determine sampling rate, tolerance, and allocate output array
    fs, tol = len(f)*(np.abs(f[1,0]-f[0,0])), 1.E-2
    fshift = np.zeros((len(f),1), dtype=float)
    xfshift = np.zeros((len(f),1), dtype=complex)

    # Determine index where f > fs/2
    Nm = np.floor(len(f)/2.0)
    Np = np.floor((len(f)-1.0)/2.0)

    # Compute output frequency array such that -fs/2 <= f < fs/2 and the
    # corresponding Fourier coefficients
    fshift[:Nm,0] = f[Np+1:,0] - fs
    fshift[Nm,0] = f[0,0]
    fshift[Nm+1:,0] = f[1:Np+1,0]

    xfshift[:Nm,0] = xf[Np+1:,0]
    xfshift[Nm,0] = xf[0,0]
    xfshift[Nm+1:,0] = xf[1:Np+1,0]

    return xfshift, fshift


# fshiftp ########################################################## fshiftp #
def fshiftp(xf, f):
    assert type(f) == np.ndarray, "f must be a np.ndarray"
    assert f.shape[1] == 1, "f must be a column array"
    assert xf.shape[1] == 1, "xf must be a column array"
    assert sum(f<0) > 0, "Some input frequencies must be negative"

    # Determine sampling rate, tolerance, and allocate output array
    fs, tol = len(f)*(np.abs(f[1,0]-f[0,0])), 1.E-2
    fshift = np.zeros((len(f),1), dtype=float)
    xfshift = np.zeros((len(f),1), dtype=complex)

    # Determine index where f > fs/2
    #Nx = np.floor((len(f)+1+tol)/2)
    Nm = np.floor(len(f)/2.0)
    Np = np.floor((len(f)-1.0)/2.0)

    # Compute output frequency array such that -fs/2 <= f < fs/2 and the
    # corresponding Fourier coefficients
    fshift[Np+1:,0] = f[:Nm:,0] + fs
    fshift[0,0] = f[Nm,0]
    fshift[1:Np+1:,0] = f[Nm+1:,0]

    xfshift[Np+1:,0] = xf[:Nm:,0]
    xfshift[0,0] = xf[Nm,0]
    xfshift[1:Np+1:,0] = xf[Nm+1:,0]

    return xfshift, fshift


# dftlpass ######################################################## dftlpass #
def dftlpass(xt, fs, fcut):
    # Perform Discrete Fourier Transform
    xf, f = dft(xt, fs, 0.0)

    # Shift frequencies to -fs/2 <= f < fs/2 ... and coefficients
    xfshift, fshift = fshiftn(xf, f)

    # Perform filtration
    xfshift = xfshift * (np.abs(fshift) <= fcut)

    # Re-shift frequencies to 0 <= f < fs ... and coefficients
    xfrecon, frecon = fshiftp(xfshift, fshift)

    # Perform inverse Discrete Fourier Transform
    yt = idft(xfrecon, fs, 0.0)
    return yt.real


# zpblpass ######################################################## zpblpass #
def zpblpass(xn, fcal, fs, fcut):
    bz, az = sps.butter(5, fcut/(fs/2))

    # Gain calibration
    Ncal = np.max([np.int(20*fs/fcal), 30000])
    Nguard = np.int(0.1*Ncal)    
    t = np.arange(Ncal) / fs
    x0_cal = 1.0 * np.cos(2*np.pi*fcal*t)
    yi_cal = sps.filtfilt(bz, az, 2.0*x0_cal*np.cos(2*np.pi*fcal*t))
    k = 1.0/np.mean(yi_cal[Nguard:Ncal-Nguard])

    # Scaled output
    yn = k * sps.filtfilt(bz, az, xn)
    return yn


# bbdftsig ######################################################## bbdftsig #
def bbdftsig(f0, f1, f2, fcut, fs, N):
    t = np.arange(N).reshape((N,1)) / fs
    s0 = np.sin(2*np.pi*f0*t)
    s1 = np.sin(2*np.pi*f1*t + 0.2)
    s2 = 0.7 * np.sin(2*np.pi*f2*t + np.pi/3.0)
    slow = s0 + s1
    s = slow + s2

    sf = dftlpass(s, fs, fcut)
    sfdftv = sf.reshape((N))
    sv = s.reshape((N))
    slowv = slow.reshape((N))

    sv = s.reshape((N))
    sfzpbv = zpblpass(sv, f1, fs, fcut)
    #sfzpbv = sfzpb.reshape((N))
    return sv, slowv, sfdftv, sfzpbv


# plotsigs ######################################################## plotsigs #
def plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname):
    n = np.arange(s.shape[0])

    # Plot results
    mplpp.figure(1, (5.0,2.25))
    mplpp.clf()
    mplpp.plot(n[Nstart:Nstop], s[Nstart:Nstop], 'm-',
               n[Nstart:Nstop:4], s[Nstart:Nstop:4], 'mx',
               n[Nstart:Nstop], slow[Nstart:Nstop], 'g-',
               n[Nstart:Nstop:10], slow[Nstart:Nstop:10], 'gx',
               n[Nstart:Nstop], sfdft[Nstart:Nstop], 'r-',
               n[Nstart:Nstop:15], sfdft[Nstart:Nstop:15], 'rx',
               n[Nstart:Nstop], sfzpb[Nstart:Nstop], 'b-',
               linewidth=1.5)
    mplpp.legend([r'$s$', r'$s$', r'$s_{\rm low}$', r'$s_{\rm low}$',
                  r'DFT', r'DFT', r'ZPB'], loc='upper right')
    mplpp.ylabel(r'Signal')
    mplpp.xlabel(r'$n$')
    #mplpp.axis([-10.0, 10.0, 1.0E-2, 1.0E2])
    mplpp.grid(True)
    mplpp.savefig(fname, dpi=600,
                bbox_inches='tight', pad_inches=0.05)
    mplpp.close()


# __main__ ######################################################## __main__ #
if __name__ == '__main__':
    # Initialize
    f0 = 3.0
    f1 = 11.5
    f2 = 20.0
    fcut = 15.0
    fs = 1000.0
    N = 5000

    s, slow, sfdft, sfzpb = bbdftsig(f0, f1, f2, fcut, fs, N)
    n = np.arange(s.shape[0])

    # Fig. 1: full data set
    Nstart = 0
    Nstop = N
    fname = 'full.pdf'
    plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)

    # Fig. 2: beginning
    Nstart = 0
    Nstop = 150
    fname = 'beginning.pdf'
    plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)

    # Fig. 3: middle
    Nstart = np.floor(N/2.0) - 75
    Nstop = Nstart + 100
    fname = 'middle.pdf'
    plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)

    # Fig. 4: ending
    Nstart = N - 150
    Nstop = N
    fname = 'ending.pdf'
    plotsigs(s, slow, sfdft, sfzpb, Nstart, Nstop, fname)

N=5000fs=1000fs/N=0.2f0,f1,f2f0=3f1=11f2=21fcut=15

Beginn der Signale - am Netz Mitten in den Signalen - am Netz Signalende - am Netz

sslowslowf1. Wie es für diese Art der Verarbeitung recht typisch ist, weisen wir zu Beginn und am Ende der Sequenz einige Unterschiede auf, die auf Kanteneffekte und eine recht gute Übereinstimmung zwischen beiden Filterarten im mittleren Bereich zurückzuführen sind.

f1f1=11.5

Beginn der Signale - netzunabhängig Mitten in den Signalen - netzunabhängig Signalende - netzunabhängig

slow

Zusammenfassend ist es also möglich, eine direkte Filterung zu verwenden, indem Fourier-Koeffizienten auf Null gesetzt werden, was manchmal auch bei der Kompressionserfassung erfolgt, um die Unterstützung eines Signals zu verringern, um einem Signal Sparsity aufzuzwingen. Dies hat jedoch Konsequenzen wie erhöhte Fehler insbesondere an den Signalflanken. Ferner ist das Obige ein bester Fall, bei dem das gesamte Signal als eine Sequenz behandelt wird. Wenn das Signal in Zeitrahmen aufgeteilt werden muss, wird es kompliziert, da wir eine Fensterung oder eine andere Technik in Betracht ziehen müssen, um die Kontinuität des Signals zwischen den Rahmen sicherzustellen. Mein Rat ist also ähnlich wie in einigen anderen Beiträgen, wenn ich empfehle, normalerweise einen Butterworth / Elliptic / .. oder einen anderen Filter zu verwenden.

Lars1
quelle
0

Das Nullstellen von Bins in einer FFT kann tatsächlich die Amplitude anderer Frequenzen in der Nähe des Null-Ed-Bin oder seiner benachbarten Bins erhöhen, aber nicht zentriert sein. Dieser Anstieg kann zu Übersteuerungen führen.

Wenn Sie die FFT mit nicht auf Nullen aufgefüllten (und nicht überlappenden) Blöcken ausführen (im Gegensatz zum gesamten Song in einer großen FFT), werden alle FFT-Datenänderungen von hinten nach vorne umgeschaltet Zeitbereichssequenz in jedem Block, wodurch andere seltsame Diskontinuitäten an den falschen Stellen hinzugefügt werden.

hotpaw2
quelle
0

Hier ist ein schnelles und schmutziges FFT-Bandpassfilter mit Nullstellung, das auch den FFT-Code enthält.

void FFT(int n, int inverse, double *gRe, double *gIm, double *GRe, double *GIm)
{

    int m = 0;
    int p = 1;
    int j = 0;
    int i1=0;
    int k=0;
    double ca=0;
    double sa=0;
    int l1,l2,l3;
    double u1,u2;
    double t1 = 0;
    double t2 = 0;
    int i2=0;
    double z;
    /* Calculate m=log_2(n) */
    while(p < n)
    {
        p *= 2;
        m++;
    }
    /* Bit reversal */
    GRe[n - 1] = gRe[n - 1];
    GIm[n - 1] = gIm[n - 1];
    for(i1 = 0; i1 < n - 1; i1++)
    {
        GRe[i1] = gRe[j];
        GIm[i1] = gIm[j];
        k = n / 2;
        while(k <= j)
        {
            j -= k;
            k /= 2;
        }
        j += k;
    }
    /* Calculate the FFT */
    ca = -1.0;
    sa = 0.0;
    l1 = 1;
    l2 = 1;
    l3=0;
    for(l3 = 0; l3 < m; l3++)
    {
        l1 = l2;
        l2 *= 2;
        u1 = 1.0;
        u2 = 0.0;       
    for(j = 0; j < l1; j++)
        {
            i2=j;
            for(i2 = j; i2 < n; i2 += l2)
            {
                i1 = i2 + l1;
                t1 = u1 * GRe[i1] - u2 * GIm[i1];
                t2 = u1 * GIm[i1] + u2 * GRe[i1];
                GRe[i1] = GRe[i2] - t1;
                GIm[i1] = GIm[i2] - t2;
                GRe[i2] += t1;
                GIm[i2] += t2;
            }
            z =  u1 * ca - u2 * sa;
            u2 = u1 * sa + u2 * ca;
            u1 = z;
        }
        sa = sqrt((1.0 - ca) / 2.0);
        if(!inverse) sa =- sa;
        ca = sqrt((1.0 + ca) / 2.0);

    }
    /* Divide through n if it isn't the IDFT */
    if(!inverse)
    {
        int i3=0;
        for(i3 = 0; i3 < n; i3++)
        {
            GRe[i3] /= n;
            GIm[i3] /= n;
        }
    }
}


void mainfftBandPass(double *insamples, double *outsamples, unsigned long fftsize, long lowfreq, long highfreq, long srate)
{
    static double *inbuf=NULL;
    static double *realn=NULL;
    static double *imags=NULL;
    static double *spectr=NULL;
    static double *zer0=NULL;
    static double *olds=NULL;
    static double *infader=NULL;
    static double *outfader=NULL;
    int notched=(highfreq<lowfreq) ? 1 : 0;
    long incounter=0;
    /* treble is the highest baseband frequency */
    /* bass the the lowest baseband frequency */
    /* this function is called twice per FFT block */
    long midcounter=0;
    long outcounter=0;
    long bass=lowfreq*(fftsize/(double)srate);
    long treble=(highfreq)*(fftsize/(double)srate);
    static long halffft=2;
    static long old_fftsize=0;
    static short first=1;
    if(first==1 || fftsize!=old_fftsize)
    {
        if(inbuf)
             free(inbuf);
        if(realn)
            free(realn);
        if(imags)
            free(imags);
        if(spectr)
            free(spectr);
        if(zer0)
            free(zer0);
        if(olds)
            free(olds);
        if(infader)
            free(infader);
        if(outfader)
            free(outfader);
        infader=(double*)malloc(fftsize*sizeof(double));
        outfader=(double*)malloc(fftsize*sizeof(double));
        inbuf=(double*)malloc(fftsize*sizeof(double));
        realn=(double*)malloc(fftsize*sizeof(double));
        imags=(double*)malloc(fftsize*sizeof(double));
        spectr=(double*)malloc(fftsize*sizeof(double));
        zer0=(double*)malloc(fftsize*sizeof(double));
        olds=(double*)malloc(fftsize*sizeof(double));
        if((!inbuf) || (!realn) ||(!imags) ||(!spectr)||(!zer0)||(!ol   ds))
        {
            printf("Not enough memory for FFT!\n");
                    exit(1);
        }
        halffft=fftsize/2;
        long infade=0;
        long outfade=halffft;
        for(infade=0;infade<halffft;infade++)
        {
            outfade--;
            outfader[infade]=(0.5 * cos((infade) *  M_PI/(double)(halffft))+0.5);
            infader[outfade]=outfader[infade];
        }
        first=0;
    }
    memset(realn,0,sizeof(double)*fftsize);
    for(incounter=0;incounter<halffft;incounter++)
    {
        inbuf[incounter]=inbuf[incounter+halffft];
    }
    for(incounter=0;incounter<halffft;incounter++)
    {
        inbuf[incounter+halffft]=insamples[incounter];
    }
    for(incounter=0;incounter<fftsize;incounter++)
    {
        realn[incounter]=inbuf[incounter];
    }   
    memset(imags,0,sizeof(double)*fftsize);
    FFT(fftsize, 0, realn,imags, spectr,zer0);
    memset(realn,0,sizeof(double)*fftsize);
    memset(imags,0,sizeof(double)*fftsize);
    if(notched==0)
    {
        for(midcounter=bass;midcounter<treble;midcounter++)
        {
            realn[midcounter]=spectr[midcounter] * 2.0;
            imags[midcounter]= zer0[midcounter] * 2.0;
        }
        if(bass==0)
            realn[0]=spectr[0];

    }
    else if(notched==1)
    {
        for(midcounter=0;midcounter<halffft;midcounter++)
        {
            if((midcounter<treble) ||(midcounter>bass))
            {
                realn[midcounter]=spectr[midcounter] * 2.0;
                imags[midcounter]= zer0[midcounter] * 2.0;
            }
        }
        if(bass==0)
        {
            realn[0]=0;
        }
        else
        {
            realn[0]=spectr[0];
        }
    }
    FFT(fftsize, 1, realn, imags,spectr,zer0);
    for(outcounter=0;outcounter<halffft;outcounter++)
    {
        outsamples[outcounter]=(((spectr[outcounter] )*infader[outcounter])+(olds[outcounter+halffft]*outfader[outcounter])) ;
    }
    for(outcounter=0;outcounter<fftsize;outcounter++)
    {
        olds[outcounter]=spectr[outcounter];
    }
    memset(spectr,0,fftsize*sizeof(double));
    memset(zer0,0,fftsize*sizeof(double));
    old_fftsize=fftsize;
}

signed short mainbandpass(signed short input, double lowcut, double highcut,long rate,long fftsize)
{
    double retvalue=0;
    static double *insamp=NULL;
    static double *outsamp=NULL;
    static int first=1;
    static int q=0;
    if(first==1)
    {
            insamp=(double*)malloc(fftsize * sizeof(double));
            outsamp=(double*)malloc(fftsize * sizeof(double));
            if(insamp==NULL || outsamp==NULL)
            {
                   printf("Not enough memory for FFT buffers.\n");
                   exit(1);
            }
        memset(insamp,0,fftsize * sizeof(double));
        memset(outsamp,0,fftsize * sizeof(double));
        first=0;
    }

    insamp[q]=input;
    retvalue=outsamp[q];
    if(retvalue> 32767)
        retvalue=32767;
    if(retvalue <-32768)
        retvalue=-32768;
    q++;
    if(q>(fftsize/2)-1)
    {
        mainfftBandPass(insamp,outsamp, fftsize, lowcut,highcut,rate);
        q=0;
    }
    return (signed short)retvalue;
}

Rufen Sie für jedes Sample des Eingangs-Audios den Hauptbandpass mit dem Eingangs-Sample und dem Frequenzbereich auf, den Sie in Lowcut und Highcut halten möchten. Wenn Lowcut größer als Highcut ist, ist das Ergebnis ein Band-Reject-Filter. Es findet eine zirkuläre Faltung statt, aber es wird keine Außerbandemissionen geben, was für Modems gut ist.

Brent Fisher
quelle