Engee 文档
Notebook

为 Arduino 生成代码(带低通滤波器的线性频率调制)

该演示在目标设备上计算、模拟和执行用于线性频率调制的数字低通滤波器。

简介

本例的目的是根据给定参数设计一个低通滤波器。在计算过程中,我们将使用 Julia 语言的 DSP 库。让我们检查一下 Engee 模型中的滤波器在线性频率调制信号上的运行情况。根据 Engee 模型生成代码后,我们将在 Arduino 调试板上重现信号的滤波过程。

硬件

本例中使用的是 Arduino MEGA 2560 调试板。输出信号在 9 号输出端产生。使用 PWM 和 RC 低通滤波器对信号进行数模转换。PWM 频率为 62.5 kHz,RC 滤波器截止频率为 14.185 kHz,滤波器阶数为 2。接线图如下图所示。

pcb_lpf.png

RC 电路参数:$R = 330 Ом ,\ C = 34 нФ$ 。3.5 毫米音频输出插座通过限流电阻器连接到电路输出端$R_д = 10 кОм$ ,将信号输出到扬声器。

型号说明

本示例中模型的功能部分是子系统FM ,它生成变量Duty 。该变量将在用户草图中传递给 PWM 控制器模块,以产生模拟输出信号。

image.png

子系统FM 的内容通过公式$y = sin(2\cdot\pi \cdot f \cdot t)$ 描述了线性频率调制。信号的频率呈线性变化:$f = 50\cdot t$ 经过块LPF 中的低通滤波器后,滤波后的信号$y_ф$ 接收偏移量并进行缩放。这对于正确和尽可能精确地生成 PWM 脉宽是必要的。本例中的 PWM 分辨率仅为 5 位,但却能实现较高的 PWM 频率。

image.png

PWM 有效值的定义公式为$Duty = 16\cdot (y_ф+1)$ 。

需要注意的是,为了进一步节省目标设备的计算能力,信号频率的变化与模拟时间直接相关。因此,调制信号在某一时刻的频率会超过奈奎斯特频率和采样频率。因此,为了正确显示滤波器结果,有必要选择一个低于奈奎斯特频率的截止频率。

低通滤波器的计算

对于低通滤波器,我们选择参数为椭圆的滤波器:

  • 采样频率 - 2000 Hz(因此奈奎斯特频率 - 1000 Hz)、
  • 截止频率 - 400 Hz、
  • 极点数 - 6、
  • 通带特性的不均匀性 - 1 dB、
  • 延迟带衰减 - 60 dB。
In [ ]:
Pkg.add(["WAV", "DSP"])
In [ ]:
fs = 2000
fp = 400;
n = 6;
Rp = 1;
Rs = 60;

让我们来计算滤波器传递函数分子和分母的多项式系数:

In [ ]:
using DSP;
myfilt = digitalfilter(Lowpass(fp; fs), Elliptic(n, Rp, Rs));
b = coefb(myfilt);
a = coefa(myfilt);

将得到的系数复制到模型块LPF 的分子和分母中。

建模结果

让我们加载并执行创建的模型:

In [ ]:
if "chirp_lpf" in [m.name for m in engee.get_all_models()]
    m = engee.open( "chirp_lpf" );
else
    m = engee.load( "$(@__DIR__)/chirp_lpf.engee" );
end

data = engee.run(m);

根据模型获得的数据,绘制输出变量图--LFD 输入和输出端的信号:LPF_inLPF_out

In [ ]:
using Plots
plotlyjs()
plot(data["LPF_in"].time, data["LPF_in"].value,
    label="До ФНЧ", size=(900,300), lw=2, st=:step)
plot!(data["LPF_out"].time, data["LPF_out"].value,
    label="После ФНЧ", size=(900,300), lw=2, st=:step)
xlabel!("Время, сек")
ylabel!("Значение")
Out[0]:

从图中可以看出,滤波器根据指定参数执行信号转换。

将代码上传到 Arduino

要将代码上传到 Arduino,您需要从子系统FM 生成代码:

In [ ]:
engee.generate_code( "$(@__DIR__)/chirp_lpf.engee",
                     "$(@__DIR__)/chirp_lpf_code";
                     subsystem_name="FM")
[ Info: Generated code and artifacts: /user/start/examples/codegen/arduino_chirp_lpf/chirp_lpf_code

让我们将指定目录下生成的文件连接到用户草图中chirp_lpf.ino 。下载这些文件,并使用 Arduino IDE 将其加载到 Arduino MEGA 中。

在 Arduino 上执行代码

成功编译并将草图加载到目标设备后,将数字示波器连接到 RC 滤波器的输出端,捕捉生成信号的可变分量。

为了进行演示,我们使用了亨达 DSO* 数字示波器,该示波器与计算机相连,并将数据输出到 DSO Analyzer 软件。

chirp_lp.gif

可以看出,随着正弦信号频率在 400 Hz 之后的增加,其振幅也随之减弱。为了更好地呈现模型在数字滤波器作用下的运行情况,我们在 RC 链输出端连接了一个扬声器,并将获得的声音录制到chirp_lpf_audio.wav 文件中。下一个代码单元允许您将接收到的音频文件加载到脚本中并播放。播放音轨以确保开发的模型和滤波器正常工作。

In [ ]:
using WAV, Base64
x, fs = wavread( "$(@__DIR__)/chirp_lpf_audio.wav" );

buf = IOBuffer();
wavwrite(x, buf; Fs=fs);
data = base64encode(unsafe_string(pointer(buf.data), buf.size));
markup = """<audio controls="controls" {autoplay}>
              <source src="data:audio/wav;base64,$data" type="audio/wav" />
              Your browser does not support the audio element.
              </audio>"""
display( "text/html", markup );

输出

在本例中,我们考虑了处理低频调制信号的数字椭圆低通滤波器的运行。无论是在模拟中还是在目标设备上执行时,计算出的滤波器都符合指定参数。