当前位置:首页 » 《我的小黑屋》 » 正文

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

13 人参与  2024年05月08日 10:35  分类 : 《我的小黑屋》  评论

点击全文阅读


文章目录

前言

背景介绍

问题描述

分析排查

解决方案

总结归纳


前言

        见《研发日记,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模块做信号延迟的应用就算是没问题了,生的代码示例如下:

#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工程,可以到笔者的主页查找和下载。


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


点击全文阅读


本文链接:http://zhangshiyu.com/post/105009.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1