我如何完成这个 sinc 低通滤波器的编写

How do I finish writing this sinc low pass filter

我一直在尝试编写 sinc 低通滤波器以用于 java 中的声波。

我一直在关注这段代码https://tomroelandts.com/articles/how-to-create-a-simple-low-pass-filter

然后我谈到了用滤波器输出对波形进行卷积的部分,并认为数组必须发生卷积,但是由于视线的代码在 python 中,我无法从其他变量中分辨出数组.我在 convul​​ving 上想到的大部分内容都需要数组才能正常运行,因为它似乎是将一个值与另一个值相乘,所以我就是这样编码的。

我应该怎么做,我的代码是否还有其他错误?

此外,我可以将共振应用于此过滤器吗?

方法 lowPass(double point) 用于采样,对其进行低通滤波并 return 它。

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package effects;

/**
 *
 * @author Edward Jenkins
 */
public class SincLowPassFilter {
    
    public static final double DEF_BAND = 0;
    
    // instance variables
    private double cutoffFrequency;
    private double resonance;
    private double sampleRate;
    private double value;
    private double sumnatedValue;
    private double cutoffAmount;
    private double resonanceAmount;
    private double transitionBand;
    private double window;
    private int n;
    private int index;
    
    // constructor
    public SincLowPassFilter(double cutoffFrequency, double resonance, 
            double sampleRate, double band) {
        this.cutoffFrequency = cutoffFrequency;
        cutoffAmount = cutoffFrequency / sampleRate;
        transitionBand = band / sampleRate;
        
        n = (int)Math.ceil(4 / transitionBand);
        if (!(n % 2 == 2)) {
            n += 1;
        }
        sumnatedValue = 0;
        
        for(int i = 0; i < n; i++) {
            value = sinc(2 * cutoffAmount * (i - (n - 1) / 2));
            
            window = 0.42 - 0.5 * Math.cos(2 * Math.PI * i / (n - 1) 
                     / 0.08 * Math.cos(4 * Math.PI * i / (n - 1)));
            
            value = value * window;
            
            sumnatedValue += value;
            value = value / sumnatedValue;
        }
    }
    
    // low pass filter
    public double lowPass(double point) {
        
        return point * value;
    }
    
    // sinc
    private double sinc(double value) {
        return Math.sin(Math.PI * value) / Math.PI * value;
    }
}

感谢堆栈交换的人们,我最终得到了这个。但是这个用了一个子class来实现

超级class:

package filters;

import sound.generator.waveforms.SamplePlayer;
import sound.generator.waveforms.ISamplePlayer;

/**
 *
 * @author Edward Jenkins
 * @version 1.2
 */
public abstract class SincSpecs implements ISimpleFilter{
    
    // instance variables
    private double cutoffFrequency;
    private double sampleRate;
    private double resonance;
    private boolean highPass;
    private double value;
    private double sumnatedValue;
    private double cutoffAmount;
    private double transitionBand;
    private double window;
    private double[] impulseResponce;
    private double[] sampleCache;
    private int sampleCacheLength;
    private int n;
    private int order;
    private int midPoint;
    //private int index;
    
    // constructor for audio sample
    public SincSpecs(double cutoffFrequency, double sampleRate, byte resonance,
            boolean highPass, int band, SamplePlayer sample) {
        this.cutoffFrequency = cutoffFrequency;
        this.resonance = (double)resonance / 127;
        this.highPass = highPass;
        this.sampleRate = sampleRate;
        
        if (highPass) {
            this.cutoffFrequency += band / 2;
        } else {
            this.cutoffFrequency -= band / 2;
        }
        
        cutoffAmount = this.cutoffFrequency  / this.sampleRate;
        transitionBand = band / sampleRate;
        //index = 0;
        
        n = (int)(Math.ceil(4 / transitionBand));
        
        // make sure length is odd
        if (n % 2 == 0) {
            n += 1;
        }
        order = n;
        midPoint = order / 2 + 1;
        impulseResponce = new double[n];
        sumnatedValue = 0;

        updateImpulseResponce();

        sampleCache = new double[n];
        sampleCacheLength = 0;

        double inputPoint;

        while (!canOutput()) {
            inputPoint = sample.getNextPoint(); // get next sample point
            inputFilterPoint(inputPoint);
        }
    }
    
