当前位置: 首页 > news >正文

STM32上部署AI的两个实用软件——Nanoedge AI Studio和STM32Cube AI

1 引言

        STM32 微控制器在嵌入式领域应用广泛,因为它性能不错、功耗低,还有丰富的外设,像工业控制、智能家居、物联网这些场景都能看到它的身影。与此同时,人工智能技术发展迅速,也逐渐融入各个行业。

        把 AI 部署到 STM32 上,能让嵌入式系统更智能,不过这并不容易。AI 模型运行需要大量计算资源和内存,而 STM32 硬件资源有限。所以,找到合适工具很重要。

        今天介绍两款能在 STM32 上部署 AI 的实用软件,Nanoedge AI Studio 和 STM32Cube AI。它们能帮开发者解决难题,顺利在 STM32 上部署 AI 算法,下面就详细讲讲这两款软件。

2 Nanoedge AI Studio

2.1 软件获取

Nanoedge AI Studio是用于STM32部署边缘AI的软件,Studio可生成四种类型的库:异常检测、单分类、多分类、预测。它支持所有类型的传感器,所生成的库不需要任何云连接,可以直接在本地学习与部署,支持STM32所有MCU系列。需要搭配STM32CubeMX、Keil或STM32CubeIDE等编译器使用。

下面这个链接是ST的下载网址:

 https://www.st.com/en/development-tools/nanoedgeaistudio.html

下载过程中会收到邮件,里面有license,第一次使用软件需要用到

到此,软件就获取完毕

2.2 软件介绍

前面已提到,Studio可生成四种类型的库:异常检测、单分类、多分类、预测。左上角四个模型分别对应这四种库(AD:异常检测,nC:多分类,1C:单分类,E:预测),然后下面是以前做过的一些历史工程。

下面对这四种库讲一下使用流程:

2.2.1 异常检测

异常检测:异常检测是指模型对正常数据与异常数据进行训练、学习后,生成的模型可以识别生成的边缘AI可以判断数据是正常还是错误。

这里可能会有疑问,为什么不使用阈值判断等方法,甚至加个滤波可能更加准确,这么做不是更简单吗,在这里使用AI的作用在哪?

答案是,第一,得到的数据难免会出现上下浮动的问题,如何选取阈值是一个值得考虑的问题,对于界限没那么清晰的情况,经常需要经过多次实验确定阈值。而如果使用AI,我们只需要告诉模型,一种情况下的现象是如何,另一种情况下的现象是如何,直接由算法帮我们分析。

第二,也是比较关键的一点,如果我们需要根据多维参数确定一个整体的综合情况,比如评价水质,我们可能会从多角度去考虑(温度、浊度、PH值、含氧量等),那么这个时候,设定阈值就会非常难。

综上,使用AI来做异常检测,会使得问题考虑起来更容易。

在学习这里的时候,在几个平台看到了几个比较经典的例子,可以引入异常检测:

1.风扇、电机等异常检测:通过电流传感器、ADC等检测电流、电压等物理量,我试过通过MPU6050加速度传感器监测电机是否在正常工作

2.声音检测:通过声音传感器反馈出电压模拟量

3.无人机飞行异常检测:没有仔细去研究参考的物理量,个人认为需要通过上述提到的物理量综合考虑

当然还有一些例子,这里就不一一列举了,大家可以尝试做一下

那么,下面就开始讲解软件基本用法:

点开左上角的AD,进入模型构建界面:

第一个界面是Project Setting:

第一步确定模型在ROM和RAM上的最大占据量,这里我直接用默认

第二步,在右边确定芯片型号。这里比较好的一点是,我可以直接选择一个系列,这个系列里的所有型号都能够通用

第三步,选择参考量的个数。如果想用三轴加速度传感器,那么显然这时需要参考三个量,点击第一个图标即可选择。当然后面还有电流量等等的检测,这里就不再赘述了。

当然,上面也提到了,使用AI来做异常检测的好处是能综合多个量判断状态,这时点击Cross sectional选项可以选择Multi-sensor,注意参考量个数的选择,几个量就是几个Axes。

