编写一个低通滤波器(Programming a low-pass filter)

2019-07-29 01:01发布

我已经设定在Java中的世嘉主系统仿真器(当然,这个问题是不是Java的具体)和已经完成的一切除了SN76489声音芯片。 如何该芯片使得声音是很容易 - 我的问题是,它转换成一种形式,通过PC /笔记本电脑/无论在JVM上运行的播放。

我已经确定的步骤如下:

由于SN76489在大约221khz的采样率运行 - 这意味着它具有输出高达110khz的频率波(虽然实际上我怀疑任何事情的任何进入这一高点)。 我需要因此实现低通滤波器之前,我下采样它。

那么我想这下采样到44.1kHz的,这样我就可以将其输出通过音频线(在我的情况下,一个Java源数据行)。

为此,我需要在22.05kHz时设置低通滤波器,但问题是我不知道(从数学上讲)低通滤波器实际上是如何工作的。 我需要这一点是为了能够写一个。

目前,我的声音芯片在这产生0.2第二缓冲器,并且存储样品,在221khz如上所述。 我可以进行下采样,我的理解这一点 - 但如果我下采样没有低通滤波器的第一施加,我明白,我可以潜在地获得混叠假信号所得到的声音流。

谁能推荐最简单的数学头脑的算法,这样做的 - 我知道,由于涉及的是一个低通从来都不是“精确”的变数,但我只需要被dummed上下足了我的大脑(这还没有真正完善的解释现在前),以了解处理的波处理。

如果有帮助,具体是:SN76489同时输出三个方波和一个噪声channnel。 这些被加在一起,并输出到混频器/放大器 - 此阶段在链中是我想我下采样之前运行的低通滤波器,然后放大该波。 任何帮助的人能给我是非常赞赏。 我意识到需要阅读的背景知识,但我想知道“是什么”我需要阅读。 非常感谢。

更新 :我想出了在最后一个简单的方法-仍然不能令人信服,但。 的SN76489的工作方式是从一个寄存器值生成各音调信道 - 的1的极性是输出,则该值递减,依此类推 - 直到该值为0,则该值被复位,极性切换为 - 1,等。 这个值然后由一个体积相乘以获取该样本的最终振幅,并与其他信道求和。

我现在简单地防止将产生一个方波高于奈奎斯特限制我从正在生产需要的寄存器值。 这给我留下了一个更好的信号,但它仍然有一些嗡嗡/在它弹出 - 不知道为什么作为最大可能的频率应18,473Hz。 会这样喀啦/嗡嗡是因为当芯片切换从一个频率信道到下一个,它不允许电流波形以完全完成? 作为一个例子,该芯片输出1111,然后00 - 而不是完整的四个零,并切换到一个新的工频突变 - 这可能导致混叠可以吗?

Answer 1:

编辑:我已经包括下面一个过滤器实现回答你的问题问的。 然而,在这样高的采样率实现具有信号高阶滤波器是要消耗很多很多每秒百万操作。 如果你第一次做芯片的输出的频谱分析,这可能是最好的。 如果有以上几kHz没有声音的能量,则抗混叠滤波器是处理资源的浪费。 即使有能量可达适度高的频率,它可能是值得第一抽取该信号,然后将所述第二级抽取之前滤波。 作为一个侧面说明,你可能还需要下降到抽取率要低得多44.1千赫。 你可能会被罚款与主系统仿真器的8位或10 kHz采样率(我们不是在这里谈论的Hi-Fi)。 但无论如何,要回答你关于如何实现与您指定的采样率和截止低通滤波器的问题。 。 。

好吧,首先设计一个低通滤波器。 MATLAB的抽取功能听起来不错,我的耳朵,所以我们会复制这个例子的做法。 文档说以下

所抽取的向量y的长度比输入矢量x较短r次。 缺省情况下,采用抽取的第八阶低通切比雪夫I型具有0.8 *(FS / 2)/ R的截止频率滤波。 它过滤输入序列在正向和反向方向上以除去所有的相位失真,有效地加倍滤波器的阶数。

Cheby过滤器是一个不错的选择,因为他们有一个陡峭的排斥比巴特沃斯设计在一点点通带纹波为代价的。 我们不能做在一个实时系统两个方向IIR滤波,但是这应该是确定你的目的。 我们可以用下面的Matlab代码使滤波器系数。 。 。 。

sr = 221e3;
srDesired = 44.1e3;
order = 8;
passBandRipple = 1; %//dB

Wp = 0.8 * (srDesired/2) / (sr/2);

[b,a] = cheby1 (order, passBandRipple, Wp, 'low');

freqz(b,a,[],sr, 'half');

sos = tf2sos(b,a)

这给了我们与像下面的响应的8阶IIR滤波器。 这看起来像我们所希望的。 相位响应是不重要的这种应用。 截止为0.8 * 22.050千赫,只要你想接近Nyquist极限的信号抽取之前得到很好的衰减。

在最后的tf2sos命令转换,我们刚刚创建成二阶节,你可以体会到使用双二阶滤波器部分的级联滤波器。 此命令的输出如下。 。 。

A节

B = 1.98795003258633e-07,3.97711540624783e-07,1.98854354149782e-07,
A = 1 -1.81843900641769,0.835282840946310

B节

B = 1,2.02501937393162,1.02534004997240,
a = 1时,-1.77945624664044,0.860871442492022

C节

B = 1,1.99938921206706,0.999702296645625,
a = 1时,-1.73415546937221,0.907015729252152

第d

B = 1,1.97498006006623,0.975285456788754,
a = 1时,-1.72600279649390,0.966884508765457

现在,你可以使用这些滤波器系数在过滤器级联每个双二阶阶段。 你可以体会到使用,如在下面的示例代码此过滤器。 这是C代码,但你应该能够将其转换成Java很容易地。 请注意,在下面的代码中没有A0系数。 第二阶段是否被正确规格化,因此A0总是等于1.刚离开它。

//Make the following vars private members of your filter class
// b0, b1, b2, a1, a2 calculated above
// m1, m2 are the memory locations
// dn is the de-denormal coeff (=1.0e-20f) 

void processBiquad(const float* in, float* out, unsigned length)
{
    for(unsigned i = 0; i < length; ++i)
    {
        register float w = in[i] - a1*m1 - a2*m2 + dn;
        out[i] = b1*m1 + b2*m2 + b0*w;
        m2 = m1; m1 = w;
    }
    dn = -dn;
}

你应该使一个类此过滤器,然后实例4单独的类(1对于每个过滤器),设置一个,和b值,以上述指定。 接下来,勾人级的输入到下一个的输出中给你你的级联。



Answer 2:

http://en.wikipedia.org/wiki/Butterworth_filter

C代码生成器: http://www-users.cs.york.ac.uk/~fisher/mkfilter/ (应该是翻译成Java很轻松了)



文章来源: Programming a low-pass filter