首页 文章 精选 留言 我的

精选列表

搜索[嵌入式],共4470篇文章
优秀的个人博客,低调大师

面向边缘设备的离线嵌入式哭声检测

* --- ## 哭声识别的价值(场景、流程) 婴幼儿的哭声既是表达需求的主要方式,也是健康状况的直接反映。核心需求是**实时哭声监测与报警/反馈机制**——在婴儿哭闹的第一时间通知父母,并支持及时安抚。婴儿哭声识别在摄像头本地离线完成,音频不出设备;夜间与短暂离开时的监测需求尤为迫切。 典型产品形态:婴儿监视器、智能摄像头、智能婴儿床、车载儿童遗留检测(CPD)。如今市面上的婴儿监视器在拼 2K 分辨率、云台与夜视,但几乎都是被动的——只是把视频传到父母面前,等待人来盯着看。加入设备端哭声检测后,被动摄像头变成主动报警设备,吊扇、窗帘、路过的家人都不再触发无效告警。 ## 哭声的特点(时域与频域) ![哭声与说话声、环境声对比](https://developer.qcloudimg.com/http-save/yehe-7961666/e190f2c575bf320ddb349ac01cdcb618.png) *图:基频-共振峰结构 vs 断续说话声 vs 无结构噪声* 这是一条真实哭声音频——上为波形图、下为梅尔频谱图,与模型在设备端使用的 16kHz 预处理一致;清晰的起—落包络与谐波结构一目了然: ![真实哭声:波形与频谱](https://developer.qcloudimg.com/http-save/yehe-7961666/4275b552174b75d29599dea8625e522d.png) *图:真实婴儿哭声示例:波形(上)+ 梅尔频谱(下)* 试听素材(真实样本,点击播放): > 🔊 音频试听:[真实婴儿哭声](https://51tage.com/zh/audio/?f=cry-1.wav&s=t.audio "真实婴儿哭声") > 🔊 音频试听:[猫叫——与哭声频谱最接近的易混淆声](https://51tage.com/zh/audio/?f=cry-2.wav&s=t.audio "猫叫——与哭声频谱最接近的易混淆声") 从频谱上看,哭声的特征非常明显:呈现清晰的**基频—共振峰结构**,谐波像乐谱上的音符一样排列,基频大约在 **300–500Hz**,并伴随一个"起—落"的能量包络,持续相对较长的一小段时间。相比之下,说话声断续、停顿频繁;环境声(电视/谈话/家电)则没有稳定的基频结构。 因此哭声识别**以频域特征为主**:谐波结构是把哭声与其他声音分开的核心证据。 ## 识别方法:预处理 → 特征提取 → 算法 ### 信号预处理 - **自适应降噪**——实际场景存在电视声、谈话声等复杂噪声,系统实时估计并抑制背景噪声,在典型家庭噪声下信噪比提升约 **5–10dB** - **端点检测与分帧**——先定位候选事件再进入分析 - **数据增强(训练阶段)**——变速、加噪、房间冲激响应卷积,提升泛化能力 ### 特征提取 - **频域**——FFT 变换后提取 Mel 频谱(低频滤波器密集、高频稀疏,匹配人耳听觉特性)→ 倒谱分析得到 MFCC(取 DCT 第 2–13 个系数);深度模型则直接使用 FBank 特征充分学习细节 - **时域**——短时能量、过零率、能量熵、chroma 等,并可叠加 delta / delta-delta 动态特征 ### 识别算法 SVM 在小样本高维数据上表现稳健;随机森林抗过拟合、适合含噪数据;CNN 自动学习局部时频特征。对比实验显示,**CNN + LSTM 混合模型**在保持高准确率的同时具备良好实时性。此外,借助预训练模型的迁移学习加速收敛;集成学习(SVM + 随机森林 + CNN 投票/加权)进一步提升鲁棒性;用户反馈机制持续优化模型参数。 ### 算法横向对比(2026 基准测试) 我们在 5 种真实噪声条件(安静/电视背景/白噪声/对话/街道噪声)下评估了主流方法(测试集 12,000+ 片段): | 方法 | 准确率 | 模型大小 | 延迟 | | --- | --- | --- | --- | | MFCC + 轻量 CNN | 97.2% | 0.9 MB | #ifdef __cplusplus extern "C" { #endif /* 识别事件 (报警策略输出, 用于事件结束回调) */ typedef struct { float start_time; /* 事件开始时间 (秒) */ float end_time; /* 事件结束时间 (秒) */ float confidence; /* 事件置信度 */ float max_confidence; /* 事件内最大帧置信度 */ int frame_count; /* 事件持续帧数 */ } cry_detect_event_t; /* 帧级回调: 每帧识别结果 (模型线程内执行) */ typedef void (*cry_detect_frame_cb_t)(float cry_prob, float timestamp, void *user_data); /* 事件开始回调: 策略判定哭声开始, 只有开始时间 */ typedef void (*cry_detect_onset_cb_t)(float start_time, void *user_data); /* 事件结束回调: 策略判定哭声结束 (或停止识别时未结束的事件), 完整事件信息 */ typedef void (*cry_detect_offset_cb_t)(const cry_detect_event_t *event, void *user_data); typedef struct cry_detect_s cry_detect_t; /* 创建/销毁; alarm_name/alarm_params 可传 NULL (用默认策略及参数) */ cry_detect_t *cry_detect_create(const char *mgk_path, /* 模型文件路径 (必填) */ const char *alarm_name, /* 报警策略名, NULL=默认 */ const char *alarm_params); /* 策略参数 key=val,key=val, NULL=默认 */ void cry_detect_destroy(cry_detect_t *det); /* 设置事件回调 (create 后调用, 也可在运行中调整); 不需要的回调传 NULL */ void cry_detect_set_listener(cry_detect_t *det, cry_detect_frame_cb_t on_frame, cry_detect_onset_cb_t on_onset, cry_detect_offset_cb_t on_offset, void *user_data); /* 启动/停止识别: 启动内部模型消费线程 / 排空缓冲后停止线程 */ int cry_detect_start(cry_detect_t *det); void cry_detect_stop(cry_detect_t *det); int cry_detect_is_running(cry_detect_t *det); /* 设置事件识别策略 (可在运行中调整) */ int cry_detect_set_alarm(cry_detect_t *det, const char *alarm_name, const char *alarm_params); /* 送入 PCM 数据 (16bit 单声道 16kHz), 线程安全, 任意数据大小 */ int cry_detect_feed(cry_detect_t *det, const int16_t *pcm, int num_samples); #ifdef __cplusplus } #endif #endif /* CRY_DETECT_H */ ``` 最简 wav 推理示例(节选,完整文件位于 SDK 的 `src/cryDetect/c/main.c`): ```bash #include #include #include #include "cry_detect.h" #define DEFAULT_MGK "cry_detect.mgk" /* 模型文件 */ #define DEFAULT_WAV "test_cry.wav" /* 16kHz 单声道 16bit PCM */ #define FEED_CHUNK 16000 /* 每次送入 1 秒音频 */ /* 帧级回调: 每帧输出哭声概率 (约 1 秒一帧) */ static void on_frame(float cry_prob, float timestamp, void *user_data) { (void)user_data; printf("%8.2fs cry=%.4f\\n", timestamp, cry_prob); } /* 事件开始回调: 策略判定哭声事件开始 */ static void on_onset(float start_time, void *user_data) { (void)user_data; printf("[EVENT] cry start at %.2fs\\n", start_time); } /* 事件结束回调: 应用层可据此做后续统计或分级响应 */ static void on_offset(const cry_detect_event_t *ev, void *user_data) { (void)user_data; printf("[EVENT] cry end at %.2fs (dur=%.2fs, conf=%.3f, frames=%d)\\n", ev->end_time, ev->end_time - ev->start_time, ev->confidence, ev->frame_count); } static int read_wav_pcm(const char *path, int16_t **pcm, int *n, int *sr); /* 完整实现见源文件 */ int main(void) { cry_detect_t *det; int16_t *pcm = NULL; int num_samples = 0, sample_rate = 0; int pos; if (read_wav_pcm(DEFAULT_WAV, &pcm, &num_samples, &sample_rate) != 0) return 1; /* 1. 创建识别器: 模型文件 + 默认报警策略 (NULL) */ det = cry_detect_create(DEFAULT_MGK, NULL, NULL); if (!det) return 1; /* 2. 注册回调 (均为可选) */ cry_detect_set_listener(det, on_frame, on_onset, on_offset, NULL); /* 3. 启动内部模型消费线程 */ cry_detect_start(det); /* 4. 分块送入 PCM; 实时录音时改在录音回调里 feed */ for (pos = 0; pos FEED_CHUNK) n = FEED_CHUNK; cry_detect_feed(det, pcm + pos, n); } /* 5. 停止并销毁 */ cry_detect_stop(det); cry_detect_destroy(det); free(pcm); return 0; } ``` 编译与运行(示例): ```bash $(CC) main.c -I. -L. -lcrydetect -lpthread -lm -o cry_detect ./cry_detect ``` 结语 哭声识别让婴儿产品从"摄像头"变成"照看者"。做婴儿监视器、智能摄像头或车载 CPD 的团队,可以直接上传自己的录音,先在线验证离线哭声检测在真实噪声下的表现。 在线验证:[上传自己的录音,在线哭声识别测试](https://51tage.com/zh/demo?s=t.a) ---

