项目内容描述
1.能识别180度范围内的4个方向
2.精度要求把180度分成4份,人站在不同位置能大概分辨出位置即可。
请从上面所给出的需求中,提供一个详细深入精确的设计方案,声音方向识别。
解析与方案库:完整设计方案,包括系统框图、关键器件选型、软件流程图;
用通俗易懂的实例详细深入精确地解析说明。
设计一个声音方向识别系统,能识别180度范围内的4个方向(即每个方向约45度范围)。精度要求不高,把人站在不同位置能大概分辨出位置即可。需要提供详细设计方案,包括系统框图、关键器件选型、软件流程图、UML建模、文件结构等。
任务:为“声音方向识别”提供一个详细深入精确的设计方案。需要覆盖完整的设计,包括系统框图、关键器件选型、软件流程图;用通俗易懂的实例详细深入精确地解析说明;并用UML建模并提供具体详尽深入的方案,用Markdown和Mermaid建立文档,建立项目文件结构组织,详细深入精确地概述整个设计开发过程中的机理、方法、步骤、方案。
首先分析需求:“能识别180度范围内的4个方向”意味着设备可以检测声音来源在左侧、左前、右前、右侧(例如),将180度划分为4个扇区,每个扇区45度。精度要求不高,只要能区分大致方向即可。
方法:可采用多个麦克风阵列(例如4个麦克风)通过声源定位算法(如TDOA,到达时间差,或简单的幅度比较)。由于精度要求低,可以使用幅度差(ILD)或粗略的时延估计。可选用低成本的MEMS麦克风,配合MCU(如STM32)进行信号处理。输出可以是4个LED指示方向,或通过串口上报。
设计内容应包括:
- 系统框图:4个麦克风呈直线排列或十字形?180度覆盖,用2个麦克风只能分辨左右,要4个方向,可以3个麦克风等腰三角形?用4个麦克风呈180度圆弧排列,每个间隔45度,利用各麦克风接收到的信号强度来判断方向。简单有效:4个定向麦克风(或心形指向)安装在设备前方180度范围,分别朝向4个方向,然后比较哪个麦克风信号最强。但这样需要定向麦克风,不通用。另一种:使用4个全向麦克风组成的阵列,通过计算时延差估计方向。考虑到精度不高,可选用3个或4个麦克风等距直线阵列或圆形阵列。如3个麦克风等距直线(间距~5cm),可分辨左右,但前后?180度平面,可以用三个麦克风呈直角三角形或等边三角形?实际上二维定位需要至少3个麦克风。我们只需区分4个方向,可以在180度范围布置4个麦克风指向不同方向,通过比较能量大小,简单可靠。
设计实例:设备类似于一个基站,人站在180度范围内说话,设备上的4个LED灯指示方向。我们可以采用4个心形指向的麦克风(或全向麦加物理挡板形成指向性),分别对准前方0°、45°、90°、135°(右侧)。或者我们可以使用4个全向麦克风,通过波束成形(延迟求和)虚拟出4个方向的指向性。用STM32F407等MCU,4个ADC同步采样,做FFT计算能量,根据各通道能量大小判定方向。这种方法对算法要求低,适合低成本。
详细方案:
系统框图:4路MEMS麦克风 → 模拟放大 → STM32 ADC同步采样 → 数字带通滤波(人声频段300-3400Hz)→ 计算各通道能量 → 比较能量 → 输出方向。
关键器件:MEMS麦克风(如INMP441,数字I2S接口,可以简化采样,但需要4个I2S接口,MCU可能不够)。模拟麦克风如MAX9814带AGC,然后STM32多通道ADC。
- 可选:SPH0645LM4H-B(I2S数字麦克风),可通过I2S多通道或TDM方式,MCU如STM32H7有多个I2S。或者使用4个模拟麦克风+4个ADC通道,STM32F4有3个独立ADC,可同时采样。
软件流程图:初始化 → 定时采集音频(例如每10ms采集2048点) → FFT/能量计算 → 峰值检测 → 方向逻辑判断 → 输出LED/UART。
UML建模:类图、序列图、状态图。
项目文件结构。
提供一个通俗易懂的实例:比如一个圆盘底座,面向用户180度,有4个LED指示灯。当人站在左侧说话,左侧LED亮;左前、右前、右侧分别对应。技术上如何实现。
需要给出机理、方法、步骤、方案。
因此回答内容要包括:
-
项目概述
-
设计思路
-
系统架构框图(Mermaid)
-
关键器件选型表
-
软件流程图(Mermaid)
-
UML建模(用例图、类图、序列图、状态图)
-
核心机理深度解析(波束形成、能量比较法、TDOA)
-
项目文件结构组织
-
开发步骤与方法
-
总结
因为问题要求“声音方向识别”,以基于能量比较的麦克风阵列方案为主,因为要求精度不高,且能识别4个方向。
也会提及可以用声达时间差(TDOA)方法但更复杂,而能量法更简单。
方案具体、详尽。
声音方向识别系统(180° 四向)设计方案
1. 项目概述与典型实例
本方案设计一个低成本声音方向识别模块,能检测 180° 范围内声源所在的四个大致方向(每 45° 一个扇区),精度要求不高。系统通过四路心形麦克风阵列,利用能量比较法判断声源位置,结果通过 LED 指示或串口输出。
典型实例:
一个智能家居控制面板,平放在桌面,前方 180° 范围内有用户说话。设备表面的四个 LED 灯分别代表左后、左前、右前、右后四个方向。当用户站在左前方说“开灯”,对应的 LED 点亮,系统可联动转向该区域照明。
不需要精确到度,只需知道是哪个扇区。
2. 系统总体设计
2.1 设计思路
采用 四只心形指向模拟麦克风,物理上分别对准 0°(正前)、45°(左前)、90°(左侧)、135°(左后)。每只麦克风接收信号经放大、带通滤波后,由 MCU 四路 ADC 同步采样。对每路信号计算语音频段(300~3400Hz)的能量,能量最强的通道即为声源方向。
为什么用心形麦克风?
心形指向对正前方声音灵敏,对背面和侧面衰减大,天然具备方向选择能力,硬件上简化算法。若使用全向麦克风,则需通过阵列时延求和(波束成形)软实现指向,MCU 开销大。精度要求不高,心形麦是最佳选择。
2.2 硬件系统框图
#mermaid-svg-XfbcD6RdfQKvDTm4{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XfbcD6RdfQKvDTm4 .error-icon{fill:#552222;}#mermaid-svg-XfbcD6RdfQKvDTm4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XfbcD6RdfQKvDTm4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .marker.cross{stroke:#333333;}#mermaid-svg-XfbcD6RdfQKvDTm4 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XfbcD6RdfQKvDTm4 p{margin:0;}#mermaid-svg-XfbcD6RdfQKvDTm4 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster-label text{fill:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster-label span{color:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster-label span p{background-color:transparent;}#mermaid-svg-XfbcD6RdfQKvDTm4 .label text,#mermaid-svg-XfbcD6RdfQKvDTm4 span{fill:#333;color:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .node rect,#mermaid-svg-XfbcD6RdfQKvDTm4 .node circle,#mermaid-svg-XfbcD6RdfQKvDTm4 .node ellipse,#mermaid-svg-XfbcD6RdfQKvDTm4 .node polygon,#mermaid-svg-XfbcD6RdfQKvDTm4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .rough-node .label text,#mermaid-svg-XfbcD6RdfQKvDTm4 .node .label text,#mermaid-svg-XfbcD6RdfQKvDTm4 .image-shape .label,#mermaid-svg-XfbcD6RdfQKvDTm4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-XfbcD6RdfQKvDTm4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .rough-node .label,#mermaid-svg-XfbcD6RdfQKvDTm4 .node .label,#mermaid-svg-XfbcD6RdfQKvDTm4 .image-shape .label,#mermaid-svg-XfbcD6RdfQKvDTm4 .icon-shape .label{text-align:center;}#mermaid-svg-XfbcD6RdfQKvDTm4 .node.clickable{cursor:pointer;}#mermaid-svg-XfbcD6RdfQKvDTm4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .arrowheadPath{fill:#333333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XfbcD6RdfQKvDTm4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XfbcD6RdfQKvDTm4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XfbcD6RdfQKvDTm4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster text{fill:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 .cluster span{color:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XfbcD6RdfQKvDTm4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XfbcD6RdfQKvDTm4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-XfbcD6RdfQKvDTm4 .icon-shape,#mermaid-svg-XfbcD6RdfQKvDTm4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XfbcD6RdfQKvDTm4 .icon-shape p,#mermaid-svg-XfbcD6RdfQKvDTm4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XfbcD6RdfQKvDTm4 .icon-shape .label rect,#mermaid-svg-XfbcD6RdfQKvDTm4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XfbcD6RdfQKvDTm4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XfbcD6RdfQKvDTm4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XfbcD6RdfQKvDTm4 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
STM32F407VET6
4路心形麦克风阵列
电源
USB 5V
AMS1117-3.3V
麦克风0朝0°
放大 MAX9814
麦克风45°
放大 MAX9814
麦克风90°
放大 MAX9814
麦克风135°
放大 MAX9814
ADC1_CH0
ADC1_CH1
ADC2_CH2
ADC3_CH3
Cortex-M4 168MHz
定时器触发同步采样
4路DMA传输
数字带通滤波+能量计算
方向判断逻辑
4方向LED指示
串口输出
解释:四只指向性麦克风分别朝向 0°、45°、90°、135°(覆盖 180°),信号经放大后送入 STM32 的四个独立 ADC 通道(利用 3 个 ADC 模块同时采样),DMA 循环搬运数据。MCU 运行语音频段滤波与能量计算,实时比较各通道能量,能量最大者即为当前声源方向。
2.3 关键器件选型
| 麦克风 | 驻极体心形指向咪头 (9.7mm) | 成本低,心形特性明显,灵敏度 -42dB,频率响应 50-16kHz |
| 麦克风放大器 | MAX9814 (AGC 可关闭) | 集成低噪声放大器,可调增益,2.7-5.5V 供电,输出可直接送 ADC |
| 主控 MCU | STM32F407VET6 | 3 个 12-bit ADC (各 2.4Msps),4 个通道可同时采样(规则并行模式),168MHz,DMA,适合实时音频处理 |
| 电源 | AMS1117-3.3V | 5V→3.3V,1A,稳定可靠 |
| LED 指示 | 高亮 LED ×4(不同颜色) | 直观显示方向 |
| 串口 | USB 转 TTL (CH340) | 调试及上报方向数据 |
3. 软件流程图
3.1 主程序流程
#mermaid-svg-PbzvtE8C7BOjIUuv{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PbzvtE8C7BOjIUuv .error-icon{fill:#552222;}#mermaid-svg-PbzvtE8C7BOjIUuv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PbzvtE8C7BOjIUuv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PbzvtE8C7BOjIUuv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PbzvtE8C7BOjIUuv .marker.cross{stroke:#333333;}#mermaid-svg-PbzvtE8C7BOjIUuv svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PbzvtE8C7BOjIUuv p{margin:0;}#mermaid-svg-PbzvtE8C7BOjIUuv .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster-label text{fill:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster-label span{color:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster-label span p{background-color:transparent;}#mermaid-svg-PbzvtE8C7BOjIUuv .label text,#mermaid-svg-PbzvtE8C7BOjIUuv span{fill:#333;color:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv .node rect,#mermaid-svg-PbzvtE8C7BOjIUuv .node circle,#mermaid-svg-PbzvtE8C7BOjIUuv .node ellipse,#mermaid-svg-PbzvtE8C7BOjIUuv .node polygon,#mermaid-svg-PbzvtE8C7BOjIUuv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PbzvtE8C7BOjIUuv .rough-node .label text,#mermaid-svg-PbzvtE8C7BOjIUuv .node .label text,#mermaid-svg-PbzvtE8C7BOjIUuv .image-shape .label,#mermaid-svg-PbzvtE8C7BOjIUuv .icon-shape .label{text-anchor:middle;}#mermaid-svg-PbzvtE8C7BOjIUuv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PbzvtE8C7BOjIUuv .rough-node .label,#mermaid-svg-PbzvtE8C7BOjIUuv .node .label,#mermaid-svg-PbzvtE8C7BOjIUuv .image-shape .label,#mermaid-svg-PbzvtE8C7BOjIUuv .icon-shape .label{text-align:center;}#mermaid-svg-PbzvtE8C7BOjIUuv .node.clickable{cursor:pointer;}#mermaid-svg-PbzvtE8C7BOjIUuv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PbzvtE8C7BOjIUuv .arrowheadPath{fill:#333333;}#mermaid-svg-PbzvtE8C7BOjIUuv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PbzvtE8C7BOjIUuv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PbzvtE8C7BOjIUuv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PbzvtE8C7BOjIUuv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PbzvtE8C7BOjIUuv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PbzvtE8C7BOjIUuv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster text{fill:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv .cluster span{color:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PbzvtE8C7BOjIUuv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PbzvtE8C7BOjIUuv rect.text{fill:none;stroke-width:0;}#mermaid-svg-PbzvtE8C7BOjIUuv .icon-shape,#mermaid-svg-PbzvtE8C7BOjIUuv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PbzvtE8C7BOjIUuv .icon-shape p,#mermaid-svg-PbzvtE8C7BOjIUuv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PbzvtE8C7BOjIUuv .icon-shape .label rect,#mermaid-svg-PbzvtE8C7BOjIUuv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PbzvtE8C7BOjIUuv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PbzvtE8C7BOjIUuv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PbzvtE8C7BOjIUuv :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
每隔 100ms
否
是
否
是
上电
初始化: 时钟, ADC, DMA, 定时器, LED
采集静音噪声基底
启动 ADC 定时采样, 10kHz 每通道
主循环
已采集 1024 点?
每个通道做带通滤波 300-3400Hz
计算每通道 RMS 能量
找出能量最大的通道
最大能量 > 阈值?
判定无有效声源
点亮对应方向 LED串口发送方向码
清除缓存, 继续采集
说明:采样率 10kHz,每 100ms 处理 1024 点,满足人声频段(<4kHz)且足够快。阈值用于排除环境噪声。
3.2 带通滤波器实现
采用 双二阶 IIR 带通滤波器,中心频率 1.5kHz,Q=0.7,覆盖人声主要能量区。代码如下(伪):
b = [0.2, 0, -0.2]
a = [1, -1.5, 0.7]
在中断或主循环中调用直接Ⅰ型结构,计算量小。
3.3 能量计算与方向判定
每个通道的 RMS = sqrt( sum(samples^2) / N )。比较四个 RMS,取最大值索引。加入滞后:为防止频繁跳变,只有当新方向连续 3 次胜出才更新输出。
4. UML 建模
4.1 用例图
#mermaid-svg-ZFi6AoSQ6Ak10siz{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ZFi6AoSQ6Ak10siz .error-icon{fill:#552222;}#mermaid-svg-ZFi6AoSQ6Ak10siz .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ZFi6AoSQ6Ak10siz .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .marker.cross{stroke:#333333;}#mermaid-svg-ZFi6AoSQ6Ak10siz svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ZFi6AoSQ6Ak10siz p{margin:0;}#mermaid-svg-ZFi6AoSQ6Ak10siz .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster-label text{fill:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster-label span{color:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster-label span p{background-color:transparent;}#mermaid-svg-ZFi6AoSQ6Ak10siz .label text,#mermaid-svg-ZFi6AoSQ6Ak10siz span{fill:#333;color:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .node rect,#mermaid-svg-ZFi6AoSQ6Ak10siz .node circle,#mermaid-svg-ZFi6AoSQ6Ak10siz .node ellipse,#mermaid-svg-ZFi6AoSQ6Ak10siz .node polygon,#mermaid-svg-ZFi6AoSQ6Ak10siz .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .rough-node .label text,#mermaid-svg-ZFi6AoSQ6Ak10siz .node .label text,#mermaid-svg-ZFi6AoSQ6Ak10siz .image-shape .label,#mermaid-svg-ZFi6AoSQ6Ak10siz .icon-shape .label{text-anchor:middle;}#mermaid-svg-ZFi6AoSQ6Ak10siz .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .rough-node .label,#mermaid-svg-ZFi6AoSQ6Ak10siz .node .label,#mermaid-svg-ZFi6AoSQ6Ak10siz .image-shape .label,#mermaid-svg-ZFi6AoSQ6Ak10siz .icon-shape .label{text-align:center;}#mermaid-svg-ZFi6AoSQ6Ak10siz .node.clickable{cursor:pointer;}#mermaid-svg-ZFi6AoSQ6Ak10siz .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .arrowheadPath{fill:#333333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZFi6AoSQ6Ak10siz .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ZFi6AoSQ6Ak10siz .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZFi6AoSQ6Ak10siz .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster text{fill:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz .cluster span{color:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ZFi6AoSQ6Ak10siz .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ZFi6AoSQ6Ak10siz rect.text{fill:none;stroke-width:0;}#mermaid-svg-ZFi6AoSQ6Ak10siz .icon-shape,#mermaid-svg-ZFi6AoSQ6Ak10siz .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ZFi6AoSQ6Ak10siz .icon-shape p,#mermaid-svg-ZFi6AoSQ6Ak10siz .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ZFi6AoSQ6Ak10siz .icon-shape .label rect,#mermaid-svg-ZFi6AoSQ6Ak10siz .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ZFi6AoSQ6Ak10siz .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ZFi6AoSQ6Ak10siz .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ZFi6AoSQ6Ak10siz :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
使用者
发出声音
声音方向识别模块
检测并指示声音方向
通过串口输出方向数据
上位机
4.2 核心类图(C++ 抽象)
#mermaid-svg-0HC40tnSlEmYfRWL{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-0HC40tnSlEmYfRWL .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-0HC40tnSlEmYfRWL .error-icon{fill:#552222;}#mermaid-svg-0HC40tnSlEmYfRWL .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-0HC40tnSlEmYfRWL .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-0HC40tnSlEmYfRWL .marker{fill:#333333;stroke:#333333;}#mermaid-svg-0HC40tnSlEmYfRWL .marker.cross{stroke:#333333;}#mermaid-svg-0HC40tnSlEmYfRWL svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-0HC40tnSlEmYfRWL p{margin:0;}#mermaid-svg-0HC40tnSlEmYfRWL g.classGroup text{fill:#9370DB;stroke:none;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-0HC40tnSlEmYfRWL g.classGroup text .title{font-weight:bolder;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster-label text{fill:#333;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster-label span{color:#333;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster-label span p{background-color:transparent;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster text{fill:#333;}#mermaid-svg-0HC40tnSlEmYfRWL .cluster span{color:#333;}#mermaid-svg-0HC40tnSlEmYfRWL .nodeLabel,#mermaid-svg-0HC40tnSlEmYfRWL .edgeLabel{color:#131300;}#mermaid-svg-0HC40tnSlEmYfRWL .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-0HC40tnSlEmYfRWL .label text{fill:#131300;}#mermaid-svg-0HC40tnSlEmYfRWL .labelBkg{background:#ECECFF;}#mermaid-svg-0HC40tnSlEmYfRWL .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-0HC40tnSlEmYfRWL .classTitle{font-weight:bolder;}#mermaid-svg-0HC40tnSlEmYfRWL .node rect,#mermaid-svg-0HC40tnSlEmYfRWL .node circle,#mermaid-svg-0HC40tnSlEmYfRWL .node ellipse,#mermaid-svg-0HC40tnSlEmYfRWL .node polygon,#mermaid-svg-0HC40tnSlEmYfRWL .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-0HC40tnSlEmYfRWL .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL g.clickable{cursor:pointer;}#mermaid-svg-0HC40tnSlEmYfRWL g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-0HC40tnSlEmYfRWL g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-0HC40tnSlEmYfRWL .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-0HC40tnSlEmYfRWL .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-0HC40tnSlEmYfRWL .dashed-line{stroke-dasharray:3;}#mermaid-svg-0HC40tnSlEmYfRWL .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-0HC40tnSlEmYfRWL #compositionStart,#mermaid-svg-0HC40tnSlEmYfRWL .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #compositionEnd,#mermaid-svg-0HC40tnSlEmYfRWL .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #dependencyStart,#mermaid-svg-0HC40tnSlEmYfRWL .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #dependencyStart,#mermaid-svg-0HC40tnSlEmYfRWL .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #extensionStart,#mermaid-svg-0HC40tnSlEmYfRWL .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #extensionEnd,#mermaid-svg-0HC40tnSlEmYfRWL .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #aggregationStart,#mermaid-svg-0HC40tnSlEmYfRWL .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #aggregationEnd,#mermaid-svg-0HC40tnSlEmYfRWL .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #lollipopStart,#mermaid-svg-0HC40tnSlEmYfRWL .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL #lollipopEnd,#mermaid-svg-0HC40tnSlEmYfRWL .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-0HC40tnSlEmYfRWL .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-0HC40tnSlEmYfRWL .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-0HC40tnSlEmYfRWL .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-0HC40tnSlEmYfRWL .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-0HC40tnSlEmYfRWL :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
DirectionDetector
– MicChannel channels[4]
– FIRFilter filter
– int currentDirection
+ update()
+ getDirection() : int
MicChannel
– ADC_Driver* adc
– float buffer[1024]
+ collectSamples()
+ getRMS() : float
FIRFilter
– float coeff_b[3], coeff_a[3]
+ apply(input, output)
4.3 序列图:一次方向检测
LED指示DirectionDetectorMicChannel定时器LED指示DirectionDetectorMicChannel定时器#mermaid-svg-cThmtyVvTQ5HRtXu{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-cThmtyVvTQ5HRtXu .error-icon{fill:#552222;}#mermaid-svg-cThmtyVvTQ5HRtXu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-cThmtyVvTQ5HRtXu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-cThmtyVvTQ5HRtXu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-cThmtyVvTQ5HRtXu .marker.cross{stroke:#333333;}#mermaid-svg-cThmtyVvTQ5HRtXu svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-cThmtyVvTQ5HRtXu p{margin:0;}#mermaid-svg-cThmtyVvTQ5HRtXu .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cThmtyVvTQ5HRtXu text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-cThmtyVvTQ5HRtXu .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-cThmtyVvTQ5HRtXu .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-cThmtyVvTQ5HRtXu #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-cThmtyVvTQ5HRtXu .sequenceNumber{fill:white;}#mermaid-svg-cThmtyVvTQ5HRtXu #sequencenumber{fill:#333;}#mermaid-svg-cThmtyVvTQ5HRtXu #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-cThmtyVvTQ5HRtXu .messageText{fill:#333;stroke:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cThmtyVvTQ5HRtXu .labelText,#mermaid-svg-cThmtyVvTQ5HRtXu .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .loopText,#mermaid-svg-cThmtyVvTQ5HRtXu .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-cThmtyVvTQ5HRtXu .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-cThmtyVvTQ5HRtXu .noteText,#mermaid-svg-cThmtyVvTQ5HRtXu .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-cThmtyVvTQ5HRtXu .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cThmtyVvTQ5HRtXu .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cThmtyVvTQ5HRtXu .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-cThmtyVvTQ5HRtXu .actorPopupMenu{position:absolute;}#mermaid-svg-cThmtyVvTQ5HRtXu .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-cThmtyVvTQ5HRtXu .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-cThmtyVvTQ5HRtXu .actor-man circle,#mermaid-svg-cThmtyVvTQ5HRtXu line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-cThmtyVvTQ5HRtXu :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}触发采样DMA 接收 1024 点通知数据就绪获取4通道RMS比较能量,选出最大点亮对应方向LED
4.4 方向状态机
#mermaid-svg-hMKUOlk1nm2X6Eia{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hMKUOlk1nm2X6Eia .error-icon{fill:#552222;}#mermaid-svg-hMKUOlk1nm2X6Eia .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hMKUOlk1nm2X6Eia .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hMKUOlk1nm2X6Eia .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia .marker.cross{stroke:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hMKUOlk1nm2X6Eia p{margin:0;}#mermaid-svg-hMKUOlk1nm2X6Eia defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-hMKUOlk1nm2X6Eia g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-hMKUOlk1nm2X6Eia g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-hMKUOlk1nm2X6Eia g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-hMKUOlk1nm2X6Eia g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-hMKUOlk1nm2X6Eia .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-hMKUOlk1nm2X6Eia .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-hMKUOlk1nm2X6Eia .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-hMKUOlk1nm2X6Eia .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-hMKUOlk1nm2X6Eia .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-hMKUOlk1nm2X6Eia .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hMKUOlk1nm2X6Eia .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hMKUOlk1nm2X6Eia .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hMKUOlk1nm2X6Eia .edgeLabel .label text{fill:#333;}#mermaid-svg-hMKUOlk1nm2X6Eia .label div .edgeLabel{color:#333;}#mermaid-svg-hMKUOlk1nm2X6Eia .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-hMKUOlk1nm2X6Eia .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-hMKUOlk1nm2X6Eia .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-hMKUOlk1nm2X6Eia .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia #statediagram-barbEnd{fill:#333333;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hMKUOlk1nm2X6Eia .cluster-label,#mermaid-svg-hMKUOlk1nm2X6Eia .nodeLabel{color:#131300;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-hMKUOlk1nm2X6Eia .note-edge{stroke-dasharray:5;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-note text{fill:black;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram-note .nodeLabel{color:black;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagram .edgeLabel{color:red;}#mermaid-svg-hMKUOlk1nm2X6Eia #dependencyStart,#mermaid-svg-hMKUOlk1nm2X6Eia #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-hMKUOlk1nm2X6Eia .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hMKUOlk1nm2X6Eia :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
Ch0能量最大
Ch1能量最大
Ch2能量最大
Ch3能量最大
无足够能量
Silence
Dir0
Dir1
Dir2
Dir3
5. 核心机理深度解析
5.1 心形麦克风指向性原理
心形指向 = 全向 + 双向 的合成。正面灵敏度高,180° 背面灵敏度极低。四只麦克风物理安装如图:
背面
麦克3(135°) 麦克0(0°)
\\ /
\\ 设备 /
\\ /
\\ /
中心
/ \\
/ \\
麦克2(90°) 麦克1(45°)
右侧 右前
实际 180° 范围被划分为:左后 (135°~180°),左前 (90°~135°),右前 (45°~90°),右侧 (0°~45°)。每个麦克风主瓣对应一个扇区。由于心形曲线在主瓣附近灵敏度相近,当人站在 45° 附近时,麦克 1 和麦克 0 可能都有输出,但麦克 1 相对能量更强,仍可正确识别。
5.2 能量比较与干扰滤除
- 语音频段滤波:人声能量集中在 300~3400Hz,用 IIR 带通滤波可滤除低频风噪、高频电路噪声。
- 静音阈值:根据静音时的噪声基底设定阈值,低于阈值视为无有效声源。
- 去毛刺:能量比较后,连续多帧一致才确认方向,防止瞬间干扰。
5.3 采样同步
STM32F407 有 3 个独立 ADC,可配置为 双重/三重同步模式。本设计需 4 个通道,可启用 ADC1+ADC2 同步(各两通道),或 ADC1 注入通道与 ADC2/3 配合,确保所有通道严格对齐采样时刻,避免时延导致能量偏差。
6. 项目文件结构组织
sound_direction_detector/
├── hardware/
│ ├── schematic/ # 原理图 (AD)
│ │ ├── mic_array.sch
│ │ ├── mcu_board.sch
│ └── pcb/ # PCB 文件
│ └── bom/ # 物料清单
├── firmware/
│ ├── Core/
│ │ ├── Inc/ # 头文件
│ │ └── Src/
│ │ ├── main.c
│ │ ├── adc_drv.c/h
│ │ ├── fir_filter.c/h
│ │ ├── direction_detect.c/h
│ │ └── led_uart.c/h
│ ├── Drivers/
│ │ └── STM32F4xx_HAL/
│ └── MDK-ARM/ # Keil 工程
├── docs/
│ ├── system_design.md # 本设计文档
│ ├── uml/ # UML 源文件
│ └── user_manual.pdf
├── test/
│ └── pyaudio_test.py # 上位机模拟测试脚本
└── README.md
7. 开发方法与步骤
阶段 1:硬件搭建(1 周)
- 焊接 4 个心形麦克风及 MAX9814 模块,调至适当增益(测试输出幅值 1Vpp 左右)。
- 连接至 STM32F407 开发板对应 ADC 引脚。
- 烧录测试程序,用示波器观察各路音频波形。
阶段 2:信号采集与处理(1 周)
- 配置 ADC 同步采样、DMA 循环缓冲。
- 实现双二阶 IIR 带通滤波,调试系数。
- 计算 RMS 能量,串口打印四路能量值。
阶段 3:方向判定算法(0.5 周)
- 添加阈值判定、滞后逻辑。
- 编写 LED 指示和串口输出。
- 在不同位置说话,验证方向识别正确率。
阶段 4:优化与测试(0.5 周)
- 噪声环境下测试(风扇、空调),调整阈值。
- 多角度测试,绘制识别正确率图。
- 编写技术文档。
8. 总结
本方案采用 4 只心形指向麦克风 + STM32F407 同步采样 的方式,以极简的硬件和算法实现了 180° 四向声源定位。相比复杂的麦克风阵列波束成形,利用物理指向性大幅降低成本和开发难度,同时满足“精度不高,能分辨大致方向”的需求。完整的 UML 建模和软件流程为项目的快速落地提供了清晰指导。# 声音方向识别系统(180° 四向)设计方案
1. 项目概述与典型实例
本项目实现一个 低成本声音方向识别模块,能将 180° 平面内的声源定位到 4 个大致方向(每个扇区约 45°),精度要求不高。系统通过 4 路心形指向麦克风 物理区分方向,利用 能量比较法 判断声源所在扇区,结果通过 LED 或串口输出。
通俗实例:
一个智能音箱放在电视柜上,正面 180° 范围内有人说话。音箱上有 4 颗 LED,分别代表“左后方、左前方、右前方、右后方”。当人站在左前方说“播放音乐”,对应的 LED 点亮,音箱可以据此调整语音唤醒的灵敏度方向或联动其他智能设备。不需要精确角度,只要知道是哪个大概区域就行。
2. 系统总体架构
2.1 设计思路
使用 4 个心形指向驻极体麦克风,物理上分别对准 0°、45°、90°、135°(覆盖 180°)。每个麦克风后的放大电路将信号调理到合适幅度,然后送入 STM32F407 的 4 个 ADC 通道进行同步采样。MCU 对每路信号做 人声频段带通滤波,实时计算 短时能量,能量最强的通道即为当前声音方向。这种方案天然利用麦克风的物理指向性,算法简单,抗干扰能力强。
2.2 系统框图
#mermaid-svg-uUP9d0VQRlvvFOoE{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uUP9d0VQRlvvFOoE .error-icon{fill:#552222;}#mermaid-svg-uUP9d0VQRlvvFOoE .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uUP9d0VQRlvvFOoE .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uUP9d0VQRlvvFOoE .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uUP9d0VQRlvvFOoE .marker.cross{stroke:#333333;}#mermaid-svg-uUP9d0VQRlvvFOoE svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uUP9d0VQRlvvFOoE p{margin:0;}#mermaid-svg-uUP9d0VQRlvvFOoE .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster-label text{fill:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster-label span{color:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster-label span p{background-color:transparent;}#mermaid-svg-uUP9d0VQRlvvFOoE .label text,#mermaid-svg-uUP9d0VQRlvvFOoE span{fill:#333;color:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE .node rect,#mermaid-svg-uUP9d0VQRlvvFOoE .node circle,#mermaid-svg-uUP9d0VQRlvvFOoE .node ellipse,#mermaid-svg-uUP9d0VQRlvvFOoE .node polygon,#mermaid-svg-uUP9d0VQRlvvFOoE .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-uUP9d0VQRlvvFOoE .rough-node .label text,#mermaid-svg-uUP9d0VQRlvvFOoE .node .label text,#mermaid-svg-uUP9d0VQRlvvFOoE .image-shape .label,#mermaid-svg-uUP9d0VQRlvvFOoE .icon-shape .label{text-anchor:middle;}#mermaid-svg-uUP9d0VQRlvvFOoE .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-uUP9d0VQRlvvFOoE .rough-node .label,#mermaid-svg-uUP9d0VQRlvvFOoE .node .label,#mermaid-svg-uUP9d0VQRlvvFOoE .image-shape .label,#mermaid-svg-uUP9d0VQRlvvFOoE .icon-shape .label{text-align:center;}#mermaid-svg-uUP9d0VQRlvvFOoE .node.clickable{cursor:pointer;}#mermaid-svg-uUP9d0VQRlvvFOoE .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-uUP9d0VQRlvvFOoE .arrowheadPath{fill:#333333;}#mermaid-svg-uUP9d0VQRlvvFOoE .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-uUP9d0VQRlvvFOoE .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-uUP9d0VQRlvvFOoE .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uUP9d0VQRlvvFOoE .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-uUP9d0VQRlvvFOoE .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uUP9d0VQRlvvFOoE .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster text{fill:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE .cluster span{color:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-uUP9d0VQRlvvFOoE .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-uUP9d0VQRlvvFOoE rect.text{fill:none;stroke-width:0;}#mermaid-svg-uUP9d0VQRlvvFOoE .icon-shape,#mermaid-svg-uUP9d0VQRlvvFOoE .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-uUP9d0VQRlvvFOoE .icon-shape p,#mermaid-svg-uUP9d0VQRlvvFOoE .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-uUP9d0VQRlvvFOoE .icon-shape .label rect,#mermaid-svg-uUP9d0VQRlvvFOoE .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-uUP9d0VQRlvvFOoE .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-uUP9d0VQRlvvFOoE .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-uUP9d0VQRlvvFOoE :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
STM32F407VET6
心形麦克风阵列
麦克风0朝向0°
MAX9814
麦克风45°
MAX9814
麦克风90°
MAX9814
麦克风135°
MAX9814
ADC1_IN0
ADC1_IN1
ADC2_IN2
ADC3_IN3
Cortex-M4 168MHz
定时器触发采样
4通道DMA
带通滤波+能量计算
方向判定逻辑
4路LED指示
串口输出方向
USB 5V
AMS1117-3.3V
解释:麦克风拾取的音频信号经 MAX9814 放大后(增益可调),输出 0~3.3V 模拟电压。STM32 的 3 个独立 ADC 模块配置为同步规则模式,实现 4 路信号严格同时采样,避免时延误差。采集到的数据通过 DMA 存入缓冲区,CPU 在主循环中处理。
2.3 关键器件选型
| 麦克风 | 心形指向驻极体咪头 (9.7mm) | -42dB 灵敏度,心形特性明显,50~16kHz,价格低 |
| 放大器 | MAX9814 (模块) | 内置低噪放,增益可调,2.7~5.5V供电,输出可直接接 ADC |
| 主控MCU | STM32F407VET6 | 3 个独立 ADC,每个 2.4Msps,支持同步采样,168MHz,DMA,适合实时处理 |
| 电源 | AMS1117-3.3V | 5V转3.3V,1A,简单可靠 |
| LED | 高亮 LED ×4(红绿蓝黄) | 指示方向 |
| 串口 | USB-TTL(CH340) | 调试及上报 |
3. 软件流程图
3.1 主程序流程
#mermaid-svg-8AUMkrWm1jOvnyoj{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-8AUMkrWm1jOvnyoj .error-icon{fill:#552222;}#mermaid-svg-8AUMkrWm1jOvnyoj .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-8AUMkrWm1jOvnyoj .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-8AUMkrWm1jOvnyoj .marker{fill:#333333;stroke:#333333;}#mermaid-svg-8AUMkrWm1jOvnyoj .marker.cross{stroke:#333333;}#mermaid-svg-8AUMkrWm1jOvnyoj svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-8AUMkrWm1jOvnyoj p{margin:0;}#mermaid-svg-8AUMkrWm1jOvnyoj .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster-label text{fill:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster-label span{color:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster-label span p{background-color:transparent;}#mermaid-svg-8AUMkrWm1jOvnyoj .label text,#mermaid-svg-8AUMkrWm1jOvnyoj span{fill:#333;color:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj .node rect,#mermaid-svg-8AUMkrWm1jOvnyoj .node circle,#mermaid-svg-8AUMkrWm1jOvnyoj .node ellipse,#mermaid-svg-8AUMkrWm1jOvnyoj .node polygon,#mermaid-svg-8AUMkrWm1jOvnyoj .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-8AUMkrWm1jOvnyoj .rough-node .label text,#mermaid-svg-8AUMkrWm1jOvnyoj .node .label text,#mermaid-svg-8AUMkrWm1jOvnyoj .image-shape .label,#mermaid-svg-8AUMkrWm1jOvnyoj .icon-shape .label{text-anchor:middle;}#mermaid-svg-8AUMkrWm1jOvnyoj .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-8AUMkrWm1jOvnyoj .rough-node .label,#mermaid-svg-8AUMkrWm1jOvnyoj .node .label,#mermaid-svg-8AUMkrWm1jOvnyoj .image-shape .label,#mermaid-svg-8AUMkrWm1jOvnyoj .icon-shape .label{text-align:center;}#mermaid-svg-8AUMkrWm1jOvnyoj .node.clickable{cursor:pointer;}#mermaid-svg-8AUMkrWm1jOvnyoj .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-8AUMkrWm1jOvnyoj .arrowheadPath{fill:#333333;}#mermaid-svg-8AUMkrWm1jOvnyoj .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-8AUMkrWm1jOvnyoj .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-8AUMkrWm1jOvnyoj .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8AUMkrWm1jOvnyoj .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-8AUMkrWm1jOvnyoj .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8AUMkrWm1jOvnyoj .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster text{fill:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj .cluster span{color:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-8AUMkrWm1jOvnyoj .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-8AUMkrWm1jOvnyoj rect.text{fill:none;stroke-width:0;}#mermaid-svg-8AUMkrWm1jOvnyoj .icon-shape,#mermaid-svg-8AUMkrWm1jOvnyoj .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-8AUMkrWm1jOvnyoj .icon-shape p,#mermaid-svg-8AUMkrWm1jOvnyoj .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-8AUMkrWm1jOvnyoj .icon-shape .label rect,#mermaid-svg-8AUMkrWm1jOvnyoj .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-8AUMkrWm1jOvnyoj .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-8AUMkrWm1jOvnyoj .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-8AUMkrWm1jOvnyoj :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
每100ms
否
是
否
是
否
是
上电初始化
配置时钟,ADC,DMA,定时器
采集静音噪声基底
启动定时器触发ADC采样
主循环
采集够1024点?
4路分别带通滤波 300-3400Hz
计算各通道短时能量(RMS)
找出能量最大的通道
最大能量 > 噪声阈值?
判定无有效声源, LED全灭
连续3帧方向一致?
更新缓存, 不清除输出
点亮对应LED, 串口发送方向码
清空缓冲, 继续采集
3.2 数字带通滤波器
采用 IIR 双二阶带通,中心频率 1.5kHz,Q=0.7,系数:
b = [0.1367, 0, -0.1367]
a = [1, -1.483, 0.7265]
实现采用直接Ⅰ型结构,每个采样点只需 5 次乘加,4 路完全可实时。
3.3 能量计算与方向判定
每帧 1024 点,计算 RMS:
rms = sqrt( sum(sample^2) / 1024 )
比较四路 RMS,最大值索引即为方向候选。加入滞后:只有当连续 3 次胜出才更新输出,避免因环境反射导致频繁跳变。
4. UML 建模
4.1 用例图
#mermaid-svg-hKros0GCZfAgwYk4{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-hKros0GCZfAgwYk4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-hKros0GCZfAgwYk4 .error-icon{fill:#552222;}#mermaid-svg-hKros0GCZfAgwYk4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-hKros0GCZfAgwYk4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-hKros0GCZfAgwYk4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-hKros0GCZfAgwYk4 .marker.cross{stroke:#333333;}#mermaid-svg-hKros0GCZfAgwYk4 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-hKros0GCZfAgwYk4 p{margin:0;}#mermaid-svg-hKros0GCZfAgwYk4 .label{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;color:#333;}#mermaid-svg-hKros0GCZfAgwYk4 .cluster-label text{fill:#333;}#mermaid-svg-hKros0GCZfAgwYk4 .cluster-label span{color:#333;}#mermaid-svg-hKros0GCZfAgwYk4 .cluster-label span p{background-color:transparent;}#mermaid-svg-hKros0GCZfAgwYk4 .label text,#mermaid-svg-hKros0GCZfAgwYk4 span{fill:#333;color:#333;}#mermaid-svg-hKros0GCZfAgwYk4 .node rect,#mermaid-svg-hKros0GCZfAgwYk4 .node circle,#mermaid-svg-hKros0GCZfAgwYk4 .node ellipse,#mermaid-svg-hKros0GCZfAgwYk4 .node polygon,#mermaid-svg-hKros0GCZfAgwYk4 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-hKros0GCZfAgwYk4 .rough-node .label text,#mermaid-svg-hKros0GCZfAgwYk4 .node .label text,#mermaid-svg-hKros0GCZfAgwYk4 .image-shape .label,#mermaid-svg-hKros0GCZfAgwYk4 .icon-shape .label{text-anchor:middle;}#mermaid-svg-hKros0GCZfAgwYk4 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-hKros0GCZfAgwYk4 .rough-node .label,#mermaid-svg-hKros0GCZfAgwYk4 .node .label,#mermaid-svg-hKros0GCZfAgwYk4 .image-shape .label,#mermaid-svg-hKros0GCZfAgwYk4 .icon-shape .label{text-align:center;}#mermaid-svg-hKros0GCZfAgwYk4 .node.clickable{cursor:pointer;}#mermaid-svg-hKros0GCZfAgwYk4 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-hKros0GCZfAgwYk4 .arrowheadPath{fill:#333333;}#mermaid-svg-hKros0GCZfAgwYk4 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-hKros0GCZfAgwYk4 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-hKros0GCZfAgwYk4 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hKros0GCZfAgwYk4 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-hKros0GCZfAgwYk4 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hKros0GCZfAgwYk4 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-hKros0GCZfAgwYk4 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-hKros0GCZfAgwYk4 .cluster text{fill:#333;}#mermaid-svg-hKros0GCZfAgwYk4 .cluster span{color:#333;}#mermaid-svg-hKros0GCZfAgwYk4 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-hKros0GCZfAgwYk4 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-hKros0GCZfAgwYk4 rect.text{fill:none;stroke-width:0;}#mermaid-svg-hKros0GCZfAgwYk4 .icon-shape,#mermaid-svg-hKros0GCZfAgwYk4 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-hKros0GCZfAgwYk4 .icon-shape p,#mermaid-svg-hKros0GCZfAgwYk4 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-hKros0GCZfAgwYk4 .icon-shape .label rect,#mermaid-svg-hKros0GCZfAgwYk4 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-hKros0GCZfAgwYk4 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-hKros0GCZfAgwYk4 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-hKros0GCZfAgwYk4 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
用户
发出声音
方向识别系统
检测声音方向
通过LED指示方向
串口上报方向数据
上位机
4.2 类图(固件抽象)
#mermaid-svg-eBf5KAPgbBSjo159{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-eBf5KAPgbBSjo159 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-eBf5KAPgbBSjo159 .error-icon{fill:#552222;}#mermaid-svg-eBf5KAPgbBSjo159 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-eBf5KAPgbBSjo159 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-eBf5KAPgbBSjo159 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-eBf5KAPgbBSjo159 .marker.cross{stroke:#333333;}#mermaid-svg-eBf5KAPgbBSjo159 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-eBf5KAPgbBSjo159 p{margin:0;}#mermaid-svg-eBf5KAPgbBSjo159 g.classGroup text{fill:#9370DB;stroke:none;font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:10px;}#mermaid-svg-eBf5KAPgbBSjo159 g.classGroup text .title{font-weight:bolder;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster-label text{fill:#333;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster-label span{color:#333;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster-label span p{background-color:transparent;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster text{fill:#333;}#mermaid-svg-eBf5KAPgbBSjo159 .cluster span{color:#333;}#mermaid-svg-eBf5KAPgbBSjo159 .nodeLabel,#mermaid-svg-eBf5KAPgbBSjo159 .edgeLabel{color:#131300;}#mermaid-svg-eBf5KAPgbBSjo159 .edgeLabel .label rect{fill:#ECECFF;}#mermaid-svg-eBf5KAPgbBSjo159 .label text{fill:#131300;}#mermaid-svg-eBf5KAPgbBSjo159 .labelBkg{background:#ECECFF;}#mermaid-svg-eBf5KAPgbBSjo159 .edgeLabel .label span{background:#ECECFF;}#mermaid-svg-eBf5KAPgbBSjo159 .classTitle{font-weight:bolder;}#mermaid-svg-eBf5KAPgbBSjo159 .node rect,#mermaid-svg-eBf5KAPgbBSjo159 .node circle,#mermaid-svg-eBf5KAPgbBSjo159 .node ellipse,#mermaid-svg-eBf5KAPgbBSjo159 .node polygon,#mermaid-svg-eBf5KAPgbBSjo159 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-eBf5KAPgbBSjo159 .divider{stroke:#9370DB;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 g.clickable{cursor:pointer;}#mermaid-svg-eBf5KAPgbBSjo159 g.classGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-eBf5KAPgbBSjo159 g.classGroup line{stroke:#9370DB;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 .classLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-eBf5KAPgbBSjo159 .classLabel .label{fill:#9370DB;font-size:10px;}#mermaid-svg-eBf5KAPgbBSjo159 .relation{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-eBf5KAPgbBSjo159 .dashed-line{stroke-dasharray:3;}#mermaid-svg-eBf5KAPgbBSjo159 .dotted-line{stroke-dasharray:1 2;}#mermaid-svg-eBf5KAPgbBSjo159 #compositionStart,#mermaid-svg-eBf5KAPgbBSjo159 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #compositionEnd,#mermaid-svg-eBf5KAPgbBSjo159 .composition{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #dependencyStart,#mermaid-svg-eBf5KAPgbBSjo159 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #dependencyStart,#mermaid-svg-eBf5KAPgbBSjo159 .dependency{fill:#333333!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #extensionStart,#mermaid-svg-eBf5KAPgbBSjo159 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #extensionEnd,#mermaid-svg-eBf5KAPgbBSjo159 .extension{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #aggregationStart,#mermaid-svg-eBf5KAPgbBSjo159 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #aggregationEnd,#mermaid-svg-eBf5KAPgbBSjo159 .aggregation{fill:transparent!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #lollipopStart,#mermaid-svg-eBf5KAPgbBSjo159 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 #lollipopEnd,#mermaid-svg-eBf5KAPgbBSjo159 .lollipop{fill:#ECECFF!important;stroke:#333333!important;stroke-width:1;}#mermaid-svg-eBf5KAPgbBSjo159 .edgeTerminals{font-size:11px;line-height:initial;}#mermaid-svg-eBf5KAPgbBSjo159 .classTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-eBf5KAPgbBSjo159 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-eBf5KAPgbBSjo159 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-eBf5KAPgbBSjo159 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
uses
DirectionDetector
– MicChannel channels[4]
– IIRFilter filter
– int currentDirection
+ update()
+ getDirection() : int
MicChannel
– ADC_HandleTypeDef* hadc
– float buffer[1024]
+ collect()
+ getRMS() : float
IIRFilter
– float b[3], a[3]
+ apply(input) : float
LEDIndicator
+ showDirection(int dir)
+ clear()
4.3 序列图:一次方向检测
UARTLEDIndicatorDirectionDetector4xMicChannel定时器UARTLEDIndicatorDirectionDetector4xMicChannel定时器#mermaid-svg-PmEIMqzaePbX8du8{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PmEIMqzaePbX8du8 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PmEIMqzaePbX8du8 .error-icon{fill:#552222;}#mermaid-svg-PmEIMqzaePbX8du8 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PmEIMqzaePbX8du8 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PmEIMqzaePbX8du8 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PmEIMqzaePbX8du8 .marker.cross{stroke:#333333;}#mermaid-svg-PmEIMqzaePbX8du8 svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PmEIMqzaePbX8du8 p{margin:0;}#mermaid-svg-PmEIMqzaePbX8du8 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PmEIMqzaePbX8du8 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-PmEIMqzaePbX8du8 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PmEIMqzaePbX8du8 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-PmEIMqzaePbX8du8 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-PmEIMqzaePbX8du8 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-PmEIMqzaePbX8du8 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-PmEIMqzaePbX8du8 .sequenceNumber{fill:white;}#mermaid-svg-PmEIMqzaePbX8du8 #sequencenumber{fill:#333;}#mermaid-svg-PmEIMqzaePbX8du8 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-PmEIMqzaePbX8du8 .messageText{fill:#333;stroke:none;}#mermaid-svg-PmEIMqzaePbX8du8 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PmEIMqzaePbX8du8 .labelText,#mermaid-svg-PmEIMqzaePbX8du8 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-PmEIMqzaePbX8du8 .loopText,#mermaid-svg-PmEIMqzaePbX8du8 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-PmEIMqzaePbX8du8 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-PmEIMqzaePbX8du8 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-PmEIMqzaePbX8du8 .noteText,#mermaid-svg-PmEIMqzaePbX8du8 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-PmEIMqzaePbX8du8 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PmEIMqzaePbX8du8 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PmEIMqzaePbX8du8 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-PmEIMqzaePbX8du8 .actorPopupMenu{position:absolute;}#mermaid-svg-PmEIMqzaePbX8du8 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-PmEIMqzaePbX8du8 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-PmEIMqzaePbX8du8 .actor-man circle,#mermaid-svg-PmEIMqzaePbX8du8 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-PmEIMqzaePbX8du8 :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}触发同步采样DMA 接收1024点通知数据就绪获取4通道RMS带通滤波+比较能量点亮对应方向LED串口输出方向码
4.4 方向状态机
#mermaid-svg-TpT1TUox2VzgSSol{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-TpT1TUox2VzgSSol .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-TpT1TUox2VzgSSol .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-TpT1TUox2VzgSSol .error-icon{fill:#552222;}#mermaid-svg-TpT1TUox2VzgSSol .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-TpT1TUox2VzgSSol .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-TpT1TUox2VzgSSol .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-TpT1TUox2VzgSSol .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-TpT1TUox2VzgSSol .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-TpT1TUox2VzgSSol .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-TpT1TUox2VzgSSol .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-TpT1TUox2VzgSSol .marker{fill:#333333;stroke:#333333;}#mermaid-svg-TpT1TUox2VzgSSol .marker.cross{stroke:#333333;}#mermaid-svg-TpT1TUox2VzgSSol svg{font-family:\”trebuchet ms\”,verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-TpT1TUox2VzgSSol p{margin:0;}#mermaid-svg-TpT1TUox2VzgSSol defs #statediagram-barbEnd{fill:#333333;stroke:#333333;}#mermaid-svg-TpT1TUox2VzgSSol g.stateGroup text{fill:#9370DB;stroke:none;font-size:10px;}#mermaid-svg-TpT1TUox2VzgSSol g.stateGroup text{fill:#333;stroke:none;font-size:10px;}#mermaid-svg-TpT1TUox2VzgSSol g.stateGroup .state-title{font-weight:bolder;fill:#131300;}#mermaid-svg-TpT1TUox2VzgSSol g.stateGroup rect{fill:#ECECFF;stroke:#9370DB;}#mermaid-svg-TpT1TUox2VzgSSol g.stateGroup line{stroke:#333333;stroke-width:1;}#mermaid-svg-TpT1TUox2VzgSSol .transition{stroke:#333333;stroke-width:1;fill:none;}#mermaid-svg-TpT1TUox2VzgSSol .stateGroup .composit{fill:white;border-bottom:1px;}#mermaid-svg-TpT1TUox2VzgSSol .stateGroup .alt-composit{fill:#e0e0e0;border-bottom:1px;}#mermaid-svg-TpT1TUox2VzgSSol .state-note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-TpT1TUox2VzgSSol .state-note text{fill:black;stroke:none;font-size:10px;}#mermaid-svg-TpT1TUox2VzgSSol .stateLabel .box{stroke:none;stroke-width:0;fill:#ECECFF;opacity:0.5;}#mermaid-svg-TpT1TUox2VzgSSol .edgeLabel .label rect{fill:#ECECFF;opacity:0.5;}#mermaid-svg-TpT1TUox2VzgSSol .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-TpT1TUox2VzgSSol .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-TpT1TUox2VzgSSol .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-TpT1TUox2VzgSSol .edgeLabel .label text{fill:#333;}#mermaid-svg-TpT1TUox2VzgSSol .label div .edgeLabel{color:#333;}#mermaid-svg-TpT1TUox2VzgSSol .stateLabel text{fill:#131300;font-size:10px;font-weight:bold;}#mermaid-svg-TpT1TUox2VzgSSol .node circle.state-start{fill:#333333;stroke:#333333;}#mermaid-svg-TpT1TUox2VzgSSol .node .fork-join{fill:#333333;stroke:#333333;}#mermaid-svg-TpT1TUox2VzgSSol .node circle.state-end{fill:#9370DB;stroke:white;stroke-width:1.5;}#mermaid-svg-TpT1TUox2VzgSSol .end-state-inner{fill:white;stroke-width:1.5;}#mermaid-svg-TpT1TUox2VzgSSol .node rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TpT1TUox2VzgSSol .node polygon{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TpT1TUox2VzgSSol #statediagram-barbEnd{fill:#333333;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-cluster rect{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-TpT1TUox2VzgSSol .cluster-label,#mermaid-svg-TpT1TUox2VzgSSol .nodeLabel{color:#131300;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-cluster rect.outer{rx:5px;ry:5px;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-state .divider{stroke:#9370DB;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-state .title-state{rx:5px;ry:5px;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-cluster.statediagram-cluster .inner{fill:white;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-cluster.statediagram-cluster-alt .inner{fill:#f0f0f0;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-cluster .inner{rx:0;ry:0;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-state rect.basic{rx:5px;ry:5px;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-state rect.divider{stroke-dasharray:10,10;fill:#f0f0f0;}#mermaid-svg-TpT1TUox2VzgSSol .note-edge{stroke-dasharray:5;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-note rect{fill:#fff5ad;stroke:#aaaa33;stroke-width:1px;rx:0;ry:0;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-note text{fill:black;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram-note .nodeLabel{color:black;}#mermaid-svg-TpT1TUox2VzgSSol .statediagram .edgeLabel{color:red;}#mermaid-svg-TpT1TUox2VzgSSol #dependencyStart,#mermaid-svg-TpT1TUox2VzgSSol #dependencyEnd{fill:#333333;stroke:#333333;stroke-width:1;}#mermaid-svg-TpT1TUox2VzgSSol .statediagramTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-TpT1TUox2VzgSSol :root{–mermaid-font-family:\”trebuchet ms\”,verdana,arial,sans-serif;}
通道3能量最大
通道2能量最大
通道1能量最大
通道0能量最大
能量低于阈值
Silence
Dir_LeftRear
Dir_LeftFront
Dir_RightFront
Dir_Right
5. 核心机理深度解析
5.1 为什么用心形麦克风?
心形指向 = 全向 + 双向,对正面灵敏,对侧面衰减 6dB,对背面衰减 20dB 以上。四只麦克风按特定角度安装,自然形成四个重叠较少的敏感扇区。即使不做复杂阵列处理,仅凭幅度大小即可区分方向,极大降低算法复杂度。
安装示意图:
背面 (设备后方)
麦克3(135°) 麦克0(0°) 正前
\\ /
\\ 设备 /
\\ /
\\ /
\\ /
麦克2(90°) 麦克1(45°)
左侧 左前/右前
扇区分配:
- 通道 0(0°):覆盖 -22.5° ~ 22.5°(正前偏右)
- 通道 1(45°):覆盖 22.5° ~ 67.5°(右前)
- 通道 2(90°):覆盖 67.5° ~ 112.5°(右侧)
- 通道 3(135°):覆盖 112.5° ~ 180°(右后/左后)
如果需要严格对称 180°,可调整安装角度为 0°, 60°, 120°, 180°,按需修改。
5.2 能量比较与抗干扰
- 语音频段滤波:滤除 300Hz 以下的空调噪声、风声,滤除 3400Hz 以上的电路高频噪声。
- 噪声基底自适应:开机后采集 2 秒静音数据,取平均 RMS 作为阈值基准。
- 连续确认:防止瞬间冲击声(如关门)引起误触发。
- AGC 关闭:MAX9814 自动增益控制关闭,以免压缩幅度差异。
5.3 ADC 同步采样
STM32F407 有 3 个独立 ADC,可配置为 三重同步模式。实际 4 个通道可分配为:
- ADC1 的 IN0、IN1
- ADC2 的 IN2、IN3
启动后由同一触发信号同步开始转换,DMA 同时搬运两个 ADC 的结果。这样各通道采样时刻相差在纳秒级,能量比较不受相位影响。
6. 项目文件结构组织
sound_direction_4way/
├── hardware/
│ ├── mic_amp_sch.pdf # 4路麦克风放大原理图
│ ├── mainboard.PcbDoc # PCB文件
│ └── BOM.xlsx
├── firmware/
│ ├── Core/
│ │ ├── Inc/
│ │ │ ├── adc_sync.h
│ │ │ ├── iir_filter.h
│ │ │ ├── direction_detect.h
│ │ │ └── led_uart.h
│ │ └── Src/
│ │ ├── main.c
│ │ ├── adc_sync.c
│ │ ├── iir_filter.c
│ │ ├── direction_detect.c
│ │ └── led_uart.c
│ ├── Drivers/ # HAL库
│ └── MDK-ARM/ # Keil工程
├── docs/
│ ├── system_design.md
│ ├── uml/ # UML源文件
│ └── calibration_guide.md
├── test/
│ └── pc_plot.py # 串口能量显示工具
└── README.md
7. 开发方法与步骤(约2周)
| 1 | 硬件搭建:焊接4路麦克风+放大模块,连接STM32开发板,验证波形 | 2天 |
| 2 | 驱动开发:配置ADC同步采样、DMA,实现实时采集,串口打印原始波形 | 2天 |
| 3 | 滤波与能量算法:编写IIR带通滤波器,计算RMS,观察四通道能量分布 | 2天 |
| 4 | 方向判定逻辑:加入阈值、滞后、LED指示,多角度实测 | 2天 |
| 5 | 优化与文档:抗噪声测试,参数微调,编写设计文档及使用说明 | 2天 |
校准步骤:
8. 总结
本方案利用 4 路心形指向麦克风的物理方向性,结合 STM32F407 同步采样与简单能量比较算法,在极低成本下实现了 180° 四向声音识别。
无需复杂阵列处理,软件逻辑清晰,开发周期短,非常适合智能家居、语音控制面板等对精度要求不高的场景。
全套设计文档和 UML 模型为快速工程化提供了完整支撑。






