以西格玛-德尔塔模数转换器模型为例说明中央处理单元(CPU)的任务
本示例实现了西格玛-德尔塔模数转换器(Sigma-Delta ADC)模型——该类型采用德尔塔-西格玛调制方法,以实现模拟信号测量的高精度和高分辨率。 它广泛应用于各种需要高测量精度的领域,例如:音频、测量传感器等(模型 sigma_delta_adc.engee):
接下来,本示例将分析 Sigma-Delta ADC 在 Simulink 和 Engee 中的工作原理,并比较这两个开发环境中的运行结果。
首先需要加载库文件:
In [ ]:
Pkg.add(["Statistics", "CSV"])
In [ ]:
# 链接库
using Plots
using CSV
using DataFrames
using Statistics
plotlyjs();
运行在 Engee 开发环境中实现的模型。
In [ ]:
modelName = "sigma_delta_adc"
SDC_model = modelName in [m.name for m in engee.get_all_models()] ? engee.open( modelName ) : engee.load( "$(@__DIR__)/$(modelName).engee");
results = engee.run( modelName )
Out[0]:
模型输出可视化
In [ ]:
SD_ADC_res_t = results["SD_ADC"].time;
SD_ADC_res_d = results["SD_ADC"].value;
p_adc_da_sl = plot(SD_ADC_res_t, SD_ADC_res_d, legend = false) # 绘制图表
plot!(title = "Engee中的模拟结果", ylabel = "数字信号", xlabel="时间,c") # 坐标轴和图表标题的标注
Out[0]:
Simulink 中的仿真结果:
In [ ]:
using MATLAB # 连接 MATLAB 内核
mat"cd /user/start/examples/dsp/sigma_delta_adc"
mat"""
out = sim('sigma_delta_adc');
sig = getElement(out.yout,1);
$DA_times = sig.Values.Time;
$DA_values = sig.Values.Data;
"""; # 启动 Simulink
In [ ]:
p_adc_da_sl = plot(DA_times, DA_values, legend = false)
plot!(title = "Simulink中的仿真结果", ylabel = "数字信号", xlabel="时间,c")
Out[0]:
模型中使用了可变步长求解器。 需要“同步”信号。首先,将两条曲线叠加在一起:
In [ ]:
plot(SD_ADC_res_t ,SD_ADC_res_d, label = "Engee")
plot!(title = "模拟结果的比较")
plot!(DA_times, DA_values, label = "Simulink")
# plot!(label = ["Engee" "Simulink"])
plot!(legend = :outertopright,ylabel = "数字信号", xlabel="时间,c")
Out[0]:
找出两个向量与仿真时间的交点:
In [ ]:
# 1. 检查数组的长度是否一致
if length(SD_ADC_res_t) != length(SD_ADC_res_d)
error("SD_ADC_res_t 和 SD_ADC_res_d 的尺寸不一致!")
end
# 2. 将 DA_times/DA_values 截断至 SD_ADC_res_t 的长度(如有必要)
new_length = min(length(DA_times), length(SD_ADC_res_t))
DA_times = DA_times[1:new_length]
DA_values = DA_values[1:new_length];
# 3. 找出时间戳的交集
common_times = intersect(DA_times, SD_ADC_res_t)
if isempty(common_times)
error("DA_times 和 SD_ADC_res_t 之间没有匹配的时间戳!")
end
然后,需要获取这些交点的数值
In [ ]:
# 4. 查找匹配元素的索引(使用整数索引)
SD_ADC_d = collect(SD_ADC_res_d).value
SD_ADC_t = collect(SD_ADC_res_t).time
da_idx = findall(t -> t in common_times, DA_times)
sd_idx = findall(t -> t in common_times, SD_ADC_t)
# 5. 确保各索引在时间上相互对应
if !all(DA_times[da_idx] .== SD_ADC_t[sd_idx])
error("索引后时间戳不一致!")
end
# 6. 提取数据
sd_comp_t = DA_times[da_idx]
sd_comp_sl = DA_values[da_idx]
sd_comp_en = SD_ADC_d[sd_idx]
# 7. 检查结果
@assert length(sd_comp_t) == length(sd_comp_sl) == length(sd_comp_en) "输出数组的尺寸不一致!"
println("已成功处理 $(length(sd_comp_t)) 个重合点")
现在我们可以正确地比较 Simulink 和 Engee 的结果:
In [ ]:
adc_abs_tol = sd_comp_sl - sd_comp_en;
mean_adc_tol = abs(mean(adc_abs_tol));
adc_rel_tol = (sd_comp_sl - sd_comp_en)./sd_comp_sl;
mean_adc_tol_rel = abs(mean(filter(!isnan,adc_rel_tol)));
println("计算的平均绝对误差:", mean_adc_tol);
println("计算的平均相对误差,%:", abs(mean_adc_tol_rel*100));
In [ ]:
engee.close( modelName, force=true);
结论
综上所述,本例实现了 sigma-delta 模数转换器的模型。基于此例,可以得出以下几点结论:
- Engee 在精度上不逊于 Simulink
- Engee 支持使用 MOP,并且得益于庞大的模块库,我们能够实现丰富的模块功能。
- 此外,当Engee的功能不足时,我们可以在Engee内部调用MATLAB的功能