为什么用Java编写的这个递归峰值过滤器不会过滤选定的频率

时间:2017-06-03 05:09:36

标签: java audio filtering

所以,我不知道我是否错误地实现了这个,或者它是否是这种过滤器的一个特征;但是,我一直在尝试对音频信号应用峰值滤波器,但它并没有工作。 一些测试显示它没有过滤我选择的频率;但附近的值,其中一些是2的幂,因此,例如,过滤4KHz实际上过滤4096Hz。 这是过滤器(它来自http://dspguide.com/ch19/3.htm): SAMPLE_RATE是88 * 1024

        class Coefficients {
        double a0=0;    
        double a1=0;    
        double a2=0;    
        double twoCos2piFreq=0;    
        double b1=0;            
        double b2=0;            
        double K=0;             
        double R=0;             
        double rSquared=0;

        public Coefficients(double freq, double bandwidth)
        {
            twoCos2piFreq=2*Math.cos(2*Math.PI*freq);
            R=1-(3*bandwidth);
            rSquared=R*R;
            K=(1-(R*twoCos2piFreq)+rSquared)/(2-twoCos2piFreq);
            b1=R*twoCos2piFreq;
            b2=-rSquared;
        }
        // ----------------------------------------------------------------
        // Source x, result y
        // y[i]=a0*x[i] + a1*x[i-1] + a2*x[i-2] + b1*y[i-1] + b2*y[i-2]
        private void recursiveFilter(float[] x, float[] y)
        {
        double x_2 = 0.0f;                    // delayed x, y samples
        double x_1 = 0.0f;
        double y_2 = 0.0f;
        double y_1 = 0.0f;

            for (int i = 0; i < x.length; ++i){
                double xi=x[i];
                double yi=a0*xi + a1*x_1 + a2*x_2 + b1*y_1 + b2*y_2;
                x_2 = x_1;                              // shift delayed x, y samples
                y_2 = y_1;
                x_1 = xi;
                y_1 = yi;
                y[i] = (float)yi;
            }
        }
        // ------------------------------------------------------------
        public float[] filtered(float[] signal)
        {
            float[] result=new float[signal.length];
            recursiveFilter(signal,result);
            return result;
        }
    }
        // ----------------------------------------------------------------
    class BandPassCoefficients extends Coefficients 
    {
        public BandPassCoefficients(double freq, double bandwidth)
        {
            super(freq/(double)SAMPLE_RATE,bandwidth/(double)SAMPLE_RATE);
            a0=1-K;
            a1=(K-R)*twoCos2piFreq;
            a2=rSquared-K;
        }
    }

为了测试它,我用一个频率范围的正弦波填充缓冲区,一次一个,应用滤波器并测量结果中的最高振幅。 相当明显的代码,但在这里:

        // ----------------------------------------------------------------
    private void genTestSignal(float freq)
    {
        float[]  leftSignal=createSinWaveBuffer(freq,ONE_SECOND);
        float[] rightSignal=createSinWaveBuffer(freq,ONE_SECOND);
        denormalise( leftSignal ,inputSignal, LEFT_CHANNEL);
        denormalise(rightSignal,inputSignal,RIGHT_CHANNEL);
    }

denormalise和normalize函数只是将交错的带符号16位值转换为单通道浮点数。 这样可以对信号的开始进行采样,以找到最大的绝对值:

        private void findOptimalFreq(float[] signal, float freq)
    {
        float maxAmplitude=0;
        int peak=0;
        for(int i=(int)freq/2; i<(int)freq*3/2; i+=2){
            BandPassCoefficients signalFilter=new BandPassCoefficients(i,10);
            float[] normalised=signalFilter.filtered(signal);
            float loudest=0;
            // only scan the first part, since it's all the same
            for(int j=1; j<10000; ++j){
                float s=Math.abs(normalised[j]);
                if(s>loudest) loudest=s;
            }
            if(loudest>maxAmplitude){
                maxAmplitude=loudest;
                peak=i;
            }
        }
        log("freq,"+freq+","+peak);
    }

并且,为了完成,跨越音频范围的代码,测试每个频率。

                for(workingFreq=100; workingFreq<20000; workingFreq+=100){
                genTestSignal(workingFreq);
                inputShorts=new short[inputSignal.length/2];
                ByteBuffer.wrap(inputSignal).order(bigEndian ? ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN).asShortBuffer().get(inputShorts);
                findOptimalFreq(normalised(inputShorts,RIGHT_CHANNEL),workingFreq);
            }

输出记录到System.out,并复制到电子表格,因为它是CSV格式。 其中一部分,左边是目标频率,右边是峰值的实际频率:

6200,6436
6300,6436
6400,6436
6500,6932
6600,6932
6700,6932
6800,6932
6900,6932
7000,7510
7100,7510
7200,7510
7300,7510
7400,7510
7500,7510
7600,8192
7700,8192
7800,8192
7900,8192
8000,8192
8100,8192
8200,9012
8300,9012

有什么想法? 我一遍又一遍地浏览过滤器代码,我确信它是正确的;但是,我在任何地方都没有提及过这种&#34;功能&#34;,所以我不知道下一步该怎么做。

1 个答案:

答案 0 :(得分:0)

没有解决问题;但是能够用这个站点的BiQuadratic过滤器替换它:BiQuadDesigner

指向java source的链接:

HTH其他任何人都在努力解决这个问题。