这里,我选择三轴加速度传感器作为演示实例。

第二个界面是Regular signals。前面提到,需要引入正常数据和异常数据进行检测,这里就是采集正常数据。

点击Add Signal,然后看到有两个方法:

一个是导入本地csv格式的数据表格,另一种是用串口向电脑发送数据。

对于导入csv表格,软件内的提示我感觉写的并不是很清晰,我的理解是:进行的一次实验测得的数据写在一行内。测得的每个数据,都要按照x,y,z的顺序来,然后不要空格。比如我得到三个方向加速度,分别为x,y,z。第一次实验,我在一段时间内测得200次,也就是得到200组加速度数据,第一组为x1,y1,z1,第二组为x2,y2,z2。那么,放在表格里的顺序是:x1,y1,z1,x2,y2,z2,......第一次实验完成后进行第二次实验,把实验数据写在第二行,每行最多有256组数据,然后实验次数不要低于20次,也就是行数不低于20行。

这里注意的一点是,不要写任何题头,直接顶格写数据

对于用串口发送数据,可能会更加方便一点,但前提是不对数据再做人工处理。但这里需要写程序把数据按顺序通过串口发送电脑上。下面的是我用MPU6050发送数据的代码,其他的思路都是一样的,供大家参考。

 char buf[30];int cnt;MPU6050_Init();while (1){sprintf(buf,"%ld,%ld,%ld,",AccelData[0],AccelData[1],AccelData[2]);MPU6050ReadAcc(Accel);for( int i=0;i<3;i++){if(Accel[i]>=0){AccelData[i]=Accel[i]*2000/32768;}else{AccelData[i]=-(-Accel[i]+1)*2000/32768;}		}HAL_UART_Transmit(&huart1,(uint8_t*)buf,strlen(buf),0xFFFF);cnt++;if(cnt==256){cnt=0;HAL_UART_Transmit(&huart1,(uint8_t*)"\r\n",2,0xFFFF);}
}

每一次实验的数据要用回车隔开,每个数要用特定字符隔开,这里我用的是逗号,当然其他一些符号也行,大家可以自己研究,最后导入之前再把提示的异常数据删除即可。

这时就能看到导入的数据的直观图了,至于RUN OPTIONAL CHECKS那里,我觉得点不点都行,这个的目的是检查数据的质量。

第三个部分是对异常情况下数据的采集,一样的,就不赘述了

第四个部分Benchmark就是模型训练了,这里会自动计算若干个算法对于导入的这些数据的适配性

训练完如此,可以选择最好的几个进行仿真测试。

最后一步,就是自动生成代码了。

左边这几个选项,第三个和第四个勾选即可,

第二个如果导入的数据里没有浮点数,就不要勾选,

如果想同时使用多个模型,勾选第一个,并命名。

最后点击COMPILE LIBRARY,生成文件。

这里需要导入编译器的文件是libenai.a和NanoEdgeAI.h,找到自己工程的位置

打开Core文件夹,里面有Src和Inc两个文件夹,把libenai.a放到Src文件夹里,NanoEdgeAI.h放到Inc文件夹里。然后打开编译器,我这里使用Keil

 导入到工程里,然后双击libneai.h文件,点第一个

文件类型选Library file 

 至此文件就导入完毕了

在Studio,最后一步右边还有自动生成的代码


/* Includes --------------------------------------------------------------------*/
#include "NanoEdgeAI.h"//直接粘贴
/* Number of samples for learning: set by user ---------------------------------*/
#define LEARNING_ITERATIONS 30//直接粘贴
float input_user_buffer[DATA_INPUT_USER * AXIS_NUMBER]; //直接粘贴
void fill_buffer(float input_buffer[])//直接粘贴,后续需要在这里加代码填充input_buffer[]
{/* USER BEGIN *//* USER END */
}/* -----------------------------------------------------------------------------*/
int main(void)
{/* Initialization ------------------------------------------------------------*/enum neai_state error_code = neai_anomalydetection_init();//直接粘贴uint8_t similarity = 0;//直接粘贴if (error_code != NEAI_OK) {/* This happens if the library works into a not supported board. */}//直接粘贴/* Learning process ----------------------------------------------------------*/for (uint16_t iteration = 0 ; iteration < LEARNING_ITERATIONS ; iteration++) {fill_buffer(input_user_buffer);neai_anomalydetection_learn(input_user_buffer);}//直接粘贴/* Detection process ---------------------------------------------------------*/while (1) {fill_buffer(input_user_buffer);neai_anomalydetection_detect(input_user_buffer, &similarity);//直接粘贴/* USER BEGIN *//** e.g.: Trigger functions depending on similarity* (blink LED, ring alarm, etc.).*//* USER END */}
}

