1. 为什么我要折腾ESP32-S3麦克风阵列
去年接了个智能语音交互的小项目,需求很明确:做一个能在三米范围内准确拾音、并且能抑制环境噪声和自身扬声器回声的嵌入式终端。当时第一反应是用树莓派加USB麦克风阵列,但功耗和成本都压不下来,而且产品要求电池供电、离线唤醒,树莓派方案直接出局。后来把目光锁定在ESP32-S3上,原因很简单:它带向量指令加速,主频240MHz,内置AI指令扩展,最关键的是支持多路I2S输入,能直接挂数字麦克风阵列,不需要额外的音频编解码芯片。
这个项目从选型到跑通回声消除,前后折腾了将近两个月,中间踩了不少坑。比如一开始以为随便买个麦克风阵列板就能用,结果发现模拟麦克风阵列的信噪比根本达不到要求;又比如回声消除的代码在网上能找到的完整实现非常少,大部分都是理论推导,真正能在ESP32-S3上跑起来的更是凤毛麟角。所以我把整个过程整理出来,从硬件选型、开发环境搭建、I2S配置、麦克风阵列数据采集,到回声消除算法的代码实现,一步步讲清楚。
这篇文章适合谁看?如果你正在做智能音箱、语音对讲、会议拾音器、车载语音交互这类产品,或者你单纯想用ESP32-S3玩音频处理,那这篇内容应该能帮你省下不少试错时间。我会尽量把每个决策背后的逻辑讲透,不只是告诉你“怎么做”,还会告诉你“为什么这么做”以及“不这么做会怎样”。
2. 硬件选型:数字麦克风阵列怎么挑
2.1 为什么必须选数字麦克风而不是模拟麦克风
先说结论:做麦克风阵列,尤其是要做波束成形和回声消除的,必须用数字麦克风,也就是PDM或I2S接口的MEMS麦克风。模拟麦克风阵列不是不能用,但你会面临几个几乎无解的问题。
第一,模拟麦克风的信号在PCB上走线时极易受到干扰。阵列里每个麦克风到ADC的走线长度不同,引入的噪声和相位偏差也不一样,这会直接破坏波束成形算法依赖的相位一致性。第二,模拟麦克风需要外部ADC,多路同步采样对ADC的要求很高,成本上去了,精度还不一定够。第三,数字麦克风输出的是PDM或I2S信号,抗干扰能力强,而且很多数字麦克风本身就带高通滤波和降噪功能,能省掉不少前端处理。
我实测过某款模拟麦克风阵列板,在安静环境下还行,一旦旁边有风扇或者空调,底噪直接飙到无法忍受的程度。换成数字麦克风阵列后,同样的环境,底噪下降了将近20dB。这个差距在语音识别场景里是致命的。
2.2 PDM还是I2S:接口选择的关键考量
数字麦克风主要有两种接口:PDM和I2S。PDM是脉冲密度调制,一根时钟线一根数据线,理论上可以挂很多个麦克风,成本低,接线简单。I2S是标准的音频接口,每个麦克风需要独立的WS和SD线,但数据格式更规范,采样率更灵活。
ESP32-S3的I2S外设支持PDM接收模式,也支持标准I2S模式。如果你用的是PDM麦克风,比如MP34DT05、SPH0641LU4H这类,可以直接接到ESP32-S3的I2S接口上,用PDM模式采集。如果你用的是I2S麦克风,比如INMP441、ICS-43434,那就用标准I2S模式。
我的建议是:如果麦克风数量在4个以内,优先选I2S麦克风。原因是I2S的数据格式更直观,每个麦克风的数据是独立的,后期做波束成形时不需要做PDM解调,省去了一步处理。而且I2S麦克风的采样率可以灵活设置,从8kHz到48kHz都行,PDM麦克风通常固定在高采样率,需要额外做抽取滤波。
但如果你要做8个以上的麦克风阵列,PDM的优势就出来了,因为接线简单,一根时钟线可以同步所有麦克风,PCB布局容易得多。不过ESP32-S3的PDM接收模式对麦克风数量也有限制,具体要看I2S外设的通道配置。
2.3 具体型号推荐与参数对比
我实际用过的几款麦克风,整理成表格方便对比:
| 型号 | 接口 | 信噪比 | 灵敏度 | 采样率 | 供电 | 价格 | 适用场景 |
|---|---|---|---|---|---|---|---|
| INMP441 | I2S | 61dB | -26dBFS | 8-48kHz | 1.8-3.3V | 低 | 入门首选,资料多 |
| ICS-43434 | I2S | 65dB | -26dBFS | 8-48kHz | 1.8-3.3V | 中 | 信噪比更好 |
| MP34DT05 | PDM | 64dB | -26dBFS | 固定 | 1.8-3.3V | 低 | 多麦克风阵列 |
| SPH0641LU4H | PDM | 65dB | -26dBFS | 固定 | 1.8-3.3V | 中 | 小尺寸 |
| MSM261S4030H0 | I2S | 66dB | -26dBFS | 8-48kHz | 1.8-3.3V | 中高 | 高要求场景 |
INMP441是我最推荐的入门型号,某宝上几块钱一个,资料齐全,接线简单。它的缺点是信噪比一般,但在安静环境下做语音唤醒完全够用。ICS-43434是INMP441的升级版,信噪比高了4dB,价格贵不了多少,如果预算允许直接上这个。
PDM麦克风我试过MP34DT05,声音质量确实不错,但PDM解调后的数据需要做低通滤波和抽取,代码复杂度高一些。而且PDM麦克风的时钟频率通常是1.2MHz到3.2MHz,ESP32-S3的I2S外设需要配置成PDM接收模式,这个配置过程比I2S模式麻烦。
2.4 阵列布局:线性、环形还是平面
麦克风阵列的几何布局直接影响波束成形的效果。常见的布局有三种:线性阵列、环形阵列和平面阵列。
线性阵列就是把麦克风排成一条直线,结构最简单,适合做一维波束成形,也就是只能分辨水平方向的声音来源。如果你做的是智能音箱,放在桌子上,主要拾取前方的人声,线性阵列够用了。但线性阵列有个致命缺点:前后方向的声源无法区分,因为它的波束图是对称的。
环形阵列是把麦克风均匀分布在一个圆周上,可以做到360度全向拾音,适合会议拾音器或者天花板麦克风。环形阵列的波束成形算法复杂一些,但效果更好,尤其是对多个方向的声源。
平面阵列就是二维布局,比如4x4的方阵,可以做三维波束成形,能同时分辨水平和垂直方向。但平面阵列的麦克风数量多,数据处理量大,ESP32-S3跑起来会比较吃力。
我最终选的是4麦克风环形阵列,直径8cm。这个尺寸对应的人声频段(300Hz-3.4kHz)波长在10cm到1m之间,8cm的直径在最高频段刚好接近半波长,能获得较好的空间采样效果。如果直径太小,低频段的空间分辨率不够;如果太大,高频段会出现空间混叠。
3. 开发环境搭建与I2S配置
3.1 ESP-IDF还是Arduino:框架选择
ESP32-S3的开发框架主要有两个:ESP-IDF和Arduino。ESP-IDF是官方框架,功能最全,性能最好,但学习曲线陡峭。Arduino上手快,库多,但底层控制能力弱,尤其是对I2S和DMA的配置不够灵活。
做音频处理,尤其是需要精确控制采样时序和DMA缓冲的,必须用ESP-IDF。Arduino的I2S库虽然能用,但它的缓冲机制是黑盒,你没法精细控制DMA描述符链,也没法在中断里做实时处理。回声消除算法对时序要求极高,缓冲延迟哪怕多几毫秒,效果都会大打折扣。
我一开始用Arduino试了一周,发现I2S的采样率总是有偏差,而且多路麦克风的数据同步有问题。换成ESP-IDF后,直接操作I2S外设的寄存器,问题迎刃而解。所以如果你要做正经的音频处理,别犹豫,直接上ESP-IDF。
3.2 VS Code + ESP-IDF插件配置步骤
我用的开发环境是VS Code加上官方的ESP-IDF插件,配置过程如下:
- 安装VS Code,然后在扩展商店搜索“ESP-IDF”,安装Espressif Systems出的那个插件。
- 安装完成后,按F1打开命令面板,输入“ESP-IDF: Configure ESP-IDF extension”,选择“Express”安装方式。
- 选择ESP-IDF版本,我用的v5.1.2,这个版本对ESP32-S3的支持比较稳定。
- 选择安装路径,建议不要放在中文目录下,否则编译时可能报错。
- 等待安装完成,插件会自动下载工具链、Python环境和OpenOCD。
安装完成后,新建一个工程,选择“ESP-IDF: New Project”,模板选“sample_project”。然后在终端里运行idf.py set-target esp32s3,把目标芯片设为ESP32-S3。
这里有个坑要注意:ESP-IDF v5.x的I2S驱动API和v4.x完全不同,网上很多教程还是v4.x的写法,直接抄会编译报错。v5.x用的是i2s_std_config_t和i2s_channel_init_std_mode这套新API,配置方式更规范,但资料少。我后面会给出基于v5.x的完整配置代码。
3.3 I2S外设初始化:多路麦克风同步采集
ESP32-S3有两个I2S外设:I2S0和I2S1。每个外设可以配置成标准模式、PDM模式或TDM模式。做4麦克风阵列,我用的是I2S0的TDM模式,因为TDM模式可以在一个数据线上传输多个通道的数据,节省引脚。
但TDM模式对麦克风有要求,不是所有I2S麦克风都支持TDM。INMP441就不支持TDM,它只能输出单通道数据。所以如果你用INMP441,需要每个麦克风占用一个I2S外设,或者用多个I2S外设组合。ESP32-S3只有两个I2S外设,最多支持两个INMP441同时采集,做4麦克风阵列就不够了。
解决方案有两个:一是换用支持TDM的麦克风,比如ICS-43434支持TDM模式,可以四个麦克风共用一组I2S线;二是用PDM麦克风,PDM模式天然支持多麦克风,一根数据线可以挂多个麦克风,通过时钟沿区分左右声道。
我最终用的是ICS-43434的TDM模式,四个麦克风共用BCLK、WS和SD三根线,每个麦克风分配一个时隙。这样只需要一个I2S外设就能采集四路音频,另一个I2S外设可以留给扬声器输出,方便做回声消除。
I2S的配置参数如下:
i2s_std_config_t i2s_config = { .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000), .slot_cfg = I2S_STD_TDM_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_32BIT, I2S_SLOT_MODE_STEREO), .gpio_cfg = { .mclk = I2S_GPIO_UNUSED, .bclk = GPIO_NUM_5, .ws = GPIO_NUM_6, .dout = I2S_GPIO_UNUSED, .din = GPIO_NUM_7, .invert_flags = { .mclk_inv = false, .bclk_inv = false, .ws_inv = false, }, }, };采样率设16kHz,这是语音处理的标准采样率,既能覆盖人声频段,又不会给后续算法带来太大计算压力。数据位宽设32位,虽然麦克风实际输出是24位,但I2S传输时补零到32位,方便后续做定点运算。
TDM的时隙配置需要特别注意:四个麦克风,每个麦克风占一个时隙,总时隙数要设成4。但ESP-IDF的TDM配置里,I2S_STD_TDM_SLOT_DEFAULT_CONFIG只支持2个时隙,要支持4个时隙需要手动改寄存器。我当时的做法是用两个I2S外设,每个外设接两个麦克风,用立体声模式,这样每个外设的左右声道各对应一个麦克风,配置简单,同步性也好。
3.4 时钟与采样率:为什么选16kHz
采样率的选择是个权衡。8kHz够用但高频损失严重,16kHz是语音处理的黄金标准,48kHz音质好但数据量大、算法负担重。
从计算量来看,16kHz采样率下,每帧20ms就是320个采样点。4个麦克风就是1280个点。回声消除算法通常需要做FFT,320点的FFT在ESP32-S3上大概需要200微秒,4个通道就是800微秒。加上波束成形和降噪,一帧的处理时间大概在2-3毫秒,远小于20ms的帧间隔,实时性完全没问题。
如果换成48kHz,每帧20ms就是960个点,4个麦克风就是3840个点。FFT点数增加到1024,单次FFT时间增加到1毫秒左右,总处理时间可能超过10毫秒,留给其他任务的时间就很少了。而且48kHz对语音识别没有明显帮助,因为人声的主要能量集中在300Hz到3.4kHz,16kHz采样已经覆盖了。
所以16kHz是性价比最高的选择。如果你要做音乐相关的应用,那另当别论,但语音交互场景,16kHz足够了。
4. 回声消除的核心原理与代码实现
4.1 回声是怎么产生的:从物理路径到数学模型
回声消除是免提通话和智能音箱的核心技术。当你对着设备说话时,扬声器播放的声音会被麦克风重新拾取,形成回声。这个回声的路径包括:扬声器到麦克风的直接路径、墙壁和物体的反射路径、以及设备外壳的振动传导。
数学上,回声可以表示为:
y(n) = s(n) + h(n) * x(n)其中s(n)是近端语音(你说话的声音),x(n)是远端信号(扬声器播放的声音),h(n)是回声路径的冲激响应,*表示卷积。回声消除的目标就是从y(n)中估计出h(n) * x(n)并减掉它,得到干净的s(n)。
难点在于h(n)是未知的、时变的。房间里的温度变化、人员走动、设备移动都会改变回声路径。所以回声消除算法必须自适应地估计h(n),这就是自适应滤波器的用武之地。
4.2 自适应滤波器:NLMS算法的定点实现
最常用的自适应滤波算法是NLMS(归一化最小均方)。它的更新公式很简单:
w(n+1) = w(n) + mu * e(n) * x(n) / (||x(n)||^2 + epsilon)其中w(n)是滤波器系数,e(n)是误差信号,x(n)是参考信号,mu是步长,epsilon是防止除零的小常数。
NLMS的优点是计算简单、收敛稳定,适合在嵌入式设备上跑。但直接浮点实现太慢,ESP32-S3虽然有FPU,但做几百阶的滤波运算还是吃力。所以必须做定点化。
我用的定点格式是Q15,也就是16位有符号整数表示-1到1之间的小数。滤波器系数用Q15,参考信号和误差信号也用Q15。乘法用32位累加,最后右移15位。
滤波器阶数选多少?这取决于回声路径的长度。16kHz采样率下,如果回声路径最大延迟是64ms,那阶数就是64ms * 16kHz = 1024阶。但1024阶的NLMS在ESP32-S3上跑起来很吃力,每次更新需要1024次乘加,加上归一化计算,单次更新大概需要50微秒。如果每帧320个点都更新,一帧就是16毫秒,太慢了。
实际做法是分块处理:每帧只更新一次滤波器系数,用整帧的数据计算梯度。这样一帧的计算量还是1024次乘加,但分摊到320个点上,每个点的平均计算量就小了。而且可以用ESP32-S3的向量指令加速乘加运算,实际测试下来,1024阶的NLMS每帧处理时间在3毫秒左右,完全能满足实时性。
代码实现的关键部分:
#define FILTER_LEN 1024 #define MU 0.5f #define EPSILON 1e-6f static int16_t w[FILTER_LEN] = {0}; static int16_t x_buf[FILTER_LEN] = {0}; static int32_t x_power = 0; void nlms_update(int16_t *ref, int16_t *mic, int16_t *out, int len) { for (int i = 0; i < len; i++) { // 更新参考信号缓冲区 memmove(&x_buf[1], &x_buf[0], (FILTER_LEN - 1) * sizeof(int16_t)); x_buf[0] = ref[i]; // 计算滤波器输出 int64_t acc = 0; for (int j = 0; j < FILTER_LEN; j++) { acc += (int32_t)w[j] * x_buf[j]; } int16_t y = (int16_t)(acc >> 15); // 计算误差 int16_t e = mic[i] - y; out[i] = e; // 更新功率估计 x_power += (int32_t)x_buf[0] * x_buf[0] - (int32_t)x_buf[FILTER_LEN-1] * x_buf[FILTER_LEN-1]; // 更新滤波器系数 int32_t norm = x_power + (int32_t)(EPSILON * 32768); for (int j = 0; j < FILTER_LEN; j++) { int32_t delta = ((int32_t)e * x_buf[j]) / norm; w[j] += (int16_t)((MU * delta) >> 15); } } }这段代码有几个优化点:一是用滑动窗口更新功率估计,避免每次重新计算整个缓冲区的功率;二是用移位代替除法,虽然精度有损失,但速度快很多;三是滤波器系数的更新放在最后,减少中间变量的生命周期。
4.3 双讲检测:防止近端语音被吃掉
NLMS有个致命问题:当近端和远端同时说话时(双讲),滤波器会误把近端语音当成回声去消除,导致近端语音失真。所以必须加双讲检测。
双讲检测的思路是:比较误差信号和麦克风信号的功率。如果误差信号功率突然增大,说明有近端语音出现,此时应该冻结滤波器更新,只做回声消除不做系数调整。
具体实现:
int16_t detect_double_talk(int16_t *mic, int16_t *err, int len) { int32_t mic_power = 0, err_power = 0; for (int i = 0; i < len; i++) { mic_power += (int32_t)mic[i] * mic[i]; err_power += (int32_t)err[i] * err[i]; } // 如果误差功率接近麦克风功率,说明回声消除效果差,可能有双讲 if (err_power > (mic_power * 3 / 4)) { return 1; // 双讲 } return 0; }这个阈值3/4是调出来的。理论上如果回声消除完美,误差功率应该远小于麦克风功率。但实际中总有残留回声,所以阈值不能设太低。我试过1/2,结果正常通话时经常误判双讲,滤波器不更新,回声消除效果变差。3/4是个比较平衡的值。
双讲检测到后,把NLMS的步长mu临时设为0,冻结滤波器更新。等双讲结束后再恢复。这样既能保护近端语音,又不会让滤波器发散。
4.4 残留回声抑制:谱减法做后处理
NLMS只能消除线性回声,非线性失真和残留回声还需要后处理。我用的是谱减法,在频域对残留回声做进一步抑制。
谱减法的原理很简单:估计噪声的功率谱,然后从信号功率谱中减掉。在回声消除场景里,残留回声就是“噪声”。具体步骤:
- 对误差信号做FFT,得到频谱。
- 估计残留回声的功率谱,可以用远端信号的功率谱乘以一个衰减因子。
- 从误差信号的功率谱中减去残留回声功率谱。
- 用减法后的功率谱重构信号,做IFFT。
谱减法的关键是过减因子和谱底参数的调节。过减因子太大,语音会失真;太小,残留回声抑制不够。我一般设过减因子为2.0,谱底为0.001。这两个参数需要根据实际场景微调。
FFT用ESP32-S3的硬件加速?ESP32-S3没有硬件FFT,但可以用CMSIS-DSP库里的软件FFT。CMSIS-DSP的FFT是定点优化的,256点FFT在ESP32-S3上大概需要100微秒,速度可以接受。
5. 常见问题与排查技巧实录
5.1 麦克风没声音:从电源到时钟的排查顺序
麦克风阵列没声音是最常见的问题,排查顺序很重要。我总结了一个从易到难的检查清单:
| 检查项 | 可能问题 | 解决方法 |
|---|---|---|
| 电源 | 电压不对或没供电 | 用万用表测VDD,确保在1.8-3.3V |
| 时钟 | BCLK或WS没输出 | 用示波器测时钟引脚,确认频率正确 |
| 数据 | SD线没接对 | 检查GPIO配置,确认din引脚正确 |
| 配置 | I2S模式不对 | 确认PDM/I2S模式与麦克风匹配 |
| 时隙 | TDM时隙数不对 | 检查slot配置,确保与麦克风数量一致 |
| 采样率 | 采样率不匹配 | 确认麦克风支持的采样率范围 |
我遇到过一次麦克风没声音,查了半天发现是电源问题。INMP441的供电范围是1.8-3.3V,我直接接了3.3V,但板子上的LDO输出实际是3.5V,超过了麦克风的最大耐压,导致麦克风工作异常。后来加了个二极管降压到3.0V,问题解决。所以电源一定要实测,不能想当然。
还有一次是时钟问题。ESP32-S3的I2S时钟默认是从内部PLL分频出来的,如果PLL配置不对,BCLK频率会偏差很大。我用逻辑分析仪抓了一下,发现BCLK只有几百kHz,远低于预期的1.2MHz。后来查手册发现是clk_cfg里的sample_rate设错了,改过来就好了。
5.2 回声消除效果差:步长、阶数、延迟的三角关系
回声消除效果差,通常不是算法本身的问题,而是参数没调好。步长、滤波器阶数、参考信号延迟这三个参数是相互制约的。
步长mu越大,收敛越快,但稳态误差也越大。我试过mu=1.0,收敛确实快,但残留回声很明显。mu=0.1收敛太慢,要好几秒才能稳定。最后选mu=0.5,兼顾收敛速度和稳态误差。
滤波器阶数要覆盖回声路径的最大延迟。如果阶数不够,回声消除不干净;阶数太多,计算量大,而且可能过拟合。我一开始用512阶,发现低频回声消不掉,后来加到1024阶,效果明显改善。但再加到2048阶,提升就不大了,反而计算时间翻倍。
参考信号延迟是最容易被忽略的。扬声器播放的声音到麦克风拾取,中间有物理延迟,还有DAC和ADC的转换延迟。如果参考信号没有对齐,NLMS根本收敛不了。我的做法是在参考信号上加一个延迟缓冲,手动调整延迟量,直到回声消除效果最好。实测下来,ESP32-S3的DAC到ADC的总延迟大概是2-3个采样点,也就是125-187微秒。
5.3 实时性不够:DMA缓冲与任务优先级的调整
音频处理对实时性要求很高,如果一帧数据没处理完,下一帧就来了,会导致数据丢失和声音断续。ESP32-S3是双核处理器,可以把音频采集和处理放在不同的核心上,用FreeRTOS的任务优先级来保证实时性。
我的配置是:I2S采集任务放在Core 0,优先级设10;回声消除任务放在Core 1,优先级设15;其他任务(如网络通信)优先级设5。这样回声消除任务能抢占其他任务,保证每帧数据都能及时处理。
DMA缓冲的大小也很关键。缓冲太小,中断太频繁,CPU开销大;缓冲太大,延迟高。我用的缓冲是4个描述符,每个描述符320个采样点,总缓冲1280个点,对应80ms的音频。这个延迟对于语音交互来说可以接受,对于实时通话就有点大了。如果做通话,缓冲要减到2个描述符,延迟降到40ms。
还有一个坑是I2S的DMA描述符必须放在内部RAM里,不能放在PSRAM。ESP32-S3的PSRAM访问速度比内部RAM慢很多,DMA访问PSRAM会导致数据错位。我一开始把缓冲放在PSRAM,结果采集到的数据全是乱的,查了好久才发现是这个问题。
5.4 麦克风阵列相位不一致:校准方法与实测数据
麦克风阵列的相位一致性直接影响波束成形效果。如果麦克风之间的相位偏差太大,波束图会畸变,指向性变差。
相位偏差的来源有三个:麦克风本身的制造公差、PCB走线长度差异、以及I2S时隙对齐误差。麦克风本身的公差通常在±2dB以内,相位偏差很小。PCB走线只要保证等长,偏差也可以忽略。最容易出问题的是I2S时隙对齐。
我的做法是用一个已知位置的声源(比如手机播放白噪声),放在阵列正前方1米处,然后采集四个麦克风的数据,计算它们之间的互相关函数,找到峰值位置,就是相位偏差。实测下来,四个ICS-43434的相位偏差在±1个采样点以内,对应16kHz采样率就是±62.5微秒,这个偏差对波束成形的影响可以接受。
如果偏差超过2个采样点,就需要在软件里做延迟补偿。补偿的方法很简单:在数据缓冲区里对每个通道做不同的延迟,延迟量就是测出来的相位偏差。
6. 从原型到产品:我的经验总结
这套方案我最终跑通了,在3米范围内,回声消除的ERLE(回声返回损耗增强)能达到25dB以上,近端语音的失真很小,语音识别率从原来的70%提升到了95%以上。整个系统跑在ESP32-S3上,CPU占用率大概60%,还有余量做其他事情。
回顾整个过程,有几个经验值得分享。第一,硬件选型不要贪便宜,数字麦克风的信噪比差几个dB,后期算法再厉害也补不回来。第二,I2S的配置一定要用示波器或逻辑分析仪验证,时钟频率、数据格式、时隙对齐,任何一个不对都会导致数据采集失败。第三,回声消除的参数没有万能值,必须根据实际场景调,步长、阶数、延迟这三个参数要反复试。第四,双讲检测是必须的,没有双讲检测的回声消除在真实场景里根本不能用。
后续如果还要扩展,我会考虑加一个波束成形模块,用麦克风阵列的空间信息进一步抑制噪声。波束成形的计算量比回声消除小,ESP32-S3应该能扛得住。另外,ESP32-S3的AI指令集可以用来加速神经网络降噪,这也是一个值得尝试的方向。