从2019年12月27到2020年2月12日,学习了Simulink仿真及代码生成技术入门到精通,历时17天。

学习的比较粗糙,有一些地方还没理解透彻,全书梳理总结:

  • Simulink的基础模块已基本掌握,对不熟悉的模块可以借助帮助文档了解其功能;
  • Simulink信号基本掌握,了解了各种信号的外观及意义的不同;
  • 对Simulink子系统的认识有待深入,对原子子系统需要进一步熟悉;
  • 对仿真过程及参数配置有所了解,对Debugger的应用不太熟悉;
  • 对回调函数有所认识,能够简单应用到参数预加载等场合;
  • 关于M语言对Simulink的操作有待进一步熟悉;
  • Simulink流控制有待进一步熟悉;
  • S函数掌握得不好;
  • 对模块的封装有所认识,能够应用到子系统外观绘制等场合;
  • 自定义库、自定义环境估计暂且用不到;
  • 对代码生成前的配置有了一定的认识,对各种优化代码生成的技巧需要进一步练习;
  • 对TLC语言有初步的入门。

在学习过程中一直采用打字记录的方法,其间一周由QQ拼音统计的结果如下,好处在于在仔细地输入过程中对书中内容有了更多的思考时间,对参数配置都过了一遍,而不是走马观花,以后用到之时即使记不起具体内容,应该也会记得我在哪里曾经输入过,方便回来查找。坏处在于花费了较多时间,且博客照搬书中文字,缺少自己的思考和创新,在以后的学习中,应该简要记录重点内容,加之自己的思考和描述。

全书共19章,最后一章由于没有下载到相应的库和工具,暂且放过。其他1~18章链接如下。在打字过程中难免疏漏,存在一些错误,希望日后查阅时能够逐步改正,如果这些博客有幸为其他小伙伴所浏览,也欢迎评论指出错误之处。

Simulink仿真入门到精通(一) Simulink界面介绍

Simulink仿真入门到精通(二) Simulink模块

Simulink仿真入门到精通(三) Simulink信号

Simulink仿真入门到精通(四) Simulink子系统

Simulink仿真入门到精通(五) Simulink模型的仿真

Simulink仿真入门到精通(六) Simulink模型保存为图片

Simulink仿真入门到精通(七) Simulink的回调函数

Simulink仿真入门到精通(八) M语言对Simulink模型的自动化操作及配置

Simulink仿真入门到精通(九) Simulink的流控制

Simulink仿真入门到精通(十) S函数

Simulink仿真入门到精通(十一) 模块的封装

Simulink仿真入门到精通(十二) Publish发布M文件

Simulink仿真入门到精通(十三) Simulink创建自定义库

Simulink仿真入门到精通(十四) Simulink自定义环境

Simulink仿真入门到精通(十五) Simulink在流程工业中的仿真应用

Simulink仿真入门到精通(十六) Simulink基于模型设计的工业应用概述

Simulink仿真入门到精通(十七) Simulink代码生成技术详解

Simulink仿真入门到精通(十八) TLC语言

学完本书,决定完成一个代码生成的练习,以低通滤波器为例,以C51做载体,原因在于C51比较简单,资源较少,我比较熟悉,另外C51可以借助Keil、Proteus等工具方便地进行仿真,验证其正确性。

下面将介绍我的练习过程。

注:MATLAB版本2018a,Keil V5.24,Proteus8.6。

1. Simulink模型

1.1 模型外观

说明:

  • 为了配合C51的数据类型,输入输出均设置为uint16,故需要进行数据类型转换;
  • LPF(Low Pass Filter)内部结构及输出表达式如图所示;
  • 增益参数设为g,并在Model Properties→Callbacks→PreLoadFcn中设置回调函数为g=0.05;以便与在生成的代码中对增益进行修改;
  • 在Mask Editor的Icon drawing commands中添加一下绘图命令,绘制低通滤波器的大致形状,使模块美观。
num=1;
den=[1,1];
ts=tf(num,den);
P=bodeoptions;
[mag,~,w]=bode(ts,P);
w=reshape(w,1,length(w));
mag=reshape(mag,1,length(w));
dB=20*log10(mag);
w=log10(w);
plot(w,dB);

传递函数G(s)=1/(s+1),使用bode获取幅频特性并绘图。

补:本想选用DSP System Toolbox→Filtering→Filter Implementations中的Analog Filter Design作为低通滤波器。但此模块阶数(Order)较高时,计算比较复杂,可能导致C51的RAM空间不足,此处只是为了验证代码生成的过程,故选用比较简单的模型。

