如何使用带通滤波器正确实现均衡

Posted

技术标签:

【中文标题】如何使用带通滤波器正确实现均衡【英文标题】:How properly implement equalization using band pass filer 【发布时间】:2014-06-02 21:50:27 【问题描述】:

我正在研究均衡器并试图了解它应该如何工作。

请帮助理解我应该做什么。

我已经拥有的:

    C#

    传入的float[]缓冲区(来自CSCore库,可以用Nuget下载)

    一个已实现且可工作的带通滤波器 (http://www.earlevel.com/main/2011/01/02/biquad-formulas/)

    一个十频段均衡器 31,62...16000

    代码片段:

        var sampleFilters = new EqFilter[] 
        
            new EqFilter(sampleRate, 31, 0.24205482f, defaultGain),
            new EqFilter(sampleRate, 62, 0.11142862f, defaultGain),
            new EqFilter(sampleRate, 125, -0.013698578f, defaultGain),
            new EqFilter(sampleRate, 250, -0.40285712f, defaultGain),
            new EqFilter(sampleRate, 500, -0.27534246f, defaultGain),
            new EqFilter(sampleRate, 1000, -0.15479457f, defaultGain),
            new EqFilter(sampleRate, 2000, 0.071232915f, defaultGain),
            new EqFilter(sampleRate, 4000, 0.28904116f, defaultGain),
            new EqFilter(sampleRate, 8000, 0.45027387f, defaultGain),
            new EqFilter(sampleRate, 16000, 0.6036986f, defaultGain)
        ;
    

第三个参数是Q,第四个是增益但是带通滤波器不使用它。

        int read = base.Read(buffer, offset, count);

        for (int c = 0; c < WaveFormat.Channels; c++)
        
            for (int i = _sampleFilters.Count; i-- > 0; )
            
                _sampleFilters[i].Filters[c].Process(buffer, offset, read, c, WaveFormat.Channels);
            
        

        for (int n = offset; n < count; n++)
        
            buffer[n] = Math.Max(-1, Math.Min(buffer[n], 1));
        

        return read;
    

其中 Process 方法应用带通滤波器。

我试图理解我做错了什么,因为如果我尝试以这种方式应用过滤器,我就会有静默作为输出。如果想象一下过滤器对信号做了什么,这似乎是正确的。但是我应该如何正确应用它? 同时,如果我只应用一个频率滤波器(例如 31Hz),它就可以工作。

一位好人告诉我低通滤波器,我应该将它混入“干”信号。我试图在这里做同样的事情但失败了。我再次得到沉默作为输出。我试图保留输入缓冲区,然后为每个频率应用滤波器,并使用以下公式将其与输入混合:

结果 = X + Y - X*Y 其中 X = input[i] 和 Y = bandpassfiltered[i]

我想我也做错了什么。

还有一个大问题是如何处理负值?如果您尝试放置像微笑这样的波段,您会在中间水平以下拉几个波段并且具有负值。如何用 BPF 实现?

同时均衡器的频段改变 Q 是否正确?那么,如果拉上或拉下一个乐队,我会改变什么?如果不是Q应该怎么改?算不上收益,因为算法没有计算在内。

有人可以帮我理解这一切吗?我究竟做错了什么?我该怎么做?

如果不清楚,我很抱歉。如果需要,我会尽量澄清。

【问题讨论】:

【参考方案1】:

每个带通滤波器都会首先去除其通带以外频率中的所有能量。因此,将每个带通滤波器按顺序应用于同一信号将去除所有信号,因为通过一个带通滤波器的频率随后会被后续滤波器去除,而没有重叠的通带。

相反,您应该将每个带通滤波器应用于原始信号,然后求和结果。类似的东西(忽略通道和偏移量):

    // Input signal is in buffer[0] to buffer[buffer.length-1]
    // accumulator[] and buffer2[] are also pre-allocated to the same length as buffer[].

    // Initialize output accumulator to zero
    for (int i = 0; i < accumulator.length; ++i)  accumulator[i] = 0;
    // Apply each bandpass filter to copies of the original input
    for (int i = _sampleFilters.Count; i-- > 0; ) 
        // Make a copy of the input
        for (int j = 0; j < buffer.length; ++j)  buffer2[j] = buffer[j];
        // Apply this filter in-place
        _sampleFilters[i].Filters[c].Process(buffer2, buffer2.length);
        // Accumulate the result
        for (int j = 0; j < accumulator.length; ++j)
            accumulator[j] += buffer2[j]
    
    // Copy back into buffer for output
    for (int i = 0; i < buffer.length; ++i)  buffer[i] = accumulator[i];

相邻带通滤波器之间的重叠频率中的相位抵消会引起进一步的问题,但这应该可以帮助您入门。

我看到你们的一些带通滤波器有负 Q。这对我来说没有任何意义。此外,即使是正 Q 也小于 1,这听起来也不对。 Q 是中心频率/带宽;您希望带宽小于中心频率(否则滤波器会一直延伸到零频率),因此 Q 小于 2 是不寻常的。

关于不同频率增益的“负值”:我们通常会看到以 dB 或 20*log_10(gain) 为单位的均衡曲线,它可以是正值或负值。增益本身应该是非负的;将增益设置为零有效地消除了某个频率的所有能量,这会尽可能多地消除它。应用负增益不会消除能量,它只是翻转波形的极性。

您所说的“负值”(将电平拉到“中间以下”)实际上是一个小于 1(但大于零)的乘法增益值。如果我们以 dB 为单位来描述该增益,它将显示为负值。

【讨论】:

感谢您的回答。不幸的是,我无法将其标记为有用,因为我没有足够的声誉。 在您回答后,我将所有波段的 Q 值更改为 1(也根据 link 我不了解滤波器的增益。我应该如何处理计算值? 你能建议如何处理重叠吗?过滤器求和后有很多噪音。 对于增益:如果您有“微笑”配置文件(或其他一些 dB 值集,每个频道一个),将它们转换为线性增益,如 lin_gain_k = pow(10.0, db_gain_k/20.0 ),然后在添加到累加器时将滤波器 k 的输出乘以该 lin_gain_k(或将其设置为各个 EqFilter 对象中的 defaultGain)。

以上是关于如何使用带通滤波器正确实现均衡的主要内容,如果未能解决你的问题,请参考以下文章

如何实现由该等式给出的带通滤波器?

如何在实时信号的 FIR 带通滤波器中摆脱瞬态响应?

iOS 带通滤波器

使用 scipy.signal.lfilter 时,实现 Butterworth 带通滤波器遇到:“ValueError: object of too small depth for desired

计算机上所有音频的实时均衡器

快速将带通滤波器应用于浮点数组