【研发日记】Matlab/Simulink软件优化(二)——通信负载柔性均衡算法

本文主要是介绍【研发日记】Matlab/Simulink软件优化(二)——通信负载柔性均衡算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录


前言

背景介绍

初始代码

优化代码

分析和应用

总结


前言

        见《【研发日记】Matlab/Simulink软件优化(一)——动态内存负荷压缩》

背景介绍

        在一个嵌入式软件开发项目中,需要设计一个ECU节点的CAN网路数据发送,需求是在500k的通信波特率上,动态发送10到40帧报文,发送一轮的时间最长不能超过50ms。示例如下:

初始代码

        一开始算法开发的思路非常简单,就是设置一个50ms的任务,用for循环把要发送的数据装入CAN发送Buffer。示例如下:

        以上模型生成的代码如下:


#include "untitled.h"
#include "untitled_private.h"/* Block signals (default storage) */
B_untitled_T untitled_B;/* Block states (default storage) */
DW_untitled_T untitled_DW;/* Real-time model */
static RT_MODEL_untitled_T untitled_M_;
RT_MODEL_untitled_T *const untitled_M = &untitled_M_;/* Model step function */
void untitled_step(void)
{int32_T i;int32_T rtb_Gain;int32_T s6_iter;char_T *sErr;void *inputMsgRef;/* Outputs for Enabled SubSystem: '<Root>/Subsystem' incorporates:*  EnablePort: '<S3>/Enable'*//* RelationalOperator: '<S1>/Compare' incorporates:*  Constant: '<S1>/Constant'*  UnitDelay: '<S2>/Output'*/if (untitled_DW.Output_DSTATE == 0) {if (!untitled_DW.Subsystem_MODE) {/* Enable for Iterator SubSystem: '<S3>/For Iterator Subsystem' *//* Enable for S-Function (svntcantransmit): '<S6>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);LibReset(&untitled_DW.CANTransmit_CANTransmit[0U]);LibStart(&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}/* End of Enable for S-Function (svntcantransmit): '<S6>/CAN Transmit' *//* End of Enable for SubSystem: '<S3>/For Iterator Subsystem' */untitled_DW.Subsystem_MODE = true;}/* Outputs for Iterator SubSystem: '<S3>/For Iterator Subsystem' incorporates:*  ForIterator: '<S6>/For Iterator'*/for (s6_iter = 0; s6_iter < 40; s6_iter++) {/* Gain: '<S6>/Gain' */rtb_Gain = s6_iter << 3;for (i = 0; i < 8; i++) {/* Selector: '<S6>/Selector' incorporates:*  Constant: '<Root>/Constant'*/untitled_B.Selector[i] = untitled_ConstP.Constant_Value[i + rtb_Gain];}/* S-Function (scanpack): '<S6>/CAN Pack' *//* S-Function (scanpack): '<S6>/CAN Pack' */untitled_B.CANPack.ID = 10U;untitled_B.CANPack.Length = 8U;untitled_B.CANPack.Extended = 0U;untitled_B.CANPack.Remote = 0;untitled_B.CANPack.Data[0] = 0;untitled_B.CANPack.Data[1] = 0;untitled_B.CANPack.Data[2] = 0;untitled_B.CANPack.Data[3] = 0;untitled_B.CANPack.Data[4] = 0;untitled_B.CANPack.Data[5] = 0;untitled_B.CANPack.Data[6] = 0;untitled_B.CANPack.Data[7] = 0;{(void) memcpy((untitled_B.CANPack.Data), &untitled_B.Selector[0],8 * sizeof(uint8_T));}/* S-Function (svntcantransmit): '<S6>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);/* S-Function (scanpack): '<S6>/CAN Pack' incorporates:*  S-Function (svntcantransmit): '<S6>/CAN Transmit'*/inputMsgRef = &untitled_B.CANPack;/* S-Function (svntcantransmit): '<S6>/CAN Transmit' */LibOutputs_CANTransmit(&untitled_DW.CANTransmit_CANTransmit[0U],inputMsgRef, 1);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}}/* End of Outputs for SubSystem: '<S3>/For Iterator Subsystem' */} else {if (untitled_DW.Subsystem_MODE) {/* Disable for Iterator SubSystem: '<S3>/For Iterator Subsystem' *//* Disable for S-Function (svntcantransmit): '<S6>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);LibReset(&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}/* End of Disable for S-Function (svntcantransmit): '<S6>/CAN Transmit' *//* End of Disable for SubSystem: '<S3>/For Iterator Subsystem' */untitled_DW.Subsystem_MODE = false;}}/* End of RelationalOperator: '<S1>/Compare' *//* End of Outputs for SubSystem: '<Root>/Subsystem' *//* Switch: '<S5>/FixPt Switch' incorporates:*  Constant: '<S4>/FixPt Constant'*  Constant: '<S5>/Constant'*  Sum: '<S4>/FixPt Sum1'*  UnitDelay: '<S2>/Output'*/if ((uint8_T)(untitled_DW.Output_DSTATE + 1U) > 49) {untitled_DW.Output_DSTATE = 0U;} else {untitled_DW.Output_DSTATE++;}/* End of Switch: '<S5>/FixPt Switch' */
}/* Model initialize function */
void untitled_initialize(void)
{{int32_T bitParams[4];char_T *sErr;/* Start for S-Function (svntcantransmit): '<S6>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);CreateHostLibrary("slhostlibcantransmit.dll",&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr == 0) {bitParams[0U] = 1;bitParams[1U] = 4;bitParams[2U] = 3;bitParams[3U] = 1;LibCreate_CANTransmit(&untitled_DW.CANTransmit_CANTransmit[0U], "vector","slvectorxlwrapper.dll", "Virtual", 0, 1, 1, 1,"canslconverter", "vectorxlplugin", 500000.0,&bitParams[0U], 0, 0, 0, 1.0, 0);}if (*sErr == 0) {LibStart(&untitled_DW.CANTransmit_CANTransmit[0U]);}if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}/* End of Start for S-Function (svntcantransmit): '<S6>/CAN Transmit' *//* End of SystemInitialize for SubSystem: '<S3>/For Iterator Subsystem' *//* End of SystemInitialize for SubSystem: '<Root>/Subsystem' */}
}/* Model terminate function */
void untitled_terminate(void)
{char_T *sErr;/* Terminate for Enabled SubSystem: '<Root>/Subsystem' *//* Terminate for Iterator SubSystem: '<S3>/For Iterator Subsystem' *//* Terminate for S-Function (svntcantransmit): '<S6>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);LibTerminate(&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}LibDestroy(&untitled_DW.CANTransmit_CANTransmit[0U], 0);DestroyHostLibrary(&untitled_DW.CANTransmit_CANTransmit[0U]);/* End of Terminate for S-Function (svntcantransmit): '<S6>/CAN Transmit' *//* End of Terminate for SubSystem: '<S3>/For Iterator Subsystem' *//* End of Terminate for SubSystem: '<Root>/Subsystem' */
}

        按照上述示例生成的代码,调试时监测到CAN网络上的瞬时负载率,在0%和100%之间来回跳变。0%和100%各自占用一段时间,两者的比例随着发送报文数量的多少变化。当报文数为最大的40帧时,100%瞬时负载率会持续10ms左右,如下图所示:

        分析上述网络通信的特点,100%瞬时负载率持续的10ms时间段里,肯定会有其他ECU节点也发出报文,这时候CAN网络就会自动根据ID的优先级分配谁先发,谁等待后发,即出现冲突抢占现象。在CAN网络中如果冲突抢占是偶发的,那就不会有太大影响,但是如果冲突抢占是持续的,那就不是我们希望看到的了。