1.2 模型配置

Solver Type:Fixed-step

Solver:discrete(no continuous states)

生成嵌入式代码必须采用固定步长,由于没有连续环节,故可选用离散解算器。

Device:Intel

Device type:8051 Compatible

注:MATLAB2018a中没有此选项,但可以在低版本MATLAB中建立模型,选择此项,再将模型在2018a中打开即可。

System target file:ert.tlc

Language:C

Generate code only:√

Default parameter behavior:Tunable

Create code generation report:√

Open report automatically:√

生成报告并自动打开。

Generate an example main program:□

自己编写main主函数,不需生成示例。

其他参数保持默认。

1.3 模型仿真

在Simulink中建立如下模型。

输入信号由正弦信号和正态随机数叠加构成。

仿真时长30s,步长0.01s,得到仿真结果如下图所示。

可以看到,模型具有较好的滤波效果。

1.4 代码生成

配置好模型参数后,选定好工作目录,按下Ctrl+B,启动代码生成。

得到Report如下图。

在LPF_data中可以看到g的定义,在此处可进行修改。

LPF_step函数为核心函数。

void LPF_step(void)
{
real_T rtb_Add1;
real_T tmp; /* Sum: '<S1>/Add1' incorporates:
* DataTypeConversion: '<Root>/Data Type Conversion'
* Gain: '<S1>/Gain'
* Inport: '<Root>/In1'
* Sum: '<S1>/Add'
* UnitDelay: '<S1>/Unit Delay'
*/
rtb_Add1 = ((real_T)LPF_U.In1 - LPF_DW.UnitDelay_DSTATE) * LPF_P.g +
LPF_DW.UnitDelay_DSTATE; /* DataTypeConversion: '<Root>/Data Type Conversion1' */
tmp = floor(rtb_Add1);
if (rtIsNaN(tmp) || rtIsInf(tmp)) {
tmp = 0.0;
} else {
tmp = fmod(tmp, 65536.0);
} /* Outport: '<Root>/Out1' incorporates:
* DataTypeConversion: '<Root>/Data Type Conversion1'
*/
LPF_Y.Out1 = tmp < 0.0 ? (uint16_T)-(int16_T)(uint16_T)-tmp : (uint16_T)tmp; /* Update for UnitDelay: '<S1>/Unit Delay' */
LPF_DW.UnitDelay_DSTATE = rtb_Add1;
}

2. Proteus硬件连接

2.1 带噪声的正弦信号发生器

由于Proteus中没有直接产生白噪声的元件,在这里采用基于EPROM的波形发生方式。首先采用外部函数将白噪声数据写入txt文件,在转换为二进制数据加载到27256中,得到噪声信号。

比如我采用R语言生成这些数据,R代码如下。

#生成波形数据部分
noise<-rnorm(500,mean=36*3.5,sd=36)
noise<-round(noise)
noise_H<-as.character(as.hexmode(noise))
#写入文件部分
write.table(noise_H,file='C:/Users/lenovo/Desktop/noise_H.txt', row.names =FALSE,col.names =FALSE, quote =FALSE)

由于正态分布在3倍标准差范围内的概率已经达到99.74%,因此此处选3.5足够。得到数据文件如下:

利用从网上下载的转换工具进行转换:(感谢这位博主)

https://download.csdn.net/download/mouseleoz/10905646

即得到可加载的bin文件。

555定时器产生周期性信号,74LS161构成16进制计数器,噪声数据即在27256的D0到D7端口输出。

2.2 A/D转换

将上面的输入信号封装为子电路图,总电路图如下。

利用11通道12位串行A/D转换芯片TLC2543进行A/D转换,TLC2543引脚说明如下。

AIN0~AIN10为模拟输入通道。
CS为片选端,低电平有效。
DATA INPUT为串行数据输入端。
DATA OUT为A/D转换结果的三态串行输出端。
EOC为转换结束端。
I/O CLK为I/O时钟端。
REF+为正基准电压端。
REF-为负基准电压端。
VCC为电源端。
GND为地。

2.3 D/A转换

利用DAC0832进行D/A转化,由于0832是8位D/A转换器,因此损失了部分精度。

