C++ 频率采样滤波器的实现

C++ 频率采样滤波器的实现,c++,signal-processing,C++,Signal Processing,首先,我对任何与DSP相关的东西都是相当陌生的,所以我可能会问一些非常奇怪或愚蠢的问题 注意:由于我太新,系统将不允许我发布mote-then链接。我决定在任何链接前添加一个-这样系统就不会将它们识别为链接,我也可以发布它们。不幸的是,这意味着您必须复制/通过才能访问该链接,对此表示抱歉 我目前正在编写一个应用程序,需要控制整个音频频谱。我选择了一个频率采样滤波器,因为在阅读了一些信息后,我认为它能够给我这种控制。我的实现包括一个梳状滤波器,在0-PI范围内为80个谐振器馈电,采样频率为4410

首先,我对任何与DSP相关的东西都是相当陌生的,所以我可能会问一些非常奇怪或愚蠢的问题

注意:由于我太新,系统将不允许我发布mote-then链接。我决定在任何链接前添加一个-这样系统就不会将它们识别为链接,我也可以发布它们。不幸的是,这意味着您必须复制/通过才能访问该链接,对此表示抱歉

我目前正在编写一个应用程序,需要控制整个音频频谱。我选择了一个频率采样滤波器,因为在阅读了一些信息后,我认为它能够给我这种控制。我的实现包括一个梳状滤波器,在0-PI范围内为80个谐振器馈电,采样频率为44100Hz

我现在得到以下脉冲响应:

当前Frequency响应如下所示:

我很抱歉以这种方式链接图像,但系统不允许我发布图像,因为我太新了,我也只允许2个链接,所以如果允许我这样做,我会在注释中添加代码链接

在这次运行中,我所有的过滤器系数都是1

我的结论是,在我希望每个峰值达到相同高度的地方,谐振器部分地相互抵消。 我似乎找不到纠正的办法,有人能帮我吗

编辑1: 我已经把最重要的函数放在这里了,我应该早点完成。我很乐意澄清任何可能不清楚的事情

//comb filter function
float filter::comb(buffer* x, float z, float input){
    //store the new input value in the buffer
    x->write(input);
    //calculate the output value according to Y[n] = X[n] - z * X[n-160] 
    return x->read(0)-(z*x->read(160));
}

//resonator function
float filter::resonator(buffer* res, float r, float w, float phi, float amp){
static int odd_even=1;
float result=0;

if(odd_even){
    odd_even=0;
    //if called odd times calculate result according to Y[n] = 2 * r * cos(phi) * y[n-1] - r^2 * y[n-1] + amp * w
    result=(2*r*cos(phi)*res->read(0))-(r*r*res->read(1))+(amp*w);
}
else{
    odd_even=1;
    //if called odd times calculate result according to Y[n] = 2 * r * cos(phi) * y[n-1] - r^2 * y[n-1] - amp * w
    result=(2*r*cos(phi)*res->read(0))-(r*r*res->read(1))-(amp*w);
}

//store result in buffer
res->write(result);

return result/SCALE;
}

//filter execute function
float filter::exec(float value){
    float w;
    float total=0;
    float temp=0;

    cout<<value<<"\t";
    //calculate the comb output
    w=comb(combX,0.886867188,value);
    for(int i=0;i<80;i++){
        temp=(resonator(&res[i],0.999,w,(((1.125+i*2.25)/180.0)*pi),getCoef(i)));
        total+=temp;
    }
    return total;
}
//梳状滤波器函数
浮点滤波器::梳状(缓冲器*x、浮点z、浮点输入){
//将新的输入值存储在缓冲区中
x->写入(输入);
//根据Y[n]=X[n]-z*X[n-160]计算输出值
返回x->read(0)-(z*x->read(160));
}
//谐振器功能
浮子滤波器::谐振器(缓冲器*res、浮子r、浮子w、浮子phi、浮子放大器){
静态int奇偶=1;
浮动结果=0;
if(奇偶){
奇偶=0;
//如果调用奇数次,则根据Y[n]=2*r*cos(φ)*Y[n-1]-r^2*Y[n-1]+amp*w计算结果
结果=(2*r*cos(phi)*res->read(0))-(r*r*res->read(1))+(amp*w);
}
否则{
奇偶=1;
//如果调用奇数次,则根据Y[n]=2*r*cos(φ)*Y[n-1]-r^2*Y[n-1]-amp*w计算结果
结果=(2*r*cos(phi)*res->read(0))-(r*r*res->read(1))-(amp*w);
}
//将结果存储在缓冲区中
res->write(结果);
返回结果/刻度;
}
//过滤器执行函数
浮点筛选器::exec(浮点值){
浮动w;
浮动总数=0;
浮动温度=0;

cout如果使用IIR滤波器作为谐振器,则它们不是线性相位,并且频率响应特性中的任何重叠都可能抵消或求和,这取决于重叠频率点处的相位响应


然而,正如Paul R所建议的,您应该单独测试每个滤波器,然后成对测试,以测量每个滤波器的增益,然后检查滤波器交叉点处发生的情况。

问题在于您没有对谐振器增益进行归一化。它们具有不同的非归一化增益,因为随着通带移动closer为0或pi时,两极移动得更近,因此通带中的能量注入开始激发两极

你需要计算出每个滤波器的带通增益(通过z变换计算其在通带中心的幅度响应),然后将其输出除以该值。快速返回包络计算得出乘法归一化因子为
(1-r)*sqrt(r^2-2.r.cos(2.phi)+1)
,但请检查


如果需要更多的细节,请告诉我。

在你需要做一些工作来缩小这个问题的时候,C++代码是可用的。这里没有人会花时间调试大量代码。我想基本问题很简单:我的结论(谐振器取消了)。有意义吗?如果有,我有什么选项来纠正它。好吧,我很困惑,你有160个长度为4的浮点缓冲区,你的exec函数会在每个循环中传递一个新的引用,所以你会将结果保存到初始位置,在循环的下一次传递中,你会使用一个新的引用,所以读取值总是返回0。你应该通过运行一个谐振器自己,看看你是否得到预期的脉冲响应/频率响应。如果正确,那么试着运行两个谐振器,等等。我将运行一些测试,稍后我会发布结果(一旦我做了测试),我添加了一些测试结果(和一些代码)对于最初的问题,我该如何应用归一化?我能把谐振器的输出乘以归一化因子吗?@Gurba:是的,或者是输入。但要小心,不要将写入缓冲区的内容乘以。谢谢!这似乎让我走了很长的路。你的建议似乎得出了6左右的值4倍太小了,我仍然忙于检查、微调、双重检查和三重检查,但它看起来确实不错,我想我现在已经得到了,今晚我将通过过滤器运行一些音频作为最后的测试,因为我现在不能这样做。昨晚没有时间做测试,我今晚会尝试做