优化代码

        根据对上述问题的分析,我们发现每个50ms周期里边都还有至少40ms是没有利用的,那么只要把前面拥挤的报文分散开到后面一部分,就能解决前面的问题了。然后如果还有剩余的时间没有利用,那么我们就柔性地缩短50ms的周期时长,提高数据发送的频率。这样既能解决前面的问题,又能把总线资源充分利用起来,用于提高我们网络通信的性能。示例如下:

        以上模型生成的代码如下:

#include "untitled.h"
#include "untitled_private.h"/* Named constants for Chart: '<S1>/Chart' */
#define untitled_IN_a                  ((uint8_T)1U)
#define untitled_IN_a1                 ((uint8_T)2U)/* Block signals (default storage) */
B_untitled_T untitled_B;/* Block states (default storage) */
DW_untitled_T untitled_DW;/* Real-time model */
static RT_MODEL_untitled_T untitled_M_;
RT_MODEL_untitled_T *const untitled_M = &untitled_M_;/* Model step function */
void untitled_step(void)
{real_T rtb_Gain;int32_T i;char_T *sErr;void *inputMsgRef;/* Chart: '<S1>/Chart' incorporates:*  Constant: '<Root>/Constant3'*/if (untitled_DW.is_active_c3_untitled == 0U) {untitled_DW.is_active_c3_untitled = 1U;untitled_DW.is_c3_untitled = untitled_IN_a;untitled_B.FrameIndex = 0.0;} else if (untitled_DW.is_c3_untitled == untitled_IN_a) {untitled_DW.is_c3_untitled = untitled_IN_a1;untitled_B.FrameIndex++;} else {/* case IN_a1: */if (untitled_B.FrameIndex >= 39.0) {untitled_DW.is_c3_untitled = untitled_IN_a;untitled_B.FrameIndex = 0.0;}}/* End of Chart: '<S1>/Chart' *//* Gain: '<S1>/Gain' */rtb_Gain = 8.0 * untitled_B.FrameIndex;for (i = 0; i < 8; i++) {/* Selector: '<S1>/Selector' incorporates:*  Constant: '<Root>/Constant2'*/untitled_B.Selector[i] = untitled_ConstP.Constant2_Value[i + (int32_T)rtb_Gain];}/* S-Function (scanpack): '<S1>/CAN Pack' *//* S-Function (scanpack): '<S1>/CAN Pack' */untitled_B.CANPack.ID = 10U;untitled_B.CANPack.Length = 8U;untitled_B.CANPack.Extended = 0U;untitled_B.CANPack.Remote = 0;untitled_B.CANPack.Data[0] = 0;untitled_B.CANPack.Data[1] = 0;untitled_B.CANPack.Data[2] = 0;untitled_B.CANPack.Data[3] = 0;untitled_B.CANPack.Data[4] = 0;untitled_B.CANPack.Data[5] = 0;untitled_B.CANPack.Data[6] = 0;untitled_B.CANPack.Data[7] = 0;{(void) memcpy((untitled_B.CANPack.Data), &untitled_B.Selector[0],8 * sizeof(uint8_T));}/* S-Function (svntcantransmit): '<S1>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);/* S-Function (scanpack): '<S1>/CAN Pack' incorporates:*  S-Function (svntcantransmit): '<S1>/CAN Transmit'*/inputMsgRef = &untitled_B.CANPack;/* S-Function (svntcantransmit): '<S1>/CAN Transmit' */LibOutputs_CANTransmit(&untitled_DW.CANTransmit_CANTransmit[0U], inputMsgRef,1);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}
}/* Model initialize function */
void untitled_initialize(void)
{{int32_T bitParams[4];char_T *sErr;/* Start for S-Function (svntcantransmit): '<S1>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);CreateHostLibrary("slhostlibcantransmit.dll",&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr == 0) {bitParams[0U] = 1;bitParams[1U] = 4;bitParams[2U] = 3;bitParams[3U] = 1;LibCreate_CANTransmit(&untitled_DW.CANTransmit_CANTransmit[0U], "vector","slvectorxlwrapper.dll", "Virtual", 0, 1, 1, 1,"canslconverter", "vectorxlplugin", 500000.0,&bitParams[0U], 0, 0, 0, 1.0, 0);}if (*sErr == 0) {LibStart(&untitled_DW.CANTransmit_CANTransmit[0U]);}if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}/* End of Start for S-Function (svntcantransmit): '<S1>/CAN Transmit' *//* Enable for S-Function (svntcantransmit): '<S1>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);LibReset(&untitled_DW.CANTransmit_CANTransmit[0U]);LibStart(&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}/* End of Enable for S-Function (svntcantransmit): '<S1>/CAN Transmit' */}
}/* Model terminate function */
void untitled_terminate(void)
{char_T *sErr;/* Terminate for S-Function (svntcantransmit): '<S1>/CAN Transmit' */sErr = GetErrorBuffer(&untitled_DW.CANTransmit_CANTransmit[0U]);LibTerminate(&untitled_DW.CANTransmit_CANTransmit[0U]);if (*sErr != 0) {rtmSetErrorStatus(untitled_M, sErr);rtmSetStopRequested(untitled_M, 1);}LibDestroy(&untitled_DW.CANTransmit_CANTransmit[0U], 0);DestroyHostLibrary(&untitled_DW.CANTransmit_CANTransmit[0U]);/* End of Terminate for S-Function (svntcantransmit): '<S1>/CAN Transmit' */
}

        按照上述示例生成的代码,调试时监测到CAN网络上的瞬时负载率非常均匀地保持在25%左右。并且不管报文数量的如何变化,软件都能自动地柔性处理,既不会负载率过高,也不会总线资源浪费,同时又能将报文频率性能发挥到最大。如下图所示:

        分析上述网络通信的特点,已实现了项目中的需求,同时也利用通信负载柔性均衡算法把性能发挥到了最优。

