【研发日记】Matlab/Simulink避坑指南(十一)——Delay周期Bug

文章目录

前言

背景介绍

问题描述

分析排查

解决方案

总结归纳


前言

见《研发日记,Matlab/Simulink避坑指南(六)------字节分割Bug

见《研发日记,Matlab/Simulink避坑指南(七)------数据溢出钳位Bug

见《研发日记,Matlab/Simulink避坑指南(八)------else if分支结构Bug

见《研发日记,Matlab/Simulink避坑指南(九)------可变数组应用Bug

见《【研发日记】Matlab/Simulink避坑指南(十)------移位溢出Bug

背景介绍

最近在一个项目中,使用Simulink写一段嵌入式代码,功能是把一个信号的当前值和上一周期的值都同时拿来使用。乍一看感觉挺简单,想着直接用一个Delay模块就能搞定了,但是就这么一个小应用让我栽了跟头,在整个工程中排查了几个小时才找到问题。下面就来分享一下这一小段个人经历。

一开始的模型搭建大概是下面这个样子:

问题描述

按照上述示例,预想应该可以正常运行,但是实际运行时却跟预想的不一样,示例如下:

我的系统运行周期是10ms,希望看到的是Out2输出一个慢10ms的信号,但是看到运行结果是慢了100ms。

分析排查

使用前段时间解锁的Debug技能《【研发日记】Matlab/Simulink技能解锁(一)------在Simulink编辑窗口Debug》,来调试一下上述模型,示例如下:

使用Step Forward单步运行,打上Signal Value Lable,可以看到Out2的输出值并不是每10ms都更新,而是累积运行10步后才更新,更新的数据是100ms前Out1的值。

这时候我们把模型的Sample Time打开,看到的结果是信号源模块和Delay模块居然都是100ms,示例如下:

信号源模块的100ms没有问题,但是Delay模块我是想让他10ms的,打开Delay模块的配置看到Sample Time设置的是-1,我们是想让他继承系统运行的10ms周期的,示例如下:

根据上述结果推测,Delay模块没有继承系统的10ms周期,而是继承了信号源模块的100ms周期,所以Out2的输出值输出值出现了错误,问题应该就出在这里。

解决方案

根据上面的分析,调整Delay模块的Sample Time,直接把它写成固定的10ms,示例如下:

重新运行程序,问题不再出现,Bug修复完工,示例如下:

至此,这个使用Delay模块做信号延迟的应用就算是没问题了,生的代码示例如下:

cpp 复制代码
#include "DelayPeriod.h"
#include "DelayPeriod_private.h"

/* Block signals (default storage) */
B_DelayPeriod_T DelayPeriod_B;

/* Block states (default storage) */
DW_DelayPeriod_T DelayPeriod_DW;

/* External outputs (root outports fed by signals with default storage) */
ExtY_DelayPeriod_T DelayPeriod_Y;

/* Real-time model */
static RT_MODEL_DelayPeriod_T DelayPeriod_M_;
RT_MODEL_DelayPeriod_T *const DelayPeriod_M = &DelayPeriod_M_;
static void rate_scheduler(void);

/*
 *   This function updates active task flag for each subrate.
 * The function is called at model base rate, hence the
 * generated code self-manages all its subrates.
 */
static void rate_scheduler(void)
{
  /* Compute which subrates run during the next base time step.  Subrates
   * are an integer multiple of the base rate counter.  Therefore, the subtask
   * counter is reset when it reaches its limit (zero means run).
   */
  (DelayPeriod_M->Timing.TaskCounters.TID[1])++;
  if ((DelayPeriod_M->Timing.TaskCounters.TID[1]) > 9) {/* Sample time: [0.1s, 0.0s] */
    DelayPeriod_M->Timing.TaskCounters.TID[1] = 0;
  }
}

real_T rt_urand_Upu32_Yd_f_pw_snf(uint32_T *u)
{
  uint32_T hi;
  uint32_T lo;

  /* Uniform random number generator (random number between 0 and 1)

     #define IA      16807                      magic multiplier = 7^5
     #define IM      2147483647                 modulus = 2^31-1
     #define IQ      127773                     IM div IA
     #define IR      2836                       IM modulo IA
     #define S       4.656612875245797e-10      reciprocal of 2^31-1
     test = IA * (seed % IQ) - IR * (seed/IQ)
     seed = test < 0 ? (test + IM) : test
     return (seed*S)
   */
  lo = *u % 127773U * 16807U;
  hi = *u / 127773U * 2836U;
  if (lo < hi) {
    *u = 2147483647U - (hi - lo);
  } else {
    *u = lo - hi;
  }

  return (real_T)*u * 4.6566128752457969E-10;
}

