二阶 IIR 滤波器,巴特沃斯带通 (EQ) 的系数?

Posted

技术标签:

【中文标题】二阶 IIR 滤波器,巴特沃斯带通 (EQ) 的系数?【英文标题】:2nd order IIR filter, coefficients for a butterworth bandpass (EQ)? 【发布时间】:2012-04-27 11:13:32 【问题描述】:

重要更新:我已经找到答案并将它们放在这个简单的开源库中:http://bartolsthoorn.github.com/NVDSP/ 看看,如果你有,它可能会为你节省很多时间ios中的音频过滤器有问题!

^

我创建了一个(实时)音频缓冲区 (float *data),其中包含几个不同频率的 sin(theta) 波。

下面的代码显示了我是如何创建缓冲区的,我尝试做一个带通滤波器,但它只是将信号变成噪声/光点:

    // Multiple signal generator
__block float *phases = nil;
[audioManager setOutputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels)

    float samplingRate = audioManager.samplingRate;
    NSUInteger activeSignalCount = [tones count];

    // Initialize phases
    if (phases == nil) 
        phases = new float[10];
        for(int z = 0; z <= 10; z++) 
            phases[z] = 0.0;
        
    

    // Multiple signals
    NSEnumerator * enumerator = [tones objectEnumerator];
    id frequency;
    UInt32 c = 0;
    while(frequency = [enumerator nextObject])
    
        for (int i=0; i < numFrames; ++i)
        
            for (int iChannel = 0; iChannel < numChannels; ++iChannel) 
            
                float theta = phases[c] * M_PI * 2;
                if (c == 0) 
                    data[i*numChannels + iChannel] = sin(theta);
                 else 
                    data[i*numChannels + iChannel] = data[i*numChannels + iChannel] + sin(theta);
                
            
            phases[c] += 1.0 / (samplingRate / [frequency floatValue]);
            if (phases[c] > 1.0) phases[c] = -1;
        
        c++;
    

    // Normalize data with active signal count
    float signalMulti = 1.0 / (float(activeSignalCount) * (sqrt(2.0)));
    vDSP_vsmul(data, 1, &signalMulti, data, 1, numFrames*numChannels);


    // Apply master volume
    float volume = masterVolumeSlider.value;
    vDSP_vsmul(data, 1, &volume, data, 1, numFrames*numChannels);


    if (fxSwitch.isOn) 
        // H(s) = (s/Q) / (s^2 + s/Q + 1)
        // http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt
        // BW 2.0  Q 0.667
        // http://www.rane.com/note170.html
        //The order of the coefficients are, B1, B2, A1, A2, B0.
        float Fs = samplingRate;

        float omega = 2*M_PI*Fs; // w0 = 2*pi*f0/Fs

        float Q = 0.50f;
        float alpha = sin(omega)/(2*Q); // sin(w0)/(2*Q)

        // Through H
        for (int i=0; i < numFrames; ++i)
        
            for (int iChannel = 0; iChannel < numChannels; ++iChannel) 
            
                data[i*numChannels + iChannel] = (data[i*numChannels + iChannel]/Q) / (pow(data[i*numChannels + iChannel],2) + data[i*numChannels + iChannel]/Q + 1);
            
        

        float b0 = alpha;
        float b1 = 0;
        float b2 = -alpha;
        float a0 = 1 + alpha;
        float a1 = -2*cos(omega);
        float a2 = 1 - alpha;

        float *coefficients = (float *) calloc(5, sizeof(float));


        coefficients[0] = b1;
        coefficients[1] = b2;
        coefficients[2] = a1;
        coefficients[3] = a2;
        coefficients[3] = b0;

        vDSP_deq22(data, 2, coefficients, data, 2, numFrames);

        free(coefficients);
    

    // Measure dB
    [self measureDB:data:numFrames:numChannels];
 ];

