AnyMath 文档
Notebook

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

本演示示例将对线性频率调制(LFM)下的数字低通滤波器进行计算、仿真并在目标设备上运行。

简介

本示例的目标是根据给定参数设计一个低通滤波器。我们将使用Julia语言的DSP库进行计算。 我们将使用AnyMath模型,对通过线性频率调制获得的信号进行滤波器性能验证。从AnyMath模型生成代码后,将在Arduino调试板上实现信号滤波。

硬件部分

本示例使用 Arduino MEGA 2560 开发板。输出信号由第 9 号引脚生成。信号的数模转换通过 PWM 和低频 RC 滤波器实现。 PWM频率为62.5 kHz,RC滤波器的截止频率为14.185 kHz,滤波阶数为2。连接图如下所示。

pcb_lpf.png

RC电路参数: 。该电路链的输出端通过限流电阻 连接至3.5毫米音频输出插孔,用于将信号传输至扬声器。

模型描述

本示例中所述模型的功能部分是子系统FM ,该子系统生成占空比变量Duty 。该变量将在用户程序中传递给控制器的PWM模块,以生成模拟输出信号。

image.png

子系统FM 的内容描述了按公式 进行的线性频率调制。信号频率呈线性变化: 经过LPF 模块中的低通滤波器处理后,滤波后的信号 会被偏移并进行缩放。 这是为了正确且尽可能精确地生成PWM占空比所必需的。本例中PWM的分辨率仅为5位,但这足以实现较高的PWM频率。

image.png

PWM占空比由公式 确定。

需要注意的是,为了进一步节省目标设备的计算资源,信号频率的变化与仿真时间直接相关。 因此,在特定时刻,被调制信号的频率将同时超过奈奎斯特频率和采样频率。由此可见,为了正确呈现滤波器的处理结果,必须选择一个低于奈奎斯特频率的截止频率。

低通滤波器的计算

为了进行低通滤波,我们选择一个具有以下参数的椭圆滤波器:

  • 采样频率 - 2000 Hz(由此可得,奈奎斯特频率为 1000 Hz),
  • 截止频率 - 400 Hz,
  • 极点数 - 6,
  • 通带内特性不均匀度 - 1 dB,
  • 阻带衰减 - 60 dB。
In [ ]:
# 链接库
neededLibs = ["WAV", "DSP"]
for lib in neededLibs
    try
        eval(Meta.parse("using $lib"))
    catch ex
        Pkg.add(lib)
        eval(Meta.parse("using $lib"))
    end
end
In [ ]:
fs = 2000
fp = 400;
n = 6;
Rp = 1;
Rs = 60;

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

In [ ]:
methods(Lowpass)
Out[0]:
# 2 methods for type constructor:
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);

根据模型生成的数据,绘制输出变量的波形图——低通滤波器(FNCH)的输入和输出信号:LPF_inLPF_out 分别。

In [ ]:
using Plots
plotlyjs()
plot(data["LPF_in"].time, data["LPF_in"].value,
    label="在FNCH之前", 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")

将生成在指定目录中的文件引入用户程序chirp_lpf.ino 中。下载这些文件,并使用 Arduino IDE 将其上传至 Arduino MEGA

在 Arduino 上执行代码

在成功编译并将程序上传至目标设备后,将数字示波器连接至 RC 滤波器的输出端,并采集所生成信号的交变分量。

演示中使用了 Hantec DSO 数字示波器,将其连接至计算机并将数据输出至 DSO Analyzer 程序。

chirp_lpf.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 );

结论

在本示例中,我们探讨了处理PLC信号的数字椭圆低通滤波器的运行原理。无论是在仿真阶段还是在目标设备上运行时,计算得到的滤波器均符合预设参数。