DAC0832引脚功能说明:
DI0~DI7:数据输入线,TTL电平。
ILE:数据锁存允许控制信号输入线,高电平有效。
CS:片选信号输入线,低电平有效。
WR1:为输入寄存器的写选通信号。
XFER:数据传送控制信号输入线,低电平有效。
WR2:为DAC寄存器写选通输入线。
Iout1:电流输出线。当输入全为1时Iout1最大。
Iout2: 电流输出线。其值与Iout1之和为一常数。
Rfb:反馈信号输入线,芯片内部有反馈电阻。
Vcc:电源输入线 (+5v~+15v)。
Vref:基准电压输入线 (-10v~+10v)。
AGND:模拟地,摸拟信号和基准电源的参考地。
DGND:数字地,两种地线在基准电源处共地比较好。

3. Keil工程

3.1 main函数

#include<reg52.h>
#include "LPF.h"
#include "LPF_private.h"
#define uint unsigned int
#define uchar unsigned char
#define y P2
uint volt;
uchar addr;
sbit CLK=P1^;//定义时钟信号口
sbit DIN=P1^;//定义2543数据写入口
sbit DOUT=P1^;//定义2543数据读取口
sbit CS=P1^;//定义2543片选信号口
sbit P2_5=P2^; void read2543(uchar addr)
{
uint ad=;
uchar i;
CLK=;
CS=;//片选段,启动2543
addr<<=;//对地址位预处理
for(i=;i<;i++) //12个时钟走完,完成一次读取测量
{
if(DOUT==)
ad=ad|0x01;//单片机读取ad数据
DIN=addr&0x80;//2543读取测量地址位
CLK=;
;;;//很短的延时
CLK=;//产生下降沿,产生时钟信号
;;;
addr<<=;
ad<<=;//将数据移位准备下一位的读写
}
CS=;//关2543
ad>>=;
volt=ad;//取走转换结果
} void main()
{
addr=;
LPF_initialize();
TMOD=0x01;
TH0=0xD8;
TL0=0xF0;
TR0=;
EA=;
ET0=;
while()
{
read2543(addr);
}
}
void Timer0_ISR(void) interrupt
{
TH0=0xD8;
TL0=0xF0;
LPF_U.In1=volt;
LPF_step();
y=LPF_Y.Out1/; }

在while(1)中不断读取A/D转换结果,在定时器中固定步长执行LPF_step函数。定时器初值D8F0=55536=2^12-10000,故步长为0.01s。

由于读取的转换结果是12位数据,因此除以16转换为8位,同时损失了精度。

3.2 编译方法

将Simulink生成的.c和.h文件加入到工程下,启动编译。

编译无误即可得到hex文件,将其加载到单片机中,启动仿真,得到示波器结果如下所示。

可以看到,该电路完成了滤波任务。

4. 模型评价总结

该实例仅是为了练习Simulink生成代码的过程,实际效果并不理想,主要缺点有:

  • 中间经过A/D和D/A转换,损失了精度,得到的结果是离散的;
  • 算法导致输出比输入有一定的相位滞后。

如图,放大后即可看到其离散性,实际效果甚至不如一阶RC滤波器(有源或无源)。

在这个过程中对Proteus的总线创建、标号添加及子电路图绘制方法进行了回顾。

对C51的端口赋值方法进行了复习,#define y P2。

在建模过程中参考了以下网页,对这些博主表示感谢。

Simulink生成代码在C51中的用法:https://blog.csdn.net/weixin_41911709/article/details/90648818

TLC2543的用法:https://blog.csdn.net/nanfeibuyi/article/details/80564741

通过此练习,起码简单验证了Simulink生成C代码的可行性,其他学习有待以后深入。

总之,本书由浅入深,还是非常值得一读,错误也比较少,即使偶尔有拼写错误也不影响阅读。

我的模型文件打包如下:

链接:https://pan.baidu.com/s/1iedYzuQbcezU4_-fW2s6tw
提取码:k3fj