similarity代表相似度,相似度越高代表越正常,最高为100,最低为0,低于一定值就代表异常,一般认为90以下异常

最后,别忘勾选Short enums/wchar(之前在Studio里勾选,这里照应上了)

 到这里就应该可以正常编译了

2.2.2 单分类/多分类

单分类的是指,将数据进行导入,进行机器学习后,可以判断出设备的正常或者异常。这里与异常判断不同的是,这里会将所有非正常的数据判断为异常,而异常判断却可以分析出当前数据与正常数据的相似度。

单分类跟异常检测还是很像的,这里就不多说了,唯一需要说的是,导入数据的时候要把两类都导入,同样多分类也是,也不多说了

2.2.3 预测

模型可以对过往的数据进行分析,训练,生成的模型可以根据近期的数据近似分析出下一个时刻可能的数据,大家也可以自行研究。

至此,Nanoedge AI Studio讲解完毕

3 STM32Cube AI

3.1 软件获取

X-CUBE-AI是STM32Cube.AI生态系统的STM32Cube扩展软件包的一部分,通过自动转换预训练的神经网络并将生成的优化库集成到用户的项目中,扩展了STM32CubeMX功能。

简而言之就是通过X-Cube-AI扩展将当前比较热门的AI框架进行C代码的转化,以支持在嵌入式设备上使用,目前使用X-Cube-AI需要在STM32CubeMX版本5.0以上,目前支持转化的模型有Keras、TF lite、ONNX等,还算比较牛的,Cube-AI把模型转化为一堆数组,而后将这些数组内容解析成模型,和Tensorflow里的模型转数组后使用原理是一样的。

在工程内,或Manage Embedded Software Packages里安装

3.2 软件介绍

我这里使用8.1版本,导入什么类型的模型就选什么格式,选择STM32Cube.AI runtime,Compression代表压缩模型,如果模型过于复杂,那么根据需求选择压缩程度,Optimization是选择时间和空间的协调程度,即时间优先还是空间优先

 然后点击Analyze分析模型,分析结束后可以直接生成代码,打开编译器,这里着重讲一下代码,需要对自动生成的代码有一定了解。

写程序基本的思路是:输入数据(预处理)、模型推理、输出数据(后处理)

先看main.c文件,自动生成的代码如下:

MX_X_CUBE_AI_Init();
while (1)
{MX_X_CUBE_AI_Process();
}

显然,第一句是AI初始化,while内的是AI的数据处理

AI的初始化我没有改动,主要看AI的数据处理过程,右键MX_X_CUBE_AI_Process()看这个函数的定义

void MX_X_CUBE_AI_Process(void)
{/* USER CODE BEGIN 6 */int res = -1;printf("TEMPLATE - run - main loop\r\n");if (network) {do {/* 1 - acquire and pre-process input data */res = acquire_and_process_data(data_ins);/* 2 - process the data - call inference engine */if (res == 0)res = ai_run();/* 3- post-process the predictions */if (res == 0)res = post_process(data_outs);} while (res==0);}if (res) {ai_error err = {AI_ERROR_INVALID_STATE, AI_ERROR_CODE_NETWORK};ai_log_err(err, "Process has FAILED");}/* USER CODE END 6 */
}

其实这里就可以看出前面提到的三个步骤,但这里的逻辑我感觉没有说很好,于是决定自己封装函数。

这里就不过多讲解了,其实这里需要对app_x_cube_ai.c文件里的代码做一定的了解,

比如代码里涉及到的数据类型,这里换了个名,要能看懂