分析和应用

        通信负载均衡,在不同的软件开发项目中重要性是不一样的。一种是实时性要求高的的应用(例如底盘控制),每一帧消息都要在准确的时间发送出去,不允许冲突抢占导致的延误。另一种是网络通信资源非常小的总线(例如低速CAN),单位时间内能发送的报文数量本来就比较少,所以更要仔细计算充分利用,要不然很容易因为负载不均衡导致报文阻塞。

        使用通信负载柔性均衡算法时,需要注意如下几点:

        1、不同波特率,理想负载率下,单位时间对应的报文数量需要仔细的计算,才能设定出最优的算法。例如:500k波特率,在25%理想负载率下,1ms对应的报文数量就是1帧。同理如果1M波特率,那么1ms对应的报文数量就是2帧。

        2、计算好最优的理论算法之后,还要更具自己处理器的性能,设定一个合适的控制粒度。例如:自己的软件最快可以1ms运算一圈,那么就可以1ms控制一次发送1帧或者2帧。如果自己的软件最快只能5ms运算一圈,那么同理就5ms控制一次发送5帧或者10帧。这里的控制粒度越小,负载均衡的效果也越好,但是并非所有的平台都能达到理论极限,只要在自己平台的基础上发挥到最优即可。

        3、对于有网络管理机制的应用场景,需求方可能不希望我们的50ms周期发生变化。例如,网络上的主ECU节点利用同步信号,控制着各个从ECU节点分别占用这50ms中的一小段。当我们自己节点的报文发送完之后,需要等着下一个50ms的到来,或者下一个同步信号的到来。这时候就要把FrameIndex的循环Limit固定成50ms,然后在Transmit模块上加一个使能条件FrameIndex < FrameNum。这样也能达到我们通信负载柔性均衡的目的,同时也满足主ECU节点的网络管理。

