【研发日记】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工程,可以到笔者的主页查找和下载。


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

相关推荐
charlie1145141913 天前
嵌入式Linux入门具备:C语言基础与基本驱动学习(2):Linux GIibc IO基础
c语言·学习·c·io·嵌入式软件
ViatorSun7 天前
「图文详解」Pycharm 远程服务器Debug
python·深度学习·算法·pycharm·debug·1024程序员节
猫猫的小茶馆11 天前
【Linux系统】Ubuntu的简单操作
linux·ubuntu·嵌入式软件
OSnotes19 天前
嵌入式软件名企笔试真题文章汇总帖
嵌入式软件·笔试真题
网易独家音乐人Mike Zhou20 天前
【Linux驱动开发】通过ioremap虚拟内存映射的寄存器操作驱动、C应用函数库开发 devmem命令测试(正点原子STM32MP135文档BUG)
linux·c语言·驱动开发·stm32·mcu·嵌入式·嵌入式软件
tekin23 天前
图解 微信开发者工具 小程序源码 调试、断点标记方法 , 微信小程序调试器,真机调试断点调试方法,小程序网络API请求调试方法 总结
微信小程序·debug·调试·断点·真机调试·miniapp·网络api请求调试方法
电赛张小七24 天前
关于通信方式的一些自我学习(uart、i2c、spi的一些最底层的逻辑以及运用方式)STM32F407上的一些实际日常应用
c语言·开发语言·stm32·单片机·学习·嵌入式软件
云卷风舒1 个月前
Fedora40使用Timeshift恢复数据后无法启动(解决办法)
linux·debug·fedora
Qiming_v1 个月前
ValueError: You cannot perform fine-tuning on purely quantized models.
debug·peft
Gogeof1 个月前
云原生化 - 工具镜像(简约版)
微服务·云原生·debug·工具