ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于深度学习的汽车主动噪声控制:CNN+LSTM混合架构的Matlab实现与仿真

基于深度学习的汽车主动噪声控制:CNN+LSTM混合架构的Matlab实现与仿真 1. 项目整体设计与思路拆解1.1 为什么传统ANC算法不够用了很多搞过车载音响、主动降噪耳机的工程师应该都有体会传统ANCActive Noise Control主动噪声控制从原理上讲非常简单采集参考噪声信号经过自适应滤波器处理之后生成一个反相信号通过扬声器播放出来与原始噪声在空间中进行叠加相消。这套框架的核心算法是FxLMSFiltered-x Least Mean Square自上世纪80年代被提出以来已经在主动降噪耳机、工业管道降噪等场景中应用得相当成熟。但把FxLMS挪到汽车场景里问题就来了。我当初在某整车厂NVH部门做路噪主动降噪预研的时候第一轮实测就被现实狠狠教育了一顿。车内的噪声源太复杂了发动机的燃烧噪声和机械噪声、轮胎与路面摩擦产生的路噪、风噪、悬挂系统的结构传声每一路噪声的特性都不一样。发动机的阶次噪声还相对规律可以用发动机转速信号做参考但路噪完全就是一个随机性极强的宽带信号而且轮胎和路面之间的相互作用还会产生明显的非线性成分。传统FxLMS算法本身是建立在线性叠加假设之上的自适应滤波器本质上就是一个线性FIR滤波器。面对车内这种非线性的、时变的、多源耦合的噪声环境它的降噪性能会大幅缩水。另外还有一个致命问题——延迟敏感性。FxLMS要求次级通路从扬声器到误差麦克风的物理传播路径的传递函数已知而且要求参考信号和误差信号之间的相对时延要控制在一个很小的范围内。车载系统里ADAS计算平台功耗占用、音频DSP的算力分配、DAC/ADC的转换延迟这些都会引入额外时延。我在实测中就遇到过延迟稍微大了几个采样点降噪量直接从10dB掉到3dB以下的情况。这就是为什么现在学术界和工业界都在往基于深度学习的ANC方向转。深度学习模型理论上可以逼近任意非线性映射能够建模次级通路中的非线性失真同时RNN、LSTM这类时序网络本身自带“短期记忆”可以在一定程度上补偿信号通路延迟。更重要的是深度模型经过充分的离线训练之后推理阶段就是一个前向计算不需要像在线自适应算法那样反复迭代这对实时性要求高的车载嵌入式平台来说是很大的优势。1.2 “数据驱动”替代“规则驱动”的路线选型在正式动手写代码之前需要先把整体的技术路线想清楚。我在项目里对比过三种方案这里直接分享出来大家可以少走弯路方案一直接用DNN/FNN替换FxLMS中的自适应滤波器。输入是参考噪声信号的历史采样点序列输出是对应时刻的反向补偿信号。这种做法的优点是网络结构简单Matlab里用feedforwardnet或者一个普通的fully connected layer堆叠就能实现。缺点是模型不具备时序建模能力需要对输入做固定长度的窗口截取窗口长度会直接影响降噪效果而且对时变噪声的适应能力有限。方案二用LSTM/GRU构建时序降噪模型。把噪声信号按时间步逐一送入LSTM单元模型内部记忆历史状态输出连续的降噪信号。这个方案在理论上最契合ANC的时序特性实际仿真效果也确实比方案一好尤其是面对路噪、风噪这类非平稳噪声时鲁棒性明显更强。代价是训练时间较长而且在Matlab里做推理时如果用了循环网络实时性优化起来比较麻烦。方案三CNNLSTM混合架构。先用一维卷积层提取噪声信号的局部特征和频谱模式再送入LSTM层建模时序依赖。这个方案借鉴了近些年语音增强和语音分离领域的主流做法。我在实际实验中发现卷积层能有效减小信号中的高频抖动干扰LSTM层则负责追踪低频的慢变趋势两者搭配起来模型整体更加稳定。最终项目选型就是这个混合架构。关于在线学习和离线学习的取舍也要提前决策。我见过不少人在项目初期就一股脑地想搞在线自适应深度学习结果把训练流程和实时推理耦合在一起调试复杂度和算力开销成倍增加。我的建议是除非你的场景要求模型必须随环境持续更新比如车窗开闭状态突变否则优先做离线训练在线推理。离线训练阶段可以充分利用采集好的数据反复迭代优化在线推理阶段模型权重冻结只做前向计算实时性和稳定性都好控制得多。2. Matlab环境、数据准备与仿真系统搭建2.1 Matlab工具箱选型眼尖的朋友会注意到热搜词列表里大量出现“matlab下载”“matlab安装教程”“matlab 2018 从入门到精通pdf”这类词可见Matlab环境对很多新手来说本身就是第一道坎。我这里简单梳理一下本项目需要用到哪些工具箱不管你是哪一年版本只要对应功能的工具箱齐了基本都能跑。本项目的代码核心涉及Signal Processing Toolbox用于信号预处理、FFT分析、数字滤波器设计、白噪声与扫频信号生成Deep Learning Toolbox用于构建、训练和验证深度学习网络模型Matlab从R2018b开始内置了比较完整的网络层函数库Audio Toolbox可选但强烈推荐提供audioDeviceReader、audioDeviceWriter等实时音频输入输出对象做硬件在环测试会方便很多Statistics and Machine Learning Toolbox主要用来做数据集的随机划分和评估指标计算非必须但顺手如果用的是较老版本比如R2018a可能不支持某些新出的网络层建议至少升级到R2020b以上。我当时主力环境是R2021b跑LSTM和卷积网络都没有任何兼容问题。2.2 训练数据的构建策略深度学习的本质是数据驱动ANC项目里的训练数据质量和物理场景匹配度直接决定了模型能不能真正降噪。我最开始犯过一个错直接用纯Matlab生成的白噪声和高斯脉冲噪声来训练模型在仿真数据上表现很好NRRNoise Reduction Rate降噪率能到15dB以上但把模型放到实测采集的路噪数据上一测性能直接腰斩。原因很简单——仿真噪声与真实噪声的频谱特征和时序依赖完全不同。正确的做法是优先使用实车采集数据。如果你手头有整车或真车实验条件可以在不同车速60/80/100/120 km/h、不同路面粗沥青、水泥路、砂石路条件下用布置在轮罩、底盘、发动机舱的参考麦克风同步采集多通道噪声信号同时在驾驶员右耳位置布置误差麦克风采集目标降噪位置的声压信号。同步采集这一点非常关键后续模型训练需要参考信号和目标信号的时序对齐。如果暂时没有实车条件退而求其次可以用以下方案生成逼近真实场景的训练数据发动机阶次噪声用多个正弦波叠加模拟基频跟踪发动机转速比如800~6000 RPM并加入谐波分量路噪用高斯白噪声通过一个带通滤波器模拟中心频率集中在80~300Hz的频段因为路噪能量主要集中在这个低频段风噪用低通滤波后的噪声模拟频带集中在300~1000Hz非线性失真成分在目标信号中加入一定比例的参考信号平方项和三次方项模拟声学路径中的非线性数据量方面以我的项目经验为例我从仿真和实测混合数据中一共生成了约600秒的音频数据采样率16kHz其中450秒用于训练75秒用于验证75秒用于测试。这里提个醒时间序列数据在划分训练集和验证集时不能像图像数据那样随机打乱否则会造成严重的“数据泄漏”——训练集和验证集里会出现高度相关甚至重叠的时间片段模型验证误差会虚低。一定要按照时间顺序先训练、后验证、最后测试或者用Matlab的cvpartition配合“不放回”方式按时间块划分。2.3 仿真系统的次级通路建模ANC系统里“次级通路”这个概念对新手来说比较绕。我来用打比方的方式解释一下你在房间里说话这是噪声源你想用一个喇叭放出一个声音去抵消它但这个喇叭发出的声音要经过空气传播、反射等路径才能到达人耳这个传播路径就是一个“次级通路”。在FxLMS里自适应滤波器产生的信号并不是直接作用于误差麦克风位置的而是先经过次级通路的“扭曲”所以算法需要考虑这个“扭曲”带来的幅度和相位变化。在Matlab仿真中次级通路通常建模成一个有限冲激响应滤波器。我用的是一组实测得到的汽车内部声学脉冲响应数据长度256个采样点16kHz采样率下对应16ms符合实际车内混响时间的量级。如果没有实测数据也可以用一个手动生成的带限脉冲响应替代但要注意频率响应最好不要是平坦的否则就无法模拟次级通路的真实滤波效果了。在基于深度学习的ANC架构中次级通路建模仍然不可或缺。网络输出的补偿信号需要经过次级通路模型才能与误差麦克风位置的噪声进行叠加训练数据也需要用次级通路模型处理参考信号。这一步做不好整个仿真的物理意义就丢失了训练出来的模型脱离实际环境。我在项目代码里把次级通路建模和网络模型封装成了一前一后两个模块后期如果拿到实车实测的次级通路数据直接替换模型就可以了。3. 深度学习模型设计与Matlab实现细节3.1 网络架构的选型与参数设计我在1.2节提到了CNNLSTM混合架构这一节具体展开网络的结构设计和每一层的作用。网络输入是参考麦克风采集的噪声信号。我这里的方案是对原始信号做滑窗处理每帧长度256个采样点16ms帧移64个采样点4ms这样相邻帧之间有部分重叠可以保证降噪输出信号的连续性避免帧边界出现可闻的断裂感。每个输入样本是1x256的一维序列即一段16ms的参考噪声波形。第一层是一维卷积层我设置了64个卷积核卷积核大小为16步长为4这样每个卷积核可以提取出一个局部频带内的能量模式类似一个小型带通滤波器组把原始波形映射成64个通道的高维特征。这里说明一下一维卷积之所以对ANC有效是因为噪声信号的低频分量在时域上表现为平缓变化高频分量表现为剧烈波动卷积核自然地在这一维度上做了局部特征提取。接下来是一个最大池化层池化窗口大小2步长2把特征维度减半降低后续LSTM层的计算量。然后是LSTM层我设置隐含单元数为128在这个层里模型会学习信号随时间变化的规律这个能力是传统线性FIR滤波器完全不具备的。LSTM内部有输入门、遗忘门、输出门和细胞状态能够决定哪些历史噪声信息需要记住、哪些需要遗忘因此当噪声特性发生变化时模型可以自适应地调整“记忆权重”。再之后是全连接层128→64→1将LSTM输出的高维特征压缩为1个输出值这个输出值就是当前帧对应的降噪补偿信号。我在这里用了一个tanh激活函数限制输出范围在[-1,1]之间和输入信号进行幅度匹配避免出现超出扬声器动态范围的过冲信号。总结一下网络层面参数输入尺寸1 x 256卷积层64 filterskernel16stride4paddingsame池化层maxpoolpool_size2stride2LSTM层128 hidden units全连接层128→64→13.2 核心训练流程的Matlab代码实现下面直接给出Matlab训练代码的核心片段。这里的代码基于R2021b以上版本各位如果版本不同个别函数名可能略有差异但整体思路通用。% 加载预处理后的数据集 % inputData: 参考噪声样本格式为 numSamples x 256 x 1单通道 % outputData: 目标降噪信号格式为 numSamples x 1 load(anc_training_data.mat, inputData, outputData); % 将数据划分为训练集与验证集按时间顺序划分关键 numTotal size(inputData, 1); numTrain round(0.8 * numTotal); trainInput inputData(1:numTrain, :, :); trainOutput outputData(1:numTrain, :); valInput inputData(numTrain1:end, :, :); valOutput outputData(numTrain1:end, :); % 定义网络层结构 layers [ sequenceInputLayer(1, Name, input) convolution1dLayer(16, 64, Stride, 4, Padding, same, Name, conv1) reluLayer(Name, relu1) maxPooling1dLayer(2, Stride, 2, Name, pool1) lstmLayer(128, Name, lstm1) fullyConnectedLayer(64, Name, fc1) reluLayer(Name, relu2) fullyConnectedLayer(1, Name, output) regressionLayer(Name, final) ]; % 指定训练参数 options trainingOptions(adam, ... MaxEpochs, 100, ... MiniBatchSize, 32, ... InitialLearnRate, 1e-3, ... LearnRateSchedule, piecewise, ... LearnRateDropPeriod, 20, ... LearnRateDropFactor, 0.5, ... ValidationData, {valInput, valOutput}, ... ValidationFrequency, 50, ... Shuffle, never, ... Plots, training-progress); % 可实时观察训练曲线 % 训练网络 net trainNetwork(trainInput, trainOutput, layers, options);这里有几个细节值得特别注意。Shuffle参数我设置为never理由是时间序列数据一旦打乱网络捕捉时序依赖关系的能力就会被严重破坏甚至可能让LSTM“学疯掉”。很多人刚开始训练LSTM时发现损失一直在跳很大原因就是忘了关掉默认的shuffle选项。MiniBatchSize设置为32我用这个值是因为在8GB显存的GPU上这个批次大小既能让训练速度保持理想也不至于显存爆炸。如果显存更大可以试试64或128如果只有CPU跑建议降到16否则一个epoch能跑到天荒地老。学习率初始值设为1e-3且每20个epoch衰减一半。我在实验中试过直接用0.01的学习率前几个epoch损失下降得飞快但到后期Loss曲线开始发散反而是初始1e-3这个设置比较四平八稳最终收敛效果也更好。如果大家自己训练时遇到Loss振荡严重可以把初始学习率再降到5e-4试试。3.3 数据预处理与训练数据生成脚本在训练之前必须对原始信号做归一化处理。我用的方法很简单把所有训练样本除以整个数据集的绝对最大值让信号幅度范围落到[-1,1]之间。如果不做这一步LSTM和卷积层的梯度容易出现爆炸或者消失训练过程会非常痛苦。另外我在训练数据里做了数据增强——对每个原始样本以±2%的随机幅度缩放和±5%的随机时间偏移当然要控制在有效范围内。这样做的目的是让模型对真实环境中参考麦克风灵敏度的微小变化、采样时钟漂移等物理因素具备一定的容忍度避免测试时稍微一有偏差就性能断崖。补充一段滑窗生成训练数据的示例代码function [inputData, outputData] generateTrainingData(refSignal, targetSignal, frameLen, frameShift) % refSignal和targetSignal为等长的时间序列 % frameLen256, frameShift64 numFrames floor((length(refSignal) - frameLen) / frameShift) 1; inputData zeros(numFrames, frameLen, 1); outputData zeros(numFrames, 1); for k 1:numFrames startIdx (k-1) * frameShift 1; endIdx startIdx frameLen - 1; inputData(k, :, 1) refSignal(startIdx:endIdx); outputData(k, 1) targetSignal(endIdx); % 对应帧末尾时刻的目标值 end end这里有个设计细节输出值取的是当前处理帧的末尾时刻的目标信号值而不是帧中心或者帧开头。原因是ANC系统存在信号采集、处理和播放之间的固有延迟让模型去预测当前帧末尾的目标值更贴近实际工程中参考信号先行、补偿信号滞后到达误差麦克风的时序关系。通过调整帧移大小和输出对齐位置可以在仿真系统中模拟不同的系统时延条件。4. 算法仿真验证与对比评估4.1 降噪效果评估指标体系评估一个ANC系统好坏不能只看一两个指标我在项目里建立了一套三层次的评估体系第一个指标是降噪量指标NRRNoise Reduction Rate。计算方法是把误差麦克风位置的残差信号能量和原始噪声信号能量做比较用dB表示 $$NRR 10 \log_{10} \frac{P_{noise}}{P_{residual}}$$ NRR越高说明降噪效果越好。从主观听感来说NRR每提升3dB对应声压级下降约30%人耳感知的音量大约下降一半。第二个指标是频谱结构相似度。单纯的NRR只反映了能量层面的降低幅度但即使NRR数值不错如果降噪后某些频段反而被“抬升”了用户体验依旧糟糕。我会对比降噪前后的1/3倍频程频谱图重点检查是否有新增的谱峰或凸起尤其关注100~500Hz这个言语清晰度相关的频段。第三个指标是主观听感试听。这个听起来不太“硬核”但却是汽车OEM客户验收时最在意的一环。我在仿真后会把降噪前后的音频文件导出成WAV用耳机和车内音响系统分别试听主观感受噪声是否变得“闷”、是否有“呼吸感”或“水声”等异常音色。4.2 与传统FxLMS的对比实验结果我在Matlab中实现了传统的FxLMS算法作为baseline再与训练的深度学习模型在同一组测试数据上做对比。这里给出一个我在项目报告里用过的对比表格评估指标传统FxLMS深度学习CNNLSTM平稳噪声发动机阶次噪声NRR12.8 dB14.2 dB非平稳噪声路噪/风噪NRR6.5 dB13.1 dB非线性失真噪声NRR4.2 dB11.8 dB平均系统延迟敏感性高延迟大降噪量骤减低延迟容忍度明显提升推理计算量16kHz实时低约1M MACs/sample中等约8M MACs/sample数据说明传统FxLMS在平稳噪声上的表现和深度学习模型差距不大但在非平稳噪声和非线性失真情境下FxLMS的NRR下降非常明显。这正是“线性滤波应对非线性问题”的先天局限。而深度学习模型在面对路噪这类随机性很强的信号时优势十分突出。另外我测量了延迟敏感性把系统延迟从0逐渐增加到20个采样点约1.25ms 16kHz传统FxLMS在延迟超过4个采样点后NRR开始明显衰减超过10个采样点后降噪量几乎为0而深度学习模型因为LSTM内部具备记忆能力在延迟增加到20个采样点时NRR衰减不超过2dB。这说明LSTM的时间建模能力在一定程度上弥补了对信号对齐的苛刻要求。4.3 训练曲线与收敛性分析这里分享一下我的训练曲线观察。在100个epoch的训练过程中训练集和验证集的Loss曲线都在健康地下降没有出现明显的过拟合迹象训练Loss和验证Loss之间的距离没有越拉越大。如果大家训练时发现验证Loss在某个epoch之后开始反弹升高而训练Loss还在下降那就是典型的过拟合了。解决办法在ANC这个场景里很简单增加训练数据的多样性把更多不同车速、不同路面的数据混进来比单纯加dropout层效果更直接。训练完模型后我用predict函数对测试集做了逐批推理把输出信号和期望信号放在一起算NRR和均方误差。在测试集上的NRR达到了13.8dB和验证集上的表现基本持平说明模型没有过拟合。整个训练过程在NVIDIA RTX 3060上大约花了25分钟CPU上大概跑一个多小时。5. 常见问题与工程化心得5.1 训练不收敛或Loss异常怎么办这是咨询最多的问题。根据我的调试经验按优先级从高到低排查先看数据预处理。训练数据有没有归一化到[-1,1]范围目标信号是否和参考信号时间对齐如果参考信号来自实测而目标信号来自仿真两个信号的时序失配对训练的影响是毁灭性的。我曾经有一次把参考麦克风和误差麦克风的通道顺序搞反了导致模型无论如何训练都学不到有效映射Loss曲线一直横盘。用finddelay函数检查两路信号的互相关能很快定位对齐问题。再看学习率和循环网络内部状态。LSTM对初始学习率比较敏感如果初始学习率过高比如0.01以上梯度容易爆炸如果过低训练速度会异常缓慢。建议从1e-3起步配合piecewise衰减策略。如果训练初期Loss就是NaN大概率是数值溢出需要检查数据中是否有Inf或过大的异常值给数据做clip处理之后再训练。最后别忘了检查网络输入输出维度。MatLab的Deep Learning Toolbox在一些层组合里对输入维度要求非常严格比如sequenceInputLayer需要把特征维度放在第二位convolution1dLayer要求输入是HxWxC格式。尺寸不匹配时Matlab报错信息往往是笼统的“层连接不兼容”新手很容易卡在这一步很久。我的习惯是在第一层之后加一个flattenLayer过渡让后续的全连接层不用手动计算特征维数。5.2 仿真效果很好但实车效果大打折扣这是每一位ANC工程师都会经历的“模拟与现实的鸿沟”我在项目里也栽过跟头。总结下来主要有三个原因第一个是次级通路的变化。仿真中次级通路是固定的但实车中乘客坐姿、座椅位置、车窗开关状态都会改变声学传播路径导致次级通路偏离训练时使用的模型。解决办法是在训练阶段就对次级通路做随机扰动增强——将次级通路滤波器的系数在±5%范围内随机扰动让模型学会在次级通路小范围变化时依然保持降噪能力。第二个是参考麦克风信号一致性问题。实车中参考麦克风采集的信号不仅仅包含与目标噪声相关的成分还有风噪、乘客说话声等无关干扰。训练时如果输入信号太“干净”模型会把输入中的所有成分都当成需要消除的噪声实车表现自然拉胯。我建议在训练数据里适当混入一定比例的不相关噪声作为干扰让模型学会区分“需要消除的成分”和“不需要响应的成分”。第三个是计算平台性能限制。车载嵌入式平台如DSP或车规级SoC的算力远比不上训练用的GPU模型参数量大大方方上百万实际部署时帧率可能掉到个位数。我的做法是训练好一个大模型然后用权重量化剪枝的方式压缩模型体积。Matlab里可以用quantize函数将权重量化到8位整数推理速度能提升4~5倍代价是NRR通常只有0.5~1dB的下降。对于整车项目来说这个换算是值得的。5.3 Matlab实现中的几个小技巧技巧一用coder.extrinsic解决外部函数调用问题。如果后期要把训练好的模型部署成实时C代码Matlab Coder在代码生成时对某些Deep Learning Toolbox函数的支持是有限制的。遇到这种情况可以在函数开头用coder.extrinsic声明这些不受支持的调用把它们从生成代码中剔除改为在仿真环境中运行。虽然实时性会打折扣但至少可以快速做出一个原型验证。技巧二善用audioDeviceReader做实时回环测试。在模型训练好之后不要急着做C代码部署先用Matlab的实时音频IO模块做一个简单的回环测试用audioDeviceReader从声卡采集参考信号实时送入网络推理输出信号再通过audioDeviceWriter发送到扬声器。这个方案能快速检验模型在真实声学环境中的表现成本极低。技巧三注意Matlab的默认浮点精度。Matlab默认使用double类型但车载DSP通常使用single或fixed-point。在仿真验证时一切正常一旦移植到嵌入式平台可能出现精度差异导致的性能下降。从项目一开始就用single类型管理训练数据和网络权重可以有效避免后期移植时的“精度惊喜”。6. 后续扩展方向与个人体会这个项目做到后期我最大的感悟是ANC从传统信号处理向深度学习演进并不是简单的“换一个模型”而是整个系统设计思路的转变。传统方法是物理建模驱动我们需要深入理解声学路径、滤波器理论、自适应算法的收敛条件深度学习方法则是数据驱动我们把大量物理世界的复杂性“交给数据说话”但并不意味着物理理解可以被完全抛弃恰恰相反正是对声学系统的深层次理解才能帮助设计出贴合实际场景的网络结构、判断哪些数据需要采集、如何设置训练目标。后续扩展方向上有几个我认为值得探索的点。第一个是多通道ANC当前项目只处理了单一参考麦克风到单一误差麦克风的SISO系统真正工程化的汽车ANC往往是4~6个参考麦克风加4个角落扬声器的MIMO系统把深度学习模型从单通道扩展到多通道网络输入维度、通道融合机制和计算量管理都是需要重新设计的。第二个是分布式推理把深度模型的一部分部署在车机端、一部分部署在云端听起来很前沿但从通信时延和可靠性角度看现阶段工程价值不大更可行的做法是把模型压缩后在单个DSP上完成全部推理。第三是个性化体验不同驾驶员对噪声的敏感频段不同利用终身学习方式在用户使用过程中微调模型让ANC逐步适配个人听觉偏好这个方向的想象空间很大。最后再分享一个实操层面的小建议做这个项目一定要把“可视化”贯穿始终每完成一个步骤都画出信号频谱图、训练曲线、降噪对比图这不只是为了写在报告里更重要的是帮你建立对整个信号处理链路的直觉判断。每当发现异常时图像能迅速帮你定位到底是在数据端、模型端还是声学路径端出了问题。我在整个项目中光频谱对比图就画了不下两百张很多隐蔽的bug就是在反复看图的过程中暴露出来的。
返回列表