嵌入式轻量级状态机库:零依赖、确定性FSM实现

news2026/3/25 8:41:25
1. 项目概述SimpleStateProcessor 是一个轻量级、零依赖的有限状态机Finite State Machine, FSM处理器库专为资源受限的嵌入式系统设计。其核心目标并非提供图灵完备的复杂状态建模能力而是以极小的内存开销典型ROM占用 2KBRAM仅需数个字节、确定性执行时间单次状态转移最坏情况为 O(1)和无动态内存分配为前提解决嵌入式固件中高频出现的状态协调问题——例如按键消抖、通信协议状态同步、传感器采集周期管理、电机启停时序控制、低功耗模式切换等。该库不引入任何操作系统抽象层如 FreeRTOS 任务或信号量亦不依赖 HAL 或 LL 库的外设驱动封装其接口完全基于纯 C 函数指针与结构体操作可无缝集成于裸机Bare-Metal环境、CMSIS-RTOS 兼容层或作为 FreeRTOS 任务内部的状态调度器使用。所有状态迁移逻辑均在调用者上下文中同步执行无隐式上下文切换开销符合 IEC 61508 SIL-2 等功能安全标准对确定性响应的要求。1.1 设计哲学与工程取舍SimpleStateProcessor 的设计严格遵循嵌入式底层开发的三大铁律确定性Determinism、可预测性Predictability、最小化Minimization。确定性每个ssp_process()调用仅触发一次状态检查与至多一次状态迁移迁移动作由用户定义的on_enter/on_exit回调函数完成不包含任何阻塞、延时或轮询逻辑。状态迁移本身不修改任何全局变量除状态机当前状态标识外避免竞态条件。可预测性库不使用malloc/free所有数据结构均通过静态声明或栈分配无递归调用无浮点运算无未定义行为如数组越界访问。编译后二进制代码大小与执行路径长度均可静态分析。最小化不实现层次化状态机HSM、正交状态Orthogonal Regions或历史状态History States等高级特性。其状态集为扁平一维数组状态 ID 为紧凑的uint8_t类型最大支持 256 个状态事件类型为uint16_t支持 65536 种离散事件。这种简化使状态跳转可通过查表state transition table或线性搜索linear scan两种模式实现开发者可根据 ROM/RAM 权衡自由选择。该库明确拒绝“通用性”陷阱它不试图替代 UML 工具生成的完整状态图框架如 QP/QM也不提供可视化调试器。它的价值在于——当工程师面对一个需要在 4KB Flash 的 Cortex-M0 上实现 UART 帧同步状态机时能直接复制粘贴 3 个函数、定义 5 个状态结构体10 分钟内完成可靠部署。2. 核心数据结构与 API 梳理SimpleStateProcessor 的运行依赖两个核心结构体ssp_state_t描述单个状态的行为ssp_machine_t封装整个状态机的上下文。所有 API 均为纯 C 函数无 C 类封装确保与任意编译器ARMCC、GCC、IAR及 C 标准C99 起兼容。2.1ssp_state_t状态行为定义该结构体定义一个状态的全部可观测行为字段均为函数指针允许用户按需实现字段类型说明on_entervoid (*)(void*)进入该状态时执行的回调。void*参数为用户传入的私有上下文指针如struct sensor_ctx*用于访问外设寄存器、共享缓冲区等。若无需执行动作可置为NULL。on_exitvoid (*)(void*)离开该状态时执行的回调。常用于资源释放如关闭 ADC 时钟、禁用 GPIO 中断。同样支持NULL。on_eventssp_state_id_t (*)(void*, ssp_event_t)核心事件处理器。接收当前上下文与事件 ID返回下一个状态 ID。若返回SSP_STATE_UNCHANGED表示事件被忽略状态保持不变若返回有效状态 ID则触发迁移若返回SSP_STATE_INVALID表示非法迁移库将保持当前状态并返回错误码见ssp_process()返回值。关键设计说明on_event的返回值机制是 SimpleStateProcessor 区别于其他 FSM 库的关键。它不强制要求“每个事件必须导致迁移”而是将决策权完全交给用户逻辑。例如在IDLE状态下收到EVENT_BUTTON_PRESS可返回STATE_DEBOUNCING而收到EVENT_SENSOR_DATA_READY则可返回SSP_STATE_UNCHANGED表示该事件在此状态下无意义。这种显式返回值比布尔型handled/unhandled更利于静态分析与测试覆盖。2.2ssp_machine_t状态机运行时上下文该结构体保存状态机的当前运行状态必须由用户静态声明或栈分配typedef struct { const ssp_state_t* states; // 指向状态数组首地址constROM 存储 uint16_t state_count; // 状态总数即 states 数组长度 ssp_state_id_t current; // 当前状态 ID初始化为 0 或指定初始状态 void* context; // 用户私有上下文指针传递给所有回调 } ssp_machine_t;states必须指向一个ssp_state_t类型的常量数组通常存储在 Flash 中。例如static const ssp_state_t my_fsm_states[] { [STATE_IDLE] { .on_enter idle_enter, .on_event idle_handler }, [STATE_ACTIVE] { .on_enter active_enter, .on_event active_handler }, [STATE_ERROR] { .on_exit error_exit, .on_event error_handler } };state_count必须精确等于数组元素个数用于边界检查防止currentID 越界访问states数组。current是唯一可变字段代表状态机当前所处状态。初始化时应设为合法状态 ID如STATE_IDLE不可为SSP_STATE_INVALID。context为用户自定义数据指针强烈建议将其指向一个结构体封装所有与该状态机相关的硬件句柄、计数器、标志位等。例如typedef struct { UART_HandleTypeDef* huart; // 关联的 UART 句柄 uint8_t rx_buffer[64]; // 接收缓冲区 uint8_t rx_len; // 当前接收长度 uint32_t last_rx_tick; // 上次接收时间戳用于超时检测 } uart_fsm_ctx_t;2.3 主要 API 函数详解ssp_init(ssp_machine_t* machine, const ssp_state_t* states, uint16_t count, ssp_state_id_t initial, void* ctx)初始化状态机上下文。这是必须首先调用的函数完成machine结构体的字段赋值。// 示例初始化 UART 协议状态机 uart_fsm_ctx_t uart_ctx { .huart huart1, .rx_len 0, .last_rx_tick HAL_GetTick() }; ssp_machine_t uart_fsm; ssp_init(uart_fsm, my_uart_states, ARRAY_SIZE(my_uart_states), STATE_IDLE, uart_ctx);states和count必须匹配initial必须 count否则行为未定义。该函数不调用任何on_enter回调仅做结构体填充。首次进入初始状态需手动调用ssp_process()。ssp_process(ssp_machine_t* machine, ssp_event_t event) - ssp_result_t状态机驱动主函数。每次外部事件发生如 GPIO 中断触发、定时器溢出、DMA 传输完成时必须调用此函数。// 在 UART RX Complete Callback 中调用 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart huart1) { ssp_result_t res ssp_process(uart_fsm, EVENT_UART_RX_COMPLETE); if (res ! SSP_OK) { // 处理错误如记录日志、触发看门狗复位 ERROR_Handler(); } } }返回值ssp_result_t枚举定义如下枚举值含义工程意义SSP_OK成功处理事件可能发生了状态迁移正常路径无需干预SSP_INVALID_STATEmachine-current超出[0, state_count)范围严重错误表明状态机被意外篡改如内存溢出覆盖current字段需立即复位SSP_INVALID_EVENT_HANDLERstates[current].on_event为NULL配置错误未为当前状态实现事件处理器属于编译期可捕获缺陷SSP_STATE_UNCHANGEDon_event返回SSP_STATE_UNCHANGED事件被当前状态忽略属预期行为非错误关键实现细节ssp_process()内部执行严格四步原子操作检查current合法性获取states[current].on_event函数指针调用on_event(context, event)获取目标状态 ID若目标 ID 有效且不等于current则a) 调用states[current].on_exit(context)b) 更新machine-current target_idc) 调用states[target_id].on_enter(context)。整个过程无锁、无中断禁用假设回调函数本身是可重入的但要求用户确保on_enter/on_exit执行时间短且不引发新事件。ssp_get_current_state(const ssp_machine_t* machine) - ssp_state_id_t安全读取当前状态 ID。仅作只读访问不触发任何回调。// 调试用途通过串口打印当前状态 printf(FSM State: %d\r\n, ssp_get_current_state(uart_fsm));ssp_force_transition(ssp_machine_t* machine, ssp_state_id_t target) - ssp_result_t强制迁移至指定状态绕过on_event逻辑。仅限调试、错误恢复或系统初始化后首次进入状态时使用。// 系统上电后强制进入 ERROR 状态进行自检 ssp_force_transition(uart_fsm, STATE_ERROR);若target非法返回SSP_INVALID_STATE成功时先执行on_exit若存在再执行on_enter若存在禁止在on_event回调内部调用此函数会导致递归迁移破坏状态一致性。3. 典型应用场景与代码示例SimpleStateProcessor 的价值在具体硬件交互场景中得以充分体现。以下三个示例覆盖嵌入式开发中最常见的三类问题输入消抖、协议解析、低功耗管理。3.1 场景一机械按键消抖状态机裸机环境机械按键存在毫秒级抖动需软件滤波。传统延时消抖HAL_Delay(20)会阻塞 CPU而基于状态机的边沿检测可实现零等待、高响应。// 定义状态 ID枚举提升可读性 typedef enum { KEY_IDLE, // 等待按键按下 KEY_DEBOUNCE, // 检测到下降沿启动消抖计时 KEY_PRESSED, // 消抖完成确认按下 KEY_RELEASED // 等待释放并消抖 } key_state_id_t; // 按键上下文存储 GPIO 端口、引脚及消抖计数器 typedef struct { GPIO_TypeDef* port; uint16_t pin; uint32_t debounce_counter; // 毫秒计数器由 SysTick 提供 } key_ctx_t; // 状态行为定义 static void key_idle_enter(void* ctx) { key_ctx_t* kctx (key_ctx_t*)ctx; // 配置 GPIO 为上拉输入 HAL_GPIO_WritePin(kctx-port, kctx-pin, GPIO_PIN_SET); } static ssp_state_id_t key_idle_handler(void* ctx, ssp_event_t ev) { key_ctx_t* kctx (key_ctx_t*)ctx; if (ev EVENT_GPIO_FALLING) { // 硬件中断检测到下降沿 return KEY_DEBOUNCE; } return SSP_STATE_UNCHANGED; } static void key_debounce_enter(void* ctx) { key_ctx_t* kctx (key_ctx_t*)ctx; kctx-debounce_counter 0; // 重置计数器 } static ssp_state_id_t key_debounce_handler(void* ctx, ssp_event_t ev) { key_ctx_t* kctx (key_ctx_t*)ctx; if (ev EVENT_SYSTICK_1MS) { // 每毫秒 SysTick 中断触发 kctx-debounce_counter; if (kctx-debounce_counter 20) { // 20ms 消抖完成 if (HAL_GPIO_ReadPin(kctx-port, kctx-pin) GPIO_PIN_RESET) { return KEY_PRESSED; } else { return KEY_IDLE; // 抖动结束恢复空闲 } } } return SSP_STATE_UNCHANGED; } static void key_pressed_enter(void* ctx) { // 触发用户业务逻辑如点亮 LED、发送消息 HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); } static ssp_state_id_t key_pressed_handler(void* ctx, ssp_event_t ev) { key_ctx_t* kctx (key_ctx_t*)ctx; if (ev EVENT_GPIO_RISING) { return KEY_RELEASED; } return SSP_STATE_UNCHANGED; } // 状态数组存储在 Flash static const ssp_state_t key_fsm_states[] { [KEY_IDLE] { .on_enter key_idle_enter, .on_event key_idle_handler }, [KEY_DEBOUNCE] { .on_enter key_debounce_enter, .on_event key_debounce_handler }, [KEY_PRESSED] { .on_enter key_pressed_enter, .on_event key_pressed_handler }, [KEY_RELEASED] { .on_exit key_released_exit, .on_event key_released_handler } }; // 初始化与中断服务程序 key_ctx_t key_ctx { .port GPIOA, .pin GPIO_PIN_0 }; ssp_machine_t key_fsm; ssp_init(key_fsm, key_fsm_states, ARRAY_SIZE(key_fsm_states), KEY_IDLE, key_ctx); // EXTI Line0 IRQ Handler void EXTI0_IRQHandler(void) { if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0) ! RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0); // 根据当前电平判断边沿类型 ssp_event_t ev (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) GPIO_PIN_RESET) ? EVENT_GPIO_FALLING : EVENT_GPIO_RISING; ssp_process(key_fsm, ev); } }工程优势消抖逻辑与业务逻辑LED 控制完全解耦EVENT_SYSTICK_1MS事件由 SysTick 中断统一派发避免在每个状态中重复调用HAL_GetTick()所有状态迁移均在中断上下文中完成无阻塞响应延迟 1μsCortex-M4。3.2 场景二Modbus RTU 从机帧接收状态机FreeRTOS 任务内在 FreeRTOS 任务中处理 Modbus RTU 帧需严格遵守 3.5 字符间隔超时规则。使用状态机可清晰分离帧头检测、CRC 校验、功能码分发等阶段。// 在 Modbus 任务中 void modbus_task(void* pvParameters) { modbus_ctx_t mb_ctx { .rx_buffer rx_buf, .rx_len 0 }; ssp_machine_t mb_fsm; ssp_init(mb_fsm, modbus_states, ARRAY_SIZE(modbus_states), STATE_WAIT_START, mb_ctx); for(;;) { // 等待 UART 接收完成信号量 if (xSemaphoreTake(uart_rx_sem, portMAX_DELAY) pdTRUE) { // DMA 接收完成数据已存入 rx_buf ssp_process(mb_fsm, EVENT_UART_FRAME_RECEIVED); } } } // 状态处理器片段STATE_WAIT_START - STATE_RECEIVE_HEADER static ssp_state_id_t wait_start_handler(void* ctx, ssp_event_t ev) { modbus_ctx_t* mctx (modbus_ctx_t*)ctx; if (ev EVENT_UART_FRAME_RECEIVED mctx-rx_len 0) { uint8_t addr mctx-rx_buffer[0]; if (addr MODBUS_SLAVE_ADDR || addr MODBUS_BROADCAST_ADDR) { return STATE_RECEIVE_HEADER; } } return SSP_STATE_UNCHANGED; } // STATE_RECEIVE_HEADER 的 on_enter 启动定时器on_event 检查超时 static void receive_header_enter(void* ctx) { modbus_ctx_t* mctx (modbus_ctx_t*)ctx; mctx-timeout_ticks xTaskGetTickCount() MODBUS_T35_TICKS; // 3.5 字符时间 } static ssp_state_id_t receive_header_handler(void* ctx, ssp_event_t ev) { modbus_ctx_t* mctx (modbus_ctx_t*)ctx; if (ev EVENT_UART_FRAME_RECEIVED) { // 追加新数据到缓冲区 memcpy(mctx-rx_buffer[mctx-rx_len], dma_rx_buf, dma_len); mctx-rx_len dma_len; // 重置超时 mctx-timeout_ticks xTaskGetTickCount() MODBUS_T35_TICKS; } else if (ev EVENT_TIMEOUT_CHECK) { if (xTaskGetTickCount() mctx-timeout_ticks) { // 超时丢弃不完整帧 mctx-rx_len 0; return STATE_WAIT_START; } } return SSP_STATE_UNCHANGED; }集成要点EVENT_TIMEOUT_CHECK由任务循环定期触发如每 1ms实现软定时器on_enter中启动超时计数on_event中检查避免在while循环中忙等状态机完全运行在任务上下文中与 FreeRTOS 的xQueueSend/xSemaphoreGive无缝协作。3.3 场景三电池供电设备的低功耗状态机LL 库直驱面向超低功耗应用需精细控制外设时钟、GPIO 状态及内核睡眠模式。SimpleStateProcessor 可协调各模块的休眠准备与唤醒恢复。// 状态AWAKE - SLEEP_PREPARE - DEEP_SLEEP - AWAKE_ON_WAKEUP static void sleep_prepare_enter(void* ctx) { // 关闭所有非必要外设时钟LL_RCC_APB1_CLK_DISABLE LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_DisableClock(LL_APB1_GRP1_PERIPH_ADC1); // 配置唤醒引脚如 RTC Alarm LL_EXTI_EnableIT_0_31(LL_EXTI_LINE_17); // RTC Alarm LL_EXTI_EnableRisingTrig_0_31(LL_EXTI_LINE_17); } static ssp_state_id_t deep_sleep_handler(void* ctx, ssp_event_t ev) { if (ev EVENT_RTC_ALARM) { return STATE_AWAKE_ON_WAKEUP; } return SSP_STATE_UNCHANGED; } static void awake_on_wakeup_enter(void* ctx) { // 重新使能时钟、重初始化外设 LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM2); LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_ADC1); // 清除唤醒标志 LL_RTC_ClearFlag_ALRA(RTC); }功耗优化效果SLEEP_PREPARE状态确保所有外设在进入DEEP_SLEEP前处于已知安全状态AWAKE_ON_WAKEUP状态集中处理唤醒后的恢复逻辑避免在中断中执行耗时初始化全流程无HAL_Delay功耗状态切换时间可精确到微秒级。4. 配置选项与性能调优SimpleStateProcessor 提供两个关键编译时配置宏位于ssp_config.h需用户创建宏定义默认值说明适用场景SSP_USE_TABLE_DRIVEN0禁用若启用#define SSP_USE_TABLE_DRIVEN 1则ssp_process()使用二维查表法transition_table[current][event]实现 O(1) 迁移否则使用线性搜索O(n)。查表法 ROM 开销大state_count × event_count × sizeof(ssp_state_id_t)但速度最快。状态数 32 且事件数 64 的高频迁移场景如高速通信协议SSP_ENABLE_ASSERTIONS0禁用若启用#define SSP_ENABLE_ASSERTIONS 1则在ssp_init()和ssp_process()中插入assert()检查参数合法性。仅用于开发调试发布版本必须禁用。调试阶段快速定位配置错误性能实测数据STM32F030F4P6 48MHz线性搜索模式单次ssp_process()最坏执行时间 1.2μs12 个状态5 个事件查表模式单次ssp_process()恒定 0.35μsROM 占用线性搜索版 1.1KB查表版16×16 表增加 256BRAM 占用ssp_machine_t固定 12 字节无额外堆栈消耗。5. 错误处理与调试技巧SimpleStateProcessor 将错误分为两类可恢复错误如SSP_STATE_UNCHANGED与致命错误如SSP_INVALID_STATE。后者必须触发系统级响应。5.1 致命错误的工程化应对// 在 ssp_process() 调用后必须检查 ssp_result_t res ssp_process(fsm, ev); switch(res) { case SSP_OK: break; // 正常 case SSP_INVALID_STATE: // 立即触发看门狗复位防止状态机失控 HAL_IWDG_Refresh(hiwdg); NVIC_SystemReset(); // 硬件复位 break; case SSP_INVALID_EVENT_HANDLER: // 编译期错误此处应为断言失败 __BKPT(0); // 进入调试器 break; }5.2 调试辅助工具状态快照日志在on_enter中添加printf(ENTER STATE %d\r\n, current)配合串口终端实时观察迁移路径事件追踪定义EVENT_DEBUG_LOG事件在关键位置调用ssp_process(fsm, EVENT_DEBUG_LOG)统一记录时间戳与上下文静态分析使用cppcheck或PC-lint扫描states数组确保每个on_event非 NULL且所有on_event返回值均在合法范围内。SimpleStateProcessor 的生命力源于其对嵌入式本质的坚守它不试图成为万能胶而是作为一枚精密的齿轮严丝合缝地嵌入到你的裸机循环、FreeRTOS 任务或 CMSIS-RTOS 封装层中以确定性的节奏驱动着每一个硬件状态的优雅变迁。当你在凌晨三点调试一个因状态竞争导致的 sporadic crash 时一个经过充分测试、无隐藏副作用的 FSM 库就是你最值得信赖的战友。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2442724.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

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

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

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…