/* Model step function */
void DelayPeriod_step(void)
{
  /* Outport: '<Root>/Out2' incorporates:
   *  Delay: '<Root>/Delay'
   */
  DelayPeriod_Y.Out2 = DelayPeriod_DW.Delay_DSTATE;
  if (DelayPeriod_M->Timing.TaskCounters.TID[1] == 0) {
    /* UniformRandomNumber: '<Root>/Uniform Random Number' */
    DelayPeriod_B.UniformRandomNumber =
      DelayPeriod_DW.UniformRandomNumber_NextOutput;

    /* Outport: '<Root>/Out1' */
    DelayPeriod_Y.Out1 = DelayPeriod_B.UniformRandomNumber;

    /* Update for UniformRandomNumber: '<Root>/Uniform Random Number' */
    DelayPeriod_DW.UniformRandomNumber_NextOutput = rt_urand_Upu32_Yd_f_pw_snf
      (&DelayPeriod_DW.RandSeed) * 2.0 + -1.0;
  }

  /* Update for Delay: '<Root>/Delay' */
  DelayPeriod_DW.Delay_DSTATE = DelayPeriod_B.UniformRandomNumber;
  rate_scheduler();
}

总结归纳

那么这个代码调试过程,发现的问题可以积累下来这么几条小经验以供自己将来使用,也供广大网友参考:

1 、Delay模块对信号的延迟1个时间单位,这个时间长度的绝对值取决于Delay模块运行周期。比如它在模型顶层10ms运行一次,那么就是延时10ms。如果在使能子模块中100ms运行一次,那么就是延时100ms.

2 、各个模块中的Sample Time参数,如果写成固定值,那么系统运行时就会优先采用这个周期。如果写成-1,那么就是交给系统自动分配一个有继承关系的运行周期。

3 、除了上述自动分配的Sample Time,Matlab/Simulink中有很多处自动分配的功能,这种自动化功能大大地方便了我们的建模开发工作,但是引入了很多不确定性。所以如果我们对一些自动分配的规则没有熟练掌握时,还是要尽量自己手动开发。

以上就是本人在解决Delay模块周期Bug时,一些个人理解和分析的总结,首先介绍了基本的项目背景,然后描述了问题的想象,最后分析排查了Bug原因,并给出了问题解决方案。

后续还会分享其他的,使用Matlab/Simulink进行研发时遇到的Bug,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。

上述例程使用的Demo工程,可以到笔者的主页查找和下载。


版权声明:原创文章,转载请注明出处与链接,违者必究!

相关推荐
肥仔哥哥19302 天前
嵌入式软件、系统、RTOS(高软23)
嵌入式·嵌入式系统·嵌入式软件·嵌入式系统分类·高软嵌入式
嘿嘿嘿x314 天前
联合体(union)
网络·单片机·嵌入式软件
charlie11451419115 天前
从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(绘图设备封装)
c语言·stm32·单片机·学习·oled·嵌入式软件
charlie11451419116 天前
从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(OLED设备层封装)
c语言·stm32·单片机·教程·oled·嵌入式软件
charlie11451419117 天前
从0开始使用面对对象C语言搭建一个基于OLED的图形显示框架(基础图形库实现)
c语言·驱动开发·笔记·单片机·oled·嵌入式软件
黄金右肾1 个月前
STM32之CubeMX图形化工具开发介绍(十七)
stm32·cubemx·嵌入式软件
黄金右肾1 个月前
STM32网络通讯之LWIP下载移植项目设计(十六)
stm32·嵌入式软件·网络通讯·lwip移植
一只搬砖的猹1 个月前
项目实战——使用python脚本完成指定OTA或者其他功能的自动化断电上电测试
linux·单片机·嵌入式硬件·python自动化·rtos·嵌入式软件·ota
m0_726965981 个月前
Harmony开发【笔记1】报错解决(字段名写错了。。)
笔记·bug·debug·harmonyos
黄金右肾1 个月前
STM32之CAN通讯(十一)
stm32·单片机·can·嵌入式软件