typedef uint8_t       ai_custom_type_signature;typedef void*         ai_handle;
typedef const void*   ai_handle_const;typedef float         ai_float;
typedef double        ai_double;typedef bool          ai_bool;typedef char          ai_char;typedef uint32_t      ai_size;
typedef int16_t       ai_short_size;typedef uintptr_t     ai_uptr;typedef unsigned int  ai_uint;
typedef uint8_t       ai_u8;
typedef uint16_t      ai_u16;
typedef uint32_t      ai_u32;
typedef uint64_t      ai_u64;typedef int           ai_int;
typedef int8_t        ai_i8;
typedef int16_t       ai_i16;
typedef int32_t       ai_i32;
typedef int64_t       ai_i64;typedef uint64_t      ai_macc;typedef int32_t       ai_pbits;typedef uint32_t      ai_signature;typedef void (*ai_handle_func)(ai_handle);

CubeMX也提供了一些示例代码,也有一个大概的了解

/* USER CODE BEGIN 2 */
int acquire_and_process_data(ai_i8* data[])
{/* fill the inputs of the c-modelfor (int idx=0; idx < AI_NETWORK_1_IN_NUM; idx++ ){data[idx] = ....}*/return 0;
}int post_process(ai_i8* data[])
{/* process the predictionsfor (int idx=0; idx < AI_NETWORK_1_OUT_NUM; idx++ ){data[idx] = ....}*/return 0;
}
/* USER CODE END 2 */

最后附上我自己封装的代码,供大家参考。

我训练的模型是输入5个float数据,输出1个ai_i32数据

app_x_cube_ai.c文件

ai_buffer* Get_Inputs(void)
{ai_u16 *in_buffer=(short unsigned int*)0;return ai_network_inputs_get(network,in_buffer);
}
ai_buffer* Get_Outputs(void)
{ai_u16 *out_buffer=(short unsigned int*)0;return ai_network_outputs_get(network,out_buffer);
}
void PrepareInput(ai_float* InputData)
{ai_input=Get_Inputs();ai_input->data=InputData;
}
ai_i32* Predict()
{ai_output=Get_Outputs();ai_run();return (ai_i32*)ai_output->data;
}
void NetPrint()
{printf("Input shape:");for(int i=0;i<Get_Inputs()->shape.size;i++){printf("%d ",Get_Inputs()->shape.data[i]);}printf("\r\n");printf("Output shape:");for(int i=0;i<Get_Outputs()->shape.size;i++){printf("%d ",Get_Outputs()->shape.data[i]);}printf("\r\n");
}

.h文件

void PrepareInput(ai_float* InputData);
void NetPrint(void);
ai_i32* Predict(void);

main.c文件

float Data[6][5]={{1,450,23,7,60},{0,640,25,8,10},{2,420,25,8,0},{3,680,27,8.5,20},{4,400,24,7,80},{5,530,22,7.5,40}};
NetPrint();while (1){    for(int k=0;k<6;k++){float InputData[5]={Data[k][0],Data[k][1],Data[k][2],Data[k][3],Data[k][4]};PrepareInput(InputData);printf("InputData:%f %f %f %f %f\r\n",InputData[0],InputData[1],InputData[2],InputData[3],InputData[4]);printf("outData:%d\r\n",*Predict());printf("\r\n");}}

测试结果与上位机一致。至此,STM32Cube AI的基本使用讲解结束。

相关文章:

STM32上部署AI的两个实用软件——Nanoedge AI Studio和STM32Cube AI

1 引言 STM32 微控制器在嵌入式领域应用广泛&#xff0c;因为它性能不错、功耗低&#xff0c;还有丰富的外设&#xff0c;像工业控制、智能家居、物联网这些场景都能看到它的身影。与此同时&#xff0c;人工智能技术发展迅速&#xff0c;也逐渐融入各个行业。 把 AI 部署到 STM…...

C++ Primer 成员访问运算符

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

芯科科技的BG22L和BG24L带来应用优化的超低功耗蓝牙®连接

