首先,还是那句话:对于初学者来说,临摹是最好的学习路径。
临摹对象
官方自带的demo: 输入sf_cdplayer即可打开该模型。
(说明:MATLAB版本为R2016a)
该模型模拟的是一个CD/FM/AM播放机的处理流程。
仿真时会打开一个图形用户界面:
功能简介:
Radio Request按钮组中选择功能:播放CD、FM还是AM。
当选择播放CD时,需要先InsertDisc。然后可以选择功能:PLAY、REW、FF,也可以STOP。播放过程中如果EjectDisc,则停止播放。
模型解析:
顶层模型分为3个状态机和一个数据存储模块,以及6个显示模块。
模拟用户请求
第一个状态机是模拟用户请求。输出4个状态:Radio命令请求、CD命令请求,插入碟片,弹出碟片。
里面的流程是,每一个仿真步长取一次4个变量的值。
其中,RadioRequestMode和CdRequestMode是自定义的枚举类型。
RadioRequestMode类型定义在RadioRequestMode.m文件中,定义了四种功能:OFF、CD、FM、AM。
CdRequestMode类型定义在CdRequestMode.m文件中,定义了CD的不同状态。
这些文件都位于:<Matlabroot>\toolbox\stateflow\sfdemos。
取值的方法是,调用matlab的sfcdplayerhelper脚本。这个脚本作为GUI和Stateflow的桥梁,用于传递用户的操作信息到仿真模型中,并保存这些状态。
function result = sfcdplayerhelper(method,varargin)
persistent sRadioRequest;
persistent sCdRequest;
persistent sInsertDisc;
persistent sEjectDisc;
result = 0;
if(isempty(sCdRequest))
sCdRequest = double(CdRequestMode.STOP);
end
if(isempty(sRadioRequest))
sRadioRequest = double(RadioRequestMode.OFF);
end
if(isempty(sInsertDisc))
sInsertDisc = false;
end
if(isempty(sEjectDisc))
sEjectDisc = false;
end
switch(method)
case 'get_radio_request'
result = double(sRadioRequest);
case 'get_cd_request'
result = double(sCdRequest);
case 'set_radio_request'
sRadioRequest = varargin{1};
result = sRadioRequest;
case 'set_cd_request'
sCdRequest = varargin{1};
result = sCdRequest;
case 'set_insert_disc'
sInsertDisc = true;
result = sInsertDisc;
case 'get_insert_disc'
result = sInsertDisc;
if(sInsertDisc)
sInsertDisc = false; % toggle after the first access to mimic a trigger
end
case 'set_eject_disc'
sEjectDisc = true;
result = sEjectDisc;
case 'get_eject_disc'
result = sEjectDisc;
if(sEjectDisc)
sEjectDisc = false; % toggle after the first access to mimic a trigger
end
otherwise
error('Stateflow:DemoInternalError','Unknown method');
end
end
同样的,用户操作界面后传值的方法也是调用这个脚本。比如,播放碟片(InsertDisc)的回调函数为:
function InsertDisc_Callback(hObject, eventdata, handles)
sfcdplayerhelper('set_insert_disc');
播放机模式管理
CD行为模型
重要知识点
定义枚举变量
定义枚举型变量的好处是,显示模块可以直接显示信号的含义,而不是数字:
Matlab中枚举类型的定义是使用M文件定义的。
定义方式如下:
classdef
enumeration
end
end
Simulink中定义的枚举变量也是类,但是需要为所定义的枚举类型定义一个专有父类Simulink.IntEnumType,同时必须要给每个枚举元素进行值的指定,而不像C语言中是可以仅指定其中部分值。
例如:
classdef BasicColors < Simulink.IntEnumType
enumeration
Red(0)
Yellow(1)
Blue(2)
end
end
参考:
https://ww2.mathworks.cn/help/simulink/ug/using-enumerated-data-in-simulink-models.html
在simulink环境下使用枚举型数据时,要注意一下:
-
枚举类型数据的名称必须是唯一的,区分大小写,不能再workspace信号名称和数据类型名称有重复。
-
枚举值对应的数值必须是连续单调递增的,但是在定义的时候,对排序不做要求。
定义完成之后,在配置chart的input/output类型的数据时,也要指定正确的数据类型,并且前一个chart的输出和后一个chart的输入都是配置。
模型工作区中定义参数变量
弹出碟片1秒后状态由EJECT变为EMPTY:
这里的Ts为此Chart的一个Parameter类型的数据:
该数据是在模型工作区中定义并初始化的。
变量数据是否发生改变
CdPlayerModeManager中,使用了hasChanged运算符,来判断状态变量是否发生了改变。
相关功能:
更改类型 | 运算符 |
---|---|
从上一时间步开始到当前时间步开始,数据值发生更改。 |
请参阅hasChanged 运算符。 |
数据从上一时间步开始时指定的值更改为当前时间步开始时的另一个值。 |
|
数据从上一时间步开始时一个不同的值更改为当前时间步开始时的指定值。 |
请参阅hasChangedTo 运算符。 |
参考:检测数据值更改
https://ww2.mathworks.cn/help/stateflow/ug/detecting-changes-in-data-values.html
判断是否处于某个状态中
Play状态中使用了in运算符:
参考资料:
《Stateflow User's Guide.pdf》
Check State Activity by Using the in Operator