我如何完成这个 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 中,我无法从其他变量中分辨出数组.我在 convulving 上想到的大部分内容都需要数组才能正常运行,因为它似乎是将一个值与另一个值相乘,所以我就是这样编码的。
我应该怎么做,我的代码是否还有其他错误?
此外,我可以将共振应用于此过滤器吗?
方法 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);
}
}
我一直在尝试编写 sinc 低通滤波器以用于 java 中的声波。
我一直在关注这段代码https://tomroelandts.com/articles/how-to-create-a-simple-low-pass-filter
然后我谈到了用滤波器输出对波形进行卷积的部分,并认为数组必须发生卷积,但是由于视线的代码在 python 中,我无法从其他变量中分辨出数组.我在 convulving 上想到的大部分内容都需要数组才能正常运行,因为它似乎是将一个值与另一个值相乘,所以我就是这样编码的。
我应该怎么做,我的代码是否还有其他错误?
此外,我可以将共振应用于此过滤器吗?
方法 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);
}
}