全新的BG22L为常见蓝牙设备提供强大的安全性和处理能力&#xff0c;而BG24L支持先进的AI/ML加速和信道探测功能 2025年2月6日 – 致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;NASDAQ&#x…...

java后端开发面试常问

面试常问问题 1 spring相关 &#xff08;1&#xff09;Transactional失效的场景 <1> Transactional注解默认只会回滚运行时异常&#xff08;RuntimeException&#xff09;&#xff0c;如果方法中抛出了其他异常&#xff0c;则事务不会回滚&#xff08;数据库数据仍然插…...

‌双非硕士的抉择:自学嵌入式硬件开发还是深入Linux C/C++走软开?

今天给大家分享的是一位粉丝的提问&#xff0c;双非硕研一是自学嵌入式走偏硬件还是说深入学习Linuxc/c走软开呢&#xff1f; 接下来把粉丝的具体提问和我的回复分享给大家&#xff0c;希望也能给一些类似情况的小伙伴一些启发和帮助。 粉丝提问&#xff1a; 老师好&#xff…...

Windows系统使用Git教程详解

使用 Git 可以帮助开发人员更好地进行版本控制和团队协作&#xff0c;下面是 Windows 上 Git 的详细使用教程。 安装 Git 首先&#xff0c;你需要在 Windows 上安装 Git。你可以从 Git 官网下载最新的安装包&#xff08;https://git-scm.com/downloads&#xff09;&#xff0c;…...

Linux firewalld开启日志审计功能(2)

在Firewalld防火墙中启用和配置logdenied选项&#xff0c;记录被拒绝的数据包&#xff08;等同于开启日志功能&#xff09; 效果展示&#xff1a; 1.开启日志记录功能 firewall-cmd --set-log-deniedunicast #重新加载生效配置 firewall-cmd --reload 2.配置rsyslog捕获日志…...

【声音转文字CapsWriter】声音随时转化为文字,CapsWriter提高工作效率

文章目录 前言1. 软件与模型下载2. 本地使用测试3. 异地远程使用3.1 内网穿透工具下载安装3.2 配置公网地址3.3 修改config文件3.4 异地远程访问服务端 4. 配置固定公网地址4.1 修改config文件 5. 固定tcp公网地址远程访问服务端 前言 今天我要给大家安利一个神器——CapsWrit…...

深入理解小波变换:信号处理的强大工具

引言 在科学与工程领域&#xff0c;信号处理一直是关键环节&#xff0c;傅里叶变换与小波变换作为重要的分析工具&#xff0c;在其中发挥着重要作用。本文将深入探讨小波变换&#xff0c;阐述其原理、优势以及与傅里叶变换的对比&#xff0c;并通过具体案例展示其应用价值。 一…...

人机交互系统实验三 多通道用户界面

实验目的和要求 1)了解常见的多通道用户界面 2)查找资料&#xff0c;熟悉一种多通道用户界面并写出综述 实验环境 Windows10 实验内容与过程 (一) 实验内容: 要求上网查找资料&#xff0c;熟悉一种多通道用户界面并写出综述&#xff0c;可以是眼动跟踪、手势识别、 三维…...

Filter -> MaskFilter遮罩滤镜详解

MaskFilter 作用对象&#xff1a;MaskFilter 主要用于Paint的外观效果&#xff0c;给用Paint绘制的内容添加模糊或者浮雕效果应用效果&#xff1a; MaskFilter 处理位图的遮罩效果&#xff0c;影响绘制的边缘或整体形状主要用于模糊处理、浮雕效果等&#xff0c;通过影响绘制对…...

RK3568使用QT操作LED灯