我的目标是为这个缓冲区做一个 10 波段的 EQ,使用vDSP_deq22,方法的语法是: vDSP_deq22(&lt;float *vDSP_A&gt;, &lt;vDSP_Stride vDSP_I&gt;, &lt;float *vDSP_B&gt;, &lt;float *vDSP_C&gt;, &lt;vDSP_Stride vDSP_K&gt;, &lt;vDSP_Length __vDSP_N&gt;) 见:http://developer.apple.com/library/mac/#documentation/Accelerate/Reference/vDSPRef/Reference/reference.html#//apple_ref/doc/c_ref/vDSP_deq22

参数:

float *vDSP_A is the input data
float *vDSP_B are 5 filter coefficients
float *vDSP_C is the output data

我必须制作 10 个过滤器(10 次 vDSP_deq22)。然后我为每个频段设置增益并将它们组合在一起。但是我为每个滤波器提供什么系数?我知道vDSP_deq22 是一个二阶(巴特沃斯)IIR 滤波器,但我如何将它变成带通滤波器?

现在我有三个问题:

a) 我必须对音频缓冲区进行去交错和交错吗?我知道将 stride 设置为 2 只是过滤通道,但我如何过滤另一个通道,stride 1 会将两个通道作为一个处理。

b) 我是否必须在缓冲区进入vDSP_deq22 方法之前对其进行转换/处理?如果是这样,我是否也必须将其恢复正常?

c) 我应该为 10 vDSP_deq22s 设置什么系数值?

我已经尝试了几天,但我无法弄清楚这个问题,请帮助我!

【问题讨论】:

【参考方案1】:

您的 omega 值需要标准化,即表示为 Fs 的一小部分 - 看起来您在计算 omega 时遗漏了 f0,这也会使 alpha 错误:

    float omega = 2*M_PI*Fs; // w0 = 2*pi*f0/Fs

应该是:

    float omega = 2*M_PI*f0/Fs; // w0 = 2*pi*f0/Fs

其中 f0 是以 Hz 为单位的中心频率。

对于您的 10 频段均衡器,您需要选择 10 个 f0 值,以对数间隔,例如25 赫兹、50 赫兹、100 赫兹、200 赫兹、400 赫兹、800 赫兹、1.6 赫兹、3.2 赫兹、6.4 赫兹、12.8 赫兹。

【讨论】:

谢谢,我应该设置什么Q值来覆盖所有频率? (Q 指的是我认为的波段宽度?)你认为我已经正确计算了带通的 a0..a2 和 b0..b2 值吗? 如果你要像上面那样为 f0 使用八度音程间距,那么我猜你需要大约 2 o 的 Q。其他计算看起来没问题。提示:首先让一个过滤器工作,具有标称 f0,例如400 Hz,然后继续使用完整的滤波器组。 谢谢,我还决定使用峰值(参数)均衡器而不是带通,我想我现在明白了。谢谢! 另外,我认为不需要通过H(s) = (s/Q) / (s^2 + s/Q + 1) 运行每个样本吗? (它也没有意义,只是猜测它是必需的)omega 的值已经被规范化了。 调用 vDSP_deq22 时使用的双二阶 IIR 滤波器是一个 2 极点、2 个零点、具有两个延迟元件的递归滤波器。简单的解释:通过将滤波器中的各种(延迟)项乘以各种系数并将它们相加,您得到一个通过某些频率并拒绝其他频率的滤波器。见:en.wikipedia.org/wiki/Digital_biquad_filter

以上是关于二阶 IIR 滤波器,巴特沃斯带通 (EQ) 的系数?的主要内容,如果未能解决你的问题,请参考以下文章

如何级联两个二阶巴特沃斯滤波器

深入浅出matplotlib(106):使用巴特沃斯滤波器进行带通滤波和带阻滤波

巴特沃斯滤波器

算法常用算法概览

设计一个巴特沃斯低通滤波器

DSP教程第43章 IIR滤波器的Matlab设计