Code generation for Arduino (linear frequency modulation with low pass filter)¶
This demo calculates, simulates and executes a digital low-pass filter for linear frequency modulation on a target device.
Introduction¶
The purpose of this example is to design a low-pass filter according to the given parameters. For its calculation we will use the DSP library of the Julia language. Let's check the operation of the filter in the Engee model on the signal obtained by linear frequency modulation. After generating the code from the Engee model, we will reproduce the filtering of the signal on the Arduino debugging board.
Hardware¶
The Arduino MEGA 2560 debug board is used in this example. The output signal is generated at output #9. The digital-to-analogue conversion of the signal is performed using a PWM and RC low-pass filter. PWM frequency is 62.5 kHz, RC-filter cut-off frequency is 14.185 kHz, filter order is 2. The wiring diagram is shown in the figure below.
RC circuit parameters: $R = 330 Ом ,\ C = 34 нФ$. A 3.5 mm audio output socket is connected to the output of the circuit via a current limiting resistor $R_д = 10 кОм$ to output the signal to the speaker.
Model description¶
The functional part of the model considered in this example is the subsystem FM
, which generates the variable Duty
. This variable will be passed in the user sketch to the PWM controller module to generate an analogue output signal.
The content of the subsystem FM
describes linear frequency modulation by the formula $y = sin(2\cdot\pi \cdot f \cdot t)$. The frequency of the signal changes linearly: $f = 50\cdot t$ After passing through the low-pass filter in the block LPF
the filtered signal $y_ф$ receives an offset and is scaled. This is necessary for correct and as accurate as possible generation of the PWM pulse width. The PWM resolution in this example is only 5 bits, but this allows a high PWM frequency to be achieved.
The PWM RMS is defined by the formula $Duty = 16\cdot (y_ф+1)$.
It should be noted that in order to further save computing power of the target device, the change of the signal frequency is directly related to the simulation time. Thus, the frequency of the modulated signal at a certain moment will exceed both the Nyquist frequency and the sampling frequency. Consequently, for correct representation of the filter results it is necessary to choose such a cut-off frequency, which will be lower than the Nyquist frequency.
Calculation of the low-pass filter¶
For low-pass filtering we choose an elliptic filter with parameters:
- sampling frequency - 2000 Hz (hence, Nyquist frequency - 1000 Hz),
- cut-off frequency - 400 Hz,
- number of poles - 6,
- non-uniformity of the characteristic in the passband - 1 dB,
- attenuation in the delay band - 60 dB.
Pkg.add(["WAV", "DSP"])
fs = 2000
fp = 400;
n = 6;
Rp = 1;
Rs = 60;
Let's calculate the coefficients of polynomials of numerator and denominator of the transfer function of the filter:
using DSP;
myfilt = digitalfilter(Lowpass(fp; fs), Elliptic(n, Rp, Rs));
b = coefb(myfilt);
a = coefa(myfilt);
Let's copy the obtained coefficients to the numerator and denominator of the block LPF
of the model.
Modelling results¶
Let's load and execute the created model:
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);
From the obtained data of the model, plot the output variables - the signal at the input and output of the LFD: LPF_in
and LPF_out
respectively.
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!("Значение")
As can be seen from the graph, the filter performs signal conversion according to the specified parameters.
Uploading code to Arduino¶
To upload to the Arduino you need to generate code from the subsystem FM
:
engee.generate_code( "$(@__DIR__)/chirp_lpf.engee",
"$(@__DIR__)/chirp_lpf_code";
subsystem_name="FM")
Let's connect the files generated in the specified directory in the user sketch chirp_lpf.ino
. Download these files and load them into Arduino MEGA using Arduino IDE.
Executing the code on Arduino¶
After successful compilation and loading the sketch into the target device, connect a digital oscilloscope to the output of the RC-filter and capture the variable component of the generated signal.
For demonstration we used a digital oscilloscope Hantec DSO with connection to a computer and data output to the DSO Analyzer software.
As can be seen, as the frequency of the sinusoidal signal increases after 400 Hz, there is a suppression of its amplitude. For better representation of the model operation with digital filter, a speaker was connected to the RC-chain output, and the obtained sound was recorded in the file chirp_lpf_audio.wav
. The next code cell allows you to load the received audio file into the script and play it. Play the audio track to make sure that the developed model and filter work.
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 );