文章目录 一、QT中操作硬件设备思路Linux 中的设备文件操作硬件设备的思路1. 打开设备文件2. 写入数据到设备3. 从设备读取数据4. 设备控制5. 异常处理在 Qt 中操作设备的典型步骤实际应用中的例子:控制 LED总结二、QT实战操作LED灯设备1. `mainwindow.h` 头文件2. `mainwindo…...

python学opencv|读取图像(五十七)使用cv2.bilateralFilter()函数实现图像像素双边滤波处理

【1】引言 前序学习过程中&#xff0c;已经掌握了对图像的基本滤波操作技巧&#xff0c;具体的图像滤波方式包括均值滤波、中值滤波和高斯滤波&#xff0c;相关文章链接有&#xff1a; python学opencv|读取图像&#xff08;五十四&#xff09;使用cv2.blur()函数实现图像像素…...

为何实现大语言模型的高效推理以及充分释放 AI 芯片的计算能力对于企业级落地应用来说,被认为具备显著的研究价值与重要意义?

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ AI 芯片&#xff1a;为人工智能而生的 “大脑” AI 芯片&#xff0c;又称人工智能加速器或计算卡&#xff0c;是专为加速人工智能应用&#xff0c;特别是深度学习任务设计的专用集成电路&#xff08;A…...

Android 约束布局ConstraintLayout整体链式打包居中显示

Android 用约束布局ConstraintLayout实现将多个控件视作一个整体居中显示&#xff0c;使用 app:layout_constraintHorizontal_chainStyle"packed"实现 chain 除了链条方向有横向和竖向区分外&#xff0c; chain链条上的模式有 3种 spread - 元素将被展开&#…...

在C#中,Array,List,ArrayList,Dictionary,Hashtable,SortList,Stack的区别

Array Array你可以理解为是所有数组的大哥 普通数组 : 特点是长度固定, 只能存储相同类型的数据 static void Main(string[] args){//声明int[] ints;string[] strings;People[] peoples;//默认值 //int 类型是 0//string 类型是 nullint[] ints1 { 1, 2, 3 };string[] …...

微服务知识——微服务架构的演进过程

文章目录 初始架构&#xff1a;单机架构第一次演进&#xff1a;Tomcat与数据库分开部署第二次演进&#xff1a;引入本地缓存和分布式缓存第三次演进&#xff1a;引入反向代理实现负载均衡第四次演进&#xff1a;数据库读写分离第五次演进&#xff1a;数据库按业务分库第六次演进…...

Chrome 浏览器:互联网时代的浏览利器

Chrome 浏览器&#xff1a;互联网时代的浏览利器 引言 在互联网时代&#xff0c;浏览器已经成为我们日常生活中不可或缺的工具。作为全球最受欢迎的浏览器之一&#xff0c;Chrome 浏览器凭借其出色的性能、丰富的扩展程序和简洁的界面&#xff0c;赢得了广大用户的喜爱。本文…...

深入浅出 NRM:加速你的 npm 包管理之旅

文章目录 前言一、NRM 是什么&#xff1f;二、为什么需要 NRM&#xff1f;三、NRM 的优势四、NRM 的安装与使用4.1 安装 NRM4.2 查看可用的 npm 源4.3 切换 npm 源4.4 测试 npm 源速度4.5 添加自定义 npm 源4.6 删除 npm 源 五、NRM 的进阶使用六、总结 前言 作为一名 JavaScr…...

Linux——基础命令1

$&#xff1a;普通用户 #&#xff1a;超级用户 cd 切换目录 cd 目录 &#xff08;进入目录&#xff09; cd ../ &#xff08;返回上一级目录&#xff09; cd ~ &#xff08;切换到当前用户的家目录&#xff09; cd - &#xff08;返回上次目录&#xff09; pwd 输出当前目录…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度​

一、引言&#xff1a;多云环境的技术复杂性本质​​ 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时&#xff0c;​​基础设施的技术债呈现指数级积累​​。网络连接、身份认证、成本管理这三大核心挑战相互嵌套&#xff1a;跨云网络构建数据…...

应用升级/灾备测试时使用guarantee 闪回点迅速回退

1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间&#xff0c; 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点&#xff0c;不需要开启数据库闪回。…...

3.3.1_1 检错编码(奇偶校验码)

从这节课开始&#xff0c;我们会探讨数据链路层的差错控制功能&#xff0c;差错控制功能的主要目标是要发现并且解决一个帧内部的位错误&#xff0c;我们需要使用特殊的编码技术去发现帧内部的位错误&#xff0c;当我们发现位错误之后&#xff0c;通常来说有两种解决方案。第一…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...