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

发布于:2024-05-08 ⋅ 阅读:(20) ⋅ 点赞:(0)

文章目录

前言

背景介绍

问题描述

分析排查

解决方案

总结归纳


前言

        见《研发日记,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();
}

总结归纳

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

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

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

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

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

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

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


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