优秀的个人博客,低调大师

嵌入式Linux:常见信号的默认行为

信号是一种软件中断,用于通知进程发生了某种异步事件。信号可以由用户、其他进程或操作系统内核产生。进程可以选择捕获并处理这些信号,或者忽略它们,让系统执行默认操作。 ![](https://developer.qcloudimg.com/http-save/yehe-8201782/48a8c90ab316fc00ae6a505bd09d83ca.png) - **不可靠信号(非实时信号)**:编号为 1~31 的信号。它们的行为可能因实现而异,特别是在信号被阻塞或忽略的情况下。如果多个相同的不可靠信号在短时间内连续到达,它们可能会合并成一个信号。 - **可靠信号(实时信号)**:编号为 34~64 的信号。它们的行为在所有 POSIX 兼容的系统上都是相同的。可靠信号不会合并,即使它们在短时间内连续到达。可靠信号支持排队,这意味着如果一个可靠信号被阻塞,它将被存储在队列中,直到信号处理程序准备就绪。 常见信号的用途和系统默认操作如下: ![](https://developer.qcloudimg.com/http-save/yehe-8201782/f720a689a6ce3158b64693ce0ab21687.png) **SIGINT (2)** - 触发方式:当用户在终端按下中断字符(通常是`CTRL+C`)。 - 默认操作:终止进程。 - 描述:用于中断正在运行的前台进程,是常用的终止命令。 **SIGQUIT (3)** - 触发方式:当用户在终端按下退出字符(通常是`CTRL+\`)。 - 默认操作:终止进程并生成核心转储文件。 - 描述:用于在程序进入无限循环或不响应时终止进程,并生成调试用的核心文件。 **SIGILL (4)** - 触发方式:进程尝试执行非法的机器语言指令。 - 默认操作:终止进程。 - 描述:用于指示程序执行了无效的操作码,通常表示程序代码损坏或内存越界。 **SIGABRT (6)** - 触发方式:当进程调用`abort()`系统调用。 - 默认操作:终止进程并生成核心转储文件。 - 描述:用于指示进程自身发现了严重错误,并请求自我终止。 **SIGBUS (7)** - 触发方式:发生总线错误(例如错误的内存访问)。 - 默认操作:终止进程。 - 描述:指示内存访问冲突,通常与硬件有关。 **SIGFPE (8)** - 触发方式:特定类型的算术错误(例如除以零)。 - 默认操作:终止进程。 - 描述:用于表示浮点运算错误或其他算术异常。 **SIGKILL (9)** - 触发方式:通过`kill -9`命令或系统直接发送。 - 默认操作:立即终止进程。 - 描述:是无法被捕获或忽略的“必杀”信号,用于强制终止进程。 **SIGUSR1 (10)** - 触发方式:用户定义的信号,供程序员自定义使用。 - 默认操作:终止进程。 - 描述:用户程序可以使用此信号进行进程间通信或事件通知。 **SIGSEGV (11)** - 触发方式:进程尝试访问无效的内存地址。 - 默认操作:终止进程。 - 描述:常见于指针错误或无效内存访问操作,通常会导致程序崩溃。 **SIGUSR2 (12)** - 触发方式:与`SIGUSR1`类似,供用户自定义使用。 - 默认操作:终止进程。 - 描述:供程序员自定义,用于进程间通信或自定义处理逻辑。 **SIGPIPE (13)** - 触发方式:进程向已关闭的管道或套接字写入数据。 - 默认操作:终止进程。 - 描述:当尝试向无效的通信通道写入数据时触发,通常用于通知进程通信失败。 **SIGALRM (14)** - 触发方式:定时器到期(由`alarm()`或`setitimer()`设置)。 - 默认操作:终止进程。 - 描述:常用于定时操作,信号触发后通常终止程序或进行某种处理。 **SIGTERM (15)** - 触发方式:通过`kill`命令(不带`-9`选项)。 - 默认操作:终止进程。 - 描述:用于请求进程正常终止,通常用于优雅地关闭应用程序。 **SIGCHLD (17)** - 触发方式:子进程终止或状态改变。 - 默认操作:忽略信号。 - 描述:父进程用来得知子进程终止或状态改变,默认忽略,父进程可选择处理。 **SIGCONT (18)** - 触发方式:恢复已停止的进程。 - 默认操作:继续运行进程。 - 描述:发送给已停止的进程,使其恢复执行。 **SIGSTOP (19)** - 触发方式:强制停止进程。 - 默认操作:停止进程。 - 描述:无法捕获或忽略的“必停”信号,用于暂停进程执行。 **SIGTSTP (20)** - 触发方式:用户在终端按下停止字符(`CTRL+Z`)。 - 默认操作:停止进程。 - 描述:用于暂停前台进程组中的进程,常用于暂停任务。 **SIGXCPU (24)** - 触发方式:进程CPU时间超出限制。 - 默认操作:终止进程。 - 描述:通常用于检测进程占用CPU过多时间,可能引发警告或终止进程。 **SIGVTALRM (26)** - 触发方式:虚拟定时器到期(由`setitimer()`设置)。 - 默认操作:终止进程。 - 描述:用于虚拟定时器管理,定时器到期后触发信号。 **SIGWINCH (28)** - 触发方式:终端窗口大小改变。 - 默认操作:忽略信号。 - 描述:当终端窗口调整大小时,前台进程会接收到此信号。 **SIGPOLL/SIGIO (29)** - 触发方式:异步I/O事件发生。 - 默认操作:终止进程。 - 描述:用于异步I/O操作,通知进程文件描述符的I/O事件。 **SIGSYS (31)** - 触发方式:进程发起了无效的系统调用。 - 默认操作:终止进程。 - 描述:通常用于捕获非法系统调用或程序错误。 这些信号为Linux进程提供了丰富的控制和通信机制。了解这些信号及其默认行为,有助于编写更加健壮的程序,并能够有效处理各种异常和中断。 作者:不脱发的程序猿。来源:[CSDN 原文](https://handsome-man.blog.csdn.net/article/details/141103293)(CC BY-SA 4.0)。

优秀的个人博客,低调大师

嵌入式Linux:获取信号的描述信息

在 Linux 系统中,每个信号都有一个对应的字符串描述信息,用于描述该信号的含义。这些描述信息可以通过 `sys_siglist` 数组或者使用 `strsignal()` 和 `psignal()` 函数来获取和显示。 ## 1、`sys_siglist`数组 `sys_siglist` 是一个 `char*` 类型的数组,其中每个元素是一个字符串指针,指向与特定信号相关的描述信息。例如,可以通过 `sys_siglist[SIGINT]` 获取对 `SIGINT` 信号的描述。这个数组在很多情况下非常有用,特别是在调试和信号处理时。 为了使用 `sys_siglist` 数组,你需要包含 `` 头文件。以下是一个简单的代码示例,演示如何使用 `sys_siglist` 来获取信号的描述信息: ``` #include #include int main() { int sig = SIGINT; printf("Signal %d: %s\n", sig, sys_siglist[sig]); return 0; } ``` 在这个例子中,`sys_siglist[SIGINT]` 返回的是字符串 "Interrupt",表示 `SIGINT` 信号的描述信息。 ## 2、strsignal()函数 除了直接使用 `sys_siglist` 数组来获取信号描述信息之外,Linux 还提供了一个更为推荐的方法,即使用 `strsignal()` 函数。相比直接引用 `sys_siglist` 数组,`strsignal()` 提供了更好的封装和错误检查。 `strsignal()` 的函数原型如下: ``` char *strsignal(int sig); ``` 调用 `strsignal()` 函数时,会返回参数 `sig` 所指定信号的描述信息。如果传入了一个无效的信号编号,函数将返回 `"Unknown signal"`。这一点使得 `strsignal()` 在处理未知或不常见信号时更加健壮。 以下是一个使用 `strsignal()` 函数的示例: ``` #include #include int main() { int sig = SIGTERM; printf("Signal %d: %s\n", sig, strsignal(sig)); return 0; } ``` 在这个例子中,`strsignal(SIGTERM)` 会返回 "Terminated" 作为 `SIGTERM` 信号的描述信息。 ## 3、psignal()函数 `psignal()` 函数是另一个有用的工具,它可以在标准错误输出(`stderr`)上打印信号的描述信息,并允许调用者添加额外的输出信息。这在调试或日志记录时非常有用,因为它提供了一个简便的方式来输出信号信息,同时附带上下文信息。 `psignal()` 的函数原型如下: ``` void psignal(int sig, const char *s); ``` 调用 `psignal()` 时,它会将指定信号的描述信息输出到标准错误,格式为:`: `,并在末尾添加换行符。如果传递的 `sig` 是无效信号编号,它将输出 `"Unknown signal"`, 类似于 `strsignal()`。 以下是一个使用 `psignal()` 函数的示例: ``` #include #include int main() { int sig = SIGQUIT; psignal(sig, "Received signal"); return 0; } ``` 输出结果可能类似于: ``` Received signal: Quit ``` 在这个例子中,`psignal(SIGQUIT, "Received signal")` 将信号的描述信息与自定义消息一起输出到标准错误中。 在处理 Linux 信号时,`sys_siglist` 数组、`strsignal()` 函数和 `psignal()` 函数各有其应用场景。直接使用 `sys_siglist` 数组虽然简单明了,但 `strsignal()` 和 `psignal()` 函数提供了更高层次的封装和错误处理,使代码更加健壮和易于维护。 在实际开发中,建议优先考虑使用 `strsignal()` 和 `psignal()`,尤其是在需要处理不确定信号时。 作者:不脱发的程序猿。来源:[CSDN 原文](https://blog.csdn.net/m0_38106923/article/details/141305858)(CC BY-SA 4.0)。

优秀的个人博客,低调大师

嵌入式Linux:判断信号是否处于等待状态

在 Linux 系统中,如果进程当前正在执行信号处理函数,并在此期间接收到了新的信号,且该信号属于信号掩码中的成员,那么内核会将该信号阻塞并添加到进程的 **等待信号集** 中(即处于等待状态的信号)。这些信号会一直保持等待状态,直到它们从信号掩码中移除并被处理。 为了查询当前进程有哪些信号处于等待状态,可以使用 `sigpending()` 函数获取这些信号。 `sigpending()` 的函数原型如下: ``` #include int sigpending(sigset_t *set); ``` - **参数:** - `set`:用于存放处于等待状态的信号集的地址。 - **返回值:** - 成功返回 0; - 失败返回 -1,并设置 `errno` 以指示错误原因。 该函数需要包含头文件 ``。 下面是一个示例,展示如何使用 `sigpending()` 函数判断 `SIGINT` 信号是否处于等待状态: ``` #include #include #include int main() { sigset_t sig_set; // 初始化信号集为空 sigemptyset(&sig_set); // 获取当前处于等待状态的信号 sigpending(&sig_set); // 判断 SIGINT 信号是否处于等待状态 if (sigismember(&sig_set, SIGINT)) { puts("SIGINT 信号处于等待状态"); } else { puts("SIGINT 信号未处于等待状态"); } return 0; } ``` 作者:不脱发的程序猿。来源:[CSDN 原文](https://blog.csdn.net/m0_38106923/article/details/141756522)(CC BY-SA 4.0)。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册