如何使用带通滤波器正确实现均衡
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)。以上是关于如何使用带通滤波器正确实现均衡的主要内容,如果未能解决你的问题,请参考以下文章
使用 scipy.signal.lfilter 时,实现 Butterworth 带通滤波器遇到:“ValueError: object of too small depth for desired