总结

        以上就是本人在嵌入式软件开发中处理通信负载率不均衡问题时,一些个人理解和分析的总结,首先介绍了它的背景情况,然后展示它的初始设计和优化设计,最后分析了通信负载均衡算法的注意事项和应用场景。

        后续还会分享另外几个最近总结的软件优化知识点,欢迎评论区留言、点赞、收藏和关注,这些鼓励和支持都将成文本人持续分享的动力。

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


        版权声明:原创文章,转载和引用请注明出处和链接,侵权必究

这篇关于【研发日记】Matlab/Simulink软件优化(二)——通信负载柔性均衡算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1037591

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

HDFS—存储优化(纠删码)

纠删码原理 HDFS 默认情况下,一个文件有3个副本,这样提高了数据的可靠性,但也带来了2倍的冗余开销。 Hadoop3.x 引入了纠删码,采用计算的方式,可以节省约50%左右的存储空间。 此种方式节约了空间,但是会增加 cpu 的计算。 纠删码策略是给具体一个路径设置。所有往此路径下存储的文件,都会执行此策略。 默认只开启对 RS-6-3-1024k

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

跨国公司撤出在华研发中心的启示:中国IT产业的挑战与机遇

近日,IBM中国宣布撤出在华的两大研发中心,这一决定在IT行业引发了广泛的讨论和关注。跨国公司在华研发中心的撤出,不仅对众多IT从业者的职业发展带来了直接的冲击,也引发了人们对全球化背景下中国IT产业竞争力和未来发展方向的深思。面对这一突如其来的变化,我们应如何看待跨国公司的决策?中国IT人才又该如何应对?中国IT产业将何去何从?本文将围绕这些问题展开探讨。 跨国公司撤出的背景与

康拓展开(hash算法中会用到)

康拓展开是一个全排列到一个自然数的双射(也就是某个全排列与某个自然数一一对应) 公式: X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! 其中,a[i]为整数,并且0<=a[i]<i,1<=i<=n。(a[i]在不同应用中的含义不同); 典型应用: 计算当前排列在所有由小到大全排列中的顺序,也就是说求当前排列是第

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