    // constructor for interface
    public SincSpecs(double cutoffFrequency, double sampleRate, byte resonance,
            boolean highPass, int band, ISamplePlayer sample) {
        this.cutoffFrequency = cutoffFrequency;
        this.resonance = (double)resonance / 127;
        this.highPass = highPass;
        this.sampleRate = sampleRate;
        
        if (highPass) {
            this.cutoffFrequency -= band / 2;
        } else {
            this.cutoffFrequency += band / 2;
        }
        
        cutoffAmount = cutoffFrequency  / this.sampleRate;
        transitionBand = band / sampleRate;
        //index = 0;

        
        n = (int)(Math.ceil(4 / transitionBand));
        
        // make sure length is odd
        if (n % 2 == 0) {
            n += 1;
        }
        order = n;
        midPoint = order / 2 + 1;
        impulseResponce = new double[n];
        sumnatedValue = 0;

        updateImpulseResponce();

        sampleCache = new double[n];
        sampleCacheLength = 0;

        double inputPoint;

        while (!canOutput()) {
            inputPoint = sample.generateWaveformPoint(); // get next waveform point
            inputFilterPoint(inputPoint);
        }
    }
    
    public double getTransitionBand() {
        return transitionBand;
    }
    
    @Override
    public void setCutoff(double cutoffFrequency) {
        
        this.cutoffFrequency = cutoffFrequency;
        cutoffAmount = this.cutoffFrequency / sampleRate;
        updateImpulseResponce();
    }
    
    public void updateImpulseResponce() {
        
        // get window of filtering
        for (int i = 0; i < n; i++) {
            
            impulseResponce[i] = cutoffAmount 
                    * sinc(2 * cutoffAmount * Math.PI * (i - midPoint));
            
            impulseResponce[midPoint] = cutoffAmount;

            window = 0.54 - 0.46 * Math.cos(2 * Math.PI * i / order);
            
            impulseResponce[i] *= window;
        }
        
        // sumnate all filter kernal values
        double sum = 0;
        
        for (int i = 0; i < n; i++) {    
            sum += impulseResponce[i];
        }
        
        for (int i = 0; i < n; i++) {    
            impulseResponce[i] /= sum;
        }
        
        // invert the impulse responce if high pass is true
        if (this.highPass) {
            invertImpulseForHighPass();
        }
    }
    
    // input points
    protected void inputFilterPoint(double point) {

        sampleCache[sampleCacheLength] = point;
        sampleCacheLength++;

        for (int i = 0, j = n - 1; i < n; i++, j--) {
            value += sampleCache[j] * impulseResponce[i];
        }
    }

    protected void incrementCache(double value) {

        for (int i = 0; i < sampleCacheLength - 1; i++) {
            sampleCache[i] = sampleCache[i + 1];
        }
        sampleCache[sampleCacheLength - 1] = value;
    }

    // can output
    protected boolean canOutput() {
        boolean result = false;

        if (sampleCacheLength == n) {
            result = true;
        }

        return result;
    }

    // sinc
    protected double sinc(double value) {
        if (value == 0) {
            value = 1;
        } else {
            value = Math.sin(value) / (value) + resonance *  Math.sin(value);
        }
        return value;
    }

    protected void invertImpulseForHighPass() {

        for (int i = 0; i < impulseResponce.length; i++) {
            impulseResponce[i] *= -1;
        }
        impulseResponce[midPoint] += 1;
    }

    @Override
    public double filter(double point) {

        //index++;
        
        value = 0;

        for (int i = 0, j = n - 1; i < n; i++, j--) {
            value += sampleCache[j] * impulseResponce[i];
        }
        incrementCache(point);
        
        /*if (index == n) {
            index = 0;
        }*/

        return value;
    }
}

子class:

package filters;

import sound.generator.waveforms.ISamplePlayer;

/**
 *
 * @author Edward Jenkins
 */
public class SincFilter extends SincSpecs {

    // constants
    public static final byte DEF_RESONANCE = 0;
    public static final int DEF_BAND = 400;

    // constructor
    public SincFilter(double cutoffFrequency, double sampleRate, byte resonance,
            boolean highPass, int band, ISamplePlayer sample) {
        super(cutoffFrequency, sampleRate, (byte)resonance, highPass,
                band, sample);
    }

    // three args constructor
    public SincFilter(double cutoffFrequency, double sampleRate, byte resonance,
            boolean highPass, ISamplePlayer sample) {
        this(cutoffFrequency, sampleRate, resonance, highPass, DEF_BAND, sample);
    }

    // two args constructor
    public SincFilter(double cutoffFrequency, double sampleRate, 
            ISamplePlayer sample) {
        this(cutoffFrequency, sampleRate, DEF_RESONANCE, false, sample);
    }
        
    @Override
    public void setCutoff(double cutoffFrequency) {
        super.setCutoff(cutoffFrequency + getTransitionBand() / 2);
    }
}