Simulink仿真入门到精通(十九) 总结回顾&自我练习的更多相关文章

  1. Simulink仿真入门到精通(九) Simulink的流控制

    9.1 Simulink流控制分类 simulink中流控制时通过自带的模块实现的,包括If else.Switch.For和While4个种类. 9.2 While流控制 while 如果条件为真, ...

  2. Simulink仿真入门到精通(五) Simulink模型的仿真

    5.1 模型的配置仿真 由各种模块所构建的可视化逻辑连接,只是模型的外在表现,模型仿真的核心驱动器是被称作解算器(Solver)的组件,相当于Simulink仿真过程的心脏,驱动着模型仿真,它在每一个 ...

  3. Simulink仿真入门到精通(三) Simulink信号

    3.1 Simulink信号概述 所谓信号,表示一种随着时间而变化的量,在时间轴上的采样时刻都对应有数值. 信号在Simulink中是相当重要的组成部分,有线(line)表示,在模型中穿针引线地将各模 ...

  4. Simulink仿真入门到精通(十八) TLC语言

    TLC(Target Language Compiler)是一种为转换为目标语言而存在的额解释性语言,其目的就是将模型中编译出来的rtw文件转换为目标代码(C/C++等).与M语言类似,既可以写成脚本 ...

  5. Simulink仿真入门到精通(十六) Simulink基于模型设计的工业应用概述

    16.1 Simulink用途概述 在基于模型设计广泛应用于汽车电子嵌入式开发的今天,MBD(Model Besed Design)技术也逐步推广到各种嵌入式控制方面.与传统的嵌入式开发相比,BMD以 ...

  6. Simulink仿真入门到精通(十五) Simulink在流程工业中的仿真应用

    15.1 工业乙醇生产与计算机仿真 乙醇作为可再生清洁能源不仅可以代替四乙基铅作为汽油的防爆剂,还可以制造汽油醇.这一巨大的潜在需求促使人们去寻找提高乙醇工业生产率的途径,使人们着手于发酵工程的研究. ...

  7. Simulink仿真入门到精通(十四) Simulink自定义环境

    14.1 Simulink环境自定义功能 sl_sustomization.m函数是Simulink提供给用户使用MATLAB语言自定义Simulink标准人机界面的函数机制.若sl_sustomiz ...

  8. Simulink仿真入门到精通(十) S函数

    10.1 S函数概述 S函数也称为Simulink中的系统函数,是用来描述模块的Simulink宏函数,支持M.C等多种语言.当Simulink默认的模块不能满足用户的需求时,用户可以通过S函数自己打 ...

  9. Simulink仿真入门到精通(十二) Publish发布M文件

    12.1 M文件的注释 使用%进行注释. 连续多行注释Ctrl+R,取消注释Ctrl+T. 12.2 Cell模式 在MATLAB脚本文件中使用连续两个注释符,开启一个新的Cell块,%%后空一格追加 ...

随机推荐

  1. Docker 安装 CentOS

    Docker 安装 CentOS CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise ...

  2. MySQL 之全文索引

    最近在复习数据库索引部分,看到了 fulltext,也即全文索引,虽然全文索引在平时的业务中用到的不多,但是感觉它有点儿意思,所以花了点时间研究一下,特此记录. 引入概念通过数值比较.范围过滤等就可以 ...

  3. 推荐使用concurrent包中的Atomic类

        这是一个真实案例,曾经惹出硕大风波,故事的起因却很简单,就是需要实现一个简单的计数器,每次取值然后加1,于是就有了下面这段代码:           private int counter = ...

  4. 常见PHP安全网站漏洞及防范措施

    一:常见PHP安全网站漏洞 对于PHP的漏洞,目前常见的漏洞有五种.分别是Session文件漏洞.SQL注入漏洞.脚本命令执行漏洞.全局变量漏洞和文件漏洞.这里分别对这些漏洞进行简要的介绍. 1.se ...

  5. <USACO09FEB>庙会捷运Fair Shuttleの思路

    一个没有被我成功证明的 贪心 但是 ac了的 别人排序都是排终点.但我的排终点错了emm排起点才对qvq 有没有人友情看看怎么证(没有 #include<cstdio> #include& ...

  6. Dangling meta character '' near index 0

    1.replaceAll()方法报错 对字符串使用replaceAll()方法替换 * ? + / | 等字符的时候会报以下异常 Dangling meta character '*' near in ...

  7. TCP并发、GIL全局锁、多线程讨论

    TCP实现并发 #client客户端 import socket client = socket.socket() client.connect(('127.0.0.1',8080)) while T ...

  8. 多线程的join功能

    import threading import time def thread_job(): print("T1 start\n") for i in range(30): tim ...

  9. SpringBoot 处理 POST Json 传参枚举

    在 Spring 框架中对枚举类型的序列化/反序列化是有限制的. 假设如下面这样在某些情况下就不能正常工作: 123456789 public enum PayChannelEnum implemen ...

  10. [PyTorch入门之60分钟入门闪击战]之训练分类器

    训练分类器 目前为止,你已经知道如何定义神经网络.计算损失和更新网络的权重.现在你可能在想,那数据呢? What about data? 通常,当你需要处理图像.文本.音频或者视频数据时,你可以使用标 ...