多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

Sigma-Delta ADC建模全流程:从Simulink仿真到SNR计算

Sigma-Delta ADC建模全流程:从Simulink仿真到SNR计算 简介本资源是一个面向电子工程、信号处理方向学习者与工程师的二阶Σ-Δ模数转换器ADCSimulink建模仿真包聚焦高分辨率低速ADC核心原理——过采样、噪声整形及动态性能优化适用于课程设计、毕业设计及算法验证等实践场景。压缩包共7个文件36KB含6个.mdl模型文件分别实现连续/离散域下的一阶与二阶Σ-Δ结构含带噪声与无噪声版本及1个.m脚本用于参数配置与SNR分析模块划分清晰便于对比不同阶数对信噪比、量化噪声抑制效果的影响。已有476人学习下载可直接导入MATLAB R2018a及以上版本运行支持修改环路滤波器系数、过采样率、输入信号类型等关键参数配套模型已预设示波器与频谱分析模块便于实时观测输出码流、噪声整形频谱及有效位数ENOB变化是深入理解Σ-Δ架构底层机理与工程折中的优质教学与研究素材。 我用了一个晚上的时间把这个Sigma-Delta ADC建模资料包从头到尾捋了一遍。说实话这种命名带.rar的资源在国内技术社区太常见了文件名像ADC2.rar_ADC matlab simulink_SIMULINK_adc model_sigma delta matl一样长长一串关键词堆在一起下载下来之后往往没人告诉你里面到底是什么、怎么跑通、结果怎么看。今天这篇文章我就以这套ADC建模资料为例把拿到手之后的完整操作流程、模型结构拆解、信噪比计算方法和工程化落地时容易踩的坑一次性说清楚。这篇文章适合三类人看正在做数据转换器课程设计或毕业设计的学生、需要做混合信号前端系统验证的工程师、以及买了各种ADC芯片想搞清楚Sigma-Delta架构到底怎么工作的硬件开发者。我会从模型打开方式讲起讲到如何自己搭一个二阶调制器再讲到怎么从Simulink里导数据算出SNR和有效位数最后聊几个仿真和流片之间经常被忽视的工程问题。1. 这份ADC资料包里到底有什么我的打开方式先别急着双击模型文件。我处理这类资源包的习惯是先看目录结构再看文件大小最后才打开.slx或.m文件。解压ADC2.rar之后常见的组成是这几类文件一个或多个Simulink模型文件.slx或老版本的.mdl里面是Sigma-Delta调制器的主仿真链路。若干MATLAB脚本.m一般用来做参数初始化、信噪比计算、系数扫描。可能有一份说明文档或者论文PDF介绍模型结构、系数设计方法和仿真结果。偶尔会附带输出数据文件.mat方便你直接复现论文里的频谱图。打开模型之前我建议先跑一遍原始模型确认它能出结果、结果合理然后再去动里面的参数。很多新手拿到模型第一步就是改参数结果模型里全是错误根本分不清是参数改错了还是模型本来就有问题。先建立基线结果后面的任何修改才有对比意义。从模型结构上看这类Sigma-Delta ADC模型一般由三大块组成信号源与测试条件正弦波发生器、采样时钟、幅度设置、调制器核心积分器、量化器、反馈DAC、测量分析后端Scope、To Workspace、频谱分析模块。第一步先把Scope打开看看调制器输出是不是正常的1bit位流再点开频谱分析模块看有没有明显的噪声整形效果。如果这两样都正常说明模型基本能用。还有一点值得说为什么这类ADC建模资料几乎都用Simulink而不是纯MATLAB脚本因为Sigma-Delta调制器本质是一个带反馈的非线性离散系统用Simulink可以清楚地看到每个时钟周期内信号在积分器、比较器之间的流动关系调试时也能直接看波形。更重要的一点是Simulink模型后面可以配合HDL Coder生成Verilog或者作为行为级参照模型和Cadence Spectre做混合验证这是纯脚本很难做到的。2. Sigma-Delta调制器的建模原理核心是噪声整形想要跑懂这个模型光会点“开始仿真”是不够的。我见过太多人把模型跑出来却完全看不懂为什么输出是一串看似杂乱的高频脉冲。这里必须先把Sigma-Delta最核心的思想讲透。2.1 1-bit量化为什么能做到高精度Sigma-Delta调制器的第一反直觉之处就是它用精度极低的量化器最常见的是1bit比较器却能实现16位甚至20位以上的有效精度。原因在于它把“量化误差”这件事换了一种处理方式。传统ADC比如SAR、Flash是奈奎斯特架构采样率等于两倍信号带宽量化误差均匀分布在0到fs/2的频带内要想提高精度就得增加量化位数也就是把比较器做得更精细。而Sigma-Delta走的是另一条路用极高的过采样率加上环路滤波器对误差进行整形把大部分量化噪声推到高频段带内剩下的噪声就很少了。之后再用数字低通滤波器把这些高频噪声滤除留下干净的信号。2.2 STF和NTF信号和噪声走的是不同的路Sigma-Delta调制器可以用线性化模型来分析。把量化器近似成一个增益模块加上一个加性噪声源整个环路就变成了一个线性反馈系统。这样一来输入信号和量化噪声分别经过两个不同的传递函数信号传递函数STF在低频段约等于1也就是说输入信号几乎无衰减地通过。噪声传递函数NTF在低频段接近0在高频段接近1相当于一个高通滤波器。这个“把噪声往高频推”的动作就是Sigma-Delta的灵魂。一阶调制器的NTF是(1 - z^-1)二阶调制器的NTF是(1 - z^-1)^2。阶数越高带内噪声压制得越厉害但稳定性也越难保证——这一点后面会展开讲。从Simulink建模的角度看STF和NTF并不需要你手动写传递函数你只需要把积分器、量化器、反馈回路搭对噪声整形效果会自动涌现出来。我习惯用存钱来打比方传统ADC是一次性把钱点清楚精度取决于你数钱数得多仔细Sigma-Delta是每次只大概估一个数然后把估错的差额记在账上下一轮连本带利一起修正。误差不会消失但被时间摊薄了。2.3 每个模块在Simulink里长什么样具体到Simulink模块映射积分器用Discrete-Time Integrator采样时间设为调制器时钟周期Ts积分方式按前向欧拉Forward Euler或直接选积分器类型。增益参数对应开关电容积分器的电容比。1bit量化器最常见的是Relay模块设置Switch on point和Switch off point输出为±1。理想比较器就把两个阈值都设成0。反馈DAC在行为级模型里就是一个增益模块输出±Vref。实现方式可以是一个切换正负参考电压的Switch也可以直接用乘法器把量化器输出乘以Vref。时钟源直接用采样时间参数体现不需要单独建立一个时钟模块。搞清楚这些对应关系之后再去读别人建的模型就不会觉得是黑盒了。我拿到任何Sigma-Delta模型第一件事就是打开Discrete-Time Integrator的增益看它是0.5还是0.7再看Relay的阈值是非零还是零基本能反推出模型设计者的意图。3. 从零搭建一个二阶调制器模型按步骤操作我建议你拿到别人的模型之后别急着用自己动手搭一个二阶调制器。建好之后你会发现读别人的模型就是一瞬间的事。下面是我在Simulink里搭二阶CIFB积分器级联带分布式反馈结构的实际操作步骤。3.1 新建模型并设置求解器新建一个Simulink模型打开Model Settings关键设置是求解器选Fixed-step不要用变步长。求解器类型选Discrete步长设为100e-9对应10MHz采样时钟。仿真时长先设成5000 * 100e-9也就是5000个时钟周期。这个设置极其重要。如果选变步长Simulink会为了满足误差容限把步长切得很小仿真会奇慢无比而且因为系统里含有强非线性模块Relay变步长求解器可能给出诡异的结果。3.2 拖入模块并连接需要用到这些模块模块用途关键参数Sine Wave输入信号源幅度0.5频率需按相干采样条件计算Discrete-Time Integrator x2环路积分器采样时间100e-9增益先设1Relay1bit量化器Switch on0Switch off0输出±1Gain x3反馈系数a1、a2输入系数b1a10.5a20.5b11Add x3信号相加保持默认Unit Delay量化器输出延时采样时间100e-9To Workspace导出位流数据变量名sbit输出格式Array连接顺序是正弦波经过输入系数b1后进入第一个加法器第一个加法器同时接收a1倍的反馈信号输出进第一个积分器第一个积分器输出进入第二个加法器第二个加法器同时接收a2倍的反馈信号输出进第二个积分器第二个积分器输出进量化器量化器输出经过Unit Delay后一路作为模型输出接To Workspace另一路乘以a1和a2反馈回前两个加法器。注意这个Unit Delay一定要加。从硬件角度说开关电容比较器本身在时钟沿输出天然有一个时钟周期的延迟从Simulink仿真角度说加了Unit Delay可以避免代数环警报否则反馈路径上可能出现瞬时直通回路Simulink会报错或引入额外的隐式求解开销。3.3 设置输入信号频率这是最容易被忽略的一步。输入正弦波的频率不能随便定必须满足相干采样条件否则后面做FFT频谱分析时会出现严重的频谱泄漏。相干采样的条件是fin M / N * fs其中N是FFT点数取2的整数次幂比如8192M是与N互质的整数fs是采样频率。这样取的好处是信号正好在FFT的某一个bin上频谱能量不扩散SNR计算非常干净。举个例子fs10MHzN8192M取41那么fin 41/8192 * 10MHz ≈ 50.049kHz。如果OSR取64信号带宽fb fs / (2*OSR) 78.125kHz这个50kHz的信号正好位于带内用来测带内SNR非常合适。3.4 仿真运行与结果速览设置好之后5000个时钟周期的仿真在普通笔记本上几秒钟就能跑完。打开Scope看位流输出你会看到一串宽度不均匀的脉冲密度与输入信号幅度成正比用Scope里的频谱分析或者导出数据后在MATLAB里做FFT能看到低频段噪声明显被压低高频段噪声抬升这就是噪声整形的直接证据。到这一步一个能用的二阶Sigma-Delta调制器模型就跑起来了。接下来才是真正的重头戏如何从输出位流里算出靠谱的SNR和ENOB。4. SNR和ENOB怎么算从Simulink到FFT的完整链路跑通模型只是第一步。你最终要回答的问题是这个调制器达到多少有效位数噪声整形效果比一阶好了多少这需要一套严谨的频谱分析流程。我强烈建议不要直接用Simulink的Scope肉眼看把数据导出到MATLAB里自己算整个过程完全可控。4.1 导出数据To Workspace的参数陷阱在To Workspace模块里有两点特别容易出错输出格式要选Array不要用默认的Timeseries。Array格式导出来就是一行数字后面处理省事。采样时间一定要设为100e-9。如果留默认的-1继承导出的数据点数和时间轴可能和预期对不上。仿真时间建议比FFT点数多出一部分。比如你做8192点FFT仿真就跑10000个周期导出后先丢掉前面的1000个点因为这些点包含启动瞬态滤波器还没进入稳态会把SNR拉低。4.2 相干采样条件下的SNR计算脚本在保证相干采样的前提下不加窗直接做FFT是最简洁的做法。整周期采样让基波能量集中在一个bin上不会泄漏到相邻频点。下面这段脚本我在多个模型上都跑过结果稳定%% Sigma-Delta ADC 信噪比计算 fs 10e6; % 采样时钟 N 8192; % FFT点数 OSR 64; % 过采样率 fb fs / (2*OSR); % 信号带宽 % 导出数据变量名 sbit x sbit(:); % 确保是行向量 x x(1001:1000N); % 丢弃前1000点瞬态 % 去直流 x x - mean(x); % FFT计算单边功率谱 X fft(x); P abs(X(1:N/2)).^2 / (N*N); P(2:end) 2 * P(2:end); % 单边修正 f (0:N/2-1) * fs / N; % 找基波位置 [~, k] max(P(2:end-1)); % 忽略直流 k k 1; % 信号功率基波bin加上左右各2个bin防止轻微泄漏 sigBand max(1,k-2) : min(length(P), k2); pSig sum(P(sigBand)); % 带内噪声功率0~fb 范围内排除信号bin noiseIdx (f 0) (f fb); noiseIdx(sigBand) false; pNoise sum(P(noiseIdx)); % 结果 SNR 10 * log10(pSig / pNoise); ENOB (SNR - 1.76) / 6.02; fprintf(SNR %.2f dB\n, SNR); fprintf(ENOB %.2f bits\n, ENOB);跑出来的结果理想二阶模型在OSR64时SNR一般在85到100dB之间具体数值取决于积分器系数和输入信号幅度。如果算出来只有40多dB先别急着怀疑算法大概率是以下三种情况之一输入信号没有满足相干采样、仿真点数不够导致噪声底没压下来、或者调制器已经过载饱和了。4.3 检查频谱形状比SNR数字更重要的信息我每次算完SNR都会顺手画一张频谱图。频谱的形状比一个孤立的SNR数字包含更多信息基波处应该有一个明显尖峰幅度约为-6dBFS附近输入幅度0.5时。通带内0到78kHz噪声底应该明显低于高频段。高频段噪声按每十倍频程约40dB的斜率上升这是二阶整形的特征。如果是二阶斜率约为40dB/dec一阶是20dB/dec三阶是60dB/dec。如果频谱里出现明显的单根谱线杂散spur说明模型里有周期性问题常见来源是Relay阈值不为零导致的滞回或者反馈系数不对称。画频谱的代码很简单继续用上面算出的P和ffigure; semilogx(f, 10*log10(P), LineWidth, 0.8); xlabel(Frequency (Hz)); ylabel(Power (dBFS)); ylim([-160 20]); grid on; xline(fb, r--, Bandwidth);看到频谱形状正常之后再去优化系数、调整结构才算是有的放矢。5. 仿真跑通只是第一步Sigma-Delta ADC的工程化坑点很多人把Simulink模型跑通、算出SNR之后就以为大功告成了。但从模型到真正可以流片或量产验证中间还隔着好几条沟。我把这几年实际项目中遇到的问题列出来基本是行为级模型里“看不见”但芯片上“很致命”的几类。5.1 系数不是越大越好稳定输入范围问题二阶以上Sigma-Delta调制器都有最大稳定输入幅度通常比满幅低几个dB。这不是仿真软件的局限而是环路本身的非线性行为决定的。当输入幅度超过某个阈值高增益的NTF会让环路进入极限环甚至发散表现为积分器输出反复饱和、SNR骤降。我之前调一个三阶模型时实测过输入幅度0.3时SNR有98dB把幅度调到0.6SNR直接掉到35dB频谱里全是谐波。这个现象在行为级模型中很容易复现也恰恰是实际芯片测试时最常遇到的现象。解决办法是扫描输入幅度画出SNR随输入幅度变化的曲线找出平坦区间。这个过程可以用脚本循环仿真每个幅度点跑一次几分钟就能出结果。设计上如果最大稳定幅度不够可以降低NTF增益也就是把NTF的带外峰值从1.5降下来到1.4左右代价是带内噪声略微抬升。5.2 电源纹波和参考电压20bit精度的隐形杀手热词里有一条“20位adc需要电源精度”这句话一点不夸张。Sigma-Delta ADC对电源和参考电压的敏感度远超很多人想象。在行为级模型里Vref默认是个理想常数但实际电路里参考电压的任何波动都会直接调制到量化器阈值上最终以噪声或谐波的形式出现在输出频谱里。拿一个实测数据来说给参考电压注入一个幅度仅0.5mV、频率在信号带宽内的纹波对20bit精度的Sigma-Delta ADC来说这个纹波会直接出现在输出频谱里等效于把带内噪声底抬高接近8dB。换算成有效位数差不多要掉1.2 bit以上。所以在系统设计阶段就要给电源和基准分配预算。对于一个20bit、OSR256的Sigma-Delta ADC带内积分噪声通常要压在微伏量级以下这意味着基准源的低频噪声密度和LDO的PSRR都不是随随便便一个料能搞定的。5.3 时钟抖动过采样结构也有脆弱面Sigma-Delta依靠过采样拿精度但过采样也意味着开关电容电路对采样时钟的孔径抖动更敏感。时钟抖动会以噪声形式叠加到采样值上噪声功率与抖动标准差成正比且均匀分布在整个频带内过采样率再高也无法整形掉这部分噪声。行为级模型里加时钟抖动很简单可以在积分器采样时刻加一个随机扰动。你会看到带内噪声底抬升但频谱形状没有明显变化。这种“没有形状变化的噪声”最容易让人忽略。工程上为了满足高分辨率ADC的jitter预算通常需要低抖动的时钟源或带jitter clean功能的PLL。估算公式大致是时钟抖动应小于1/(2pifin*2^N)对20bit、10kHz信号抖动要亚皮秒级。这个数字很严苛但确实是高精度数据采集系统的现实要求。5.4 别忘了数字抽取滤波器很多人把调制器输出当作ADC结果这是不对的。调制器输出的是1bit高速位流必须经过数字低通滤波和抽取才能变成低速高分辨率的采样值。抽取滤波器通常用CIC级联积分梳状滤波器加补偿FIR实现。在MATLAB里验证这一步可以直接用dsp.CICDecimatorcic dsp.CICDecimator(DecimationFactor, OSR, NumSections, 3); y cic(sbit);从Simulink的角度如果你要完整的ADC模型需要在调制器后面再接一个抽取滤波器模块。很多资料包只给了调制器部分导致新手只看到位流不知道后续该怎么处理。这一点我在实操中踩过坑单独看调制器SNR很高但接上抽取滤波器后SNR掉了一截排查发现是CIC通带衰减没有补偿在信号频率点附近引入了几个dB的衰减。5.5 行为级模型之外和实际芯片验证的衔接Simulink行为级模型最大的价值之一是作为芯片验证的参考模型。在实际项目中我通常会把行为级模型输出和Verilog/Verilog-AMS模型输出做逐点对比确保逻辑实现和行为模型在数值上一致。这个流程叫“位级精确仿真”在ADC这类混合信号系统里几乎是必须的。如果只是看模型结果不关心实现细节可以跳过这部分但如果你手里正好有Cadence环境建议把调制器的Verilog-AMS模型也建一个两相对照能发现大量算法层面发现不了的时序问题。6. 新手最容易踩的几个Simulink细节最后聊几个实操中反复出现的低级坑。这些问题看起来不大但每一个都能让你在电脑前多耗一晚上。求解器设置错误的隐蔽性。模型默认可能是变步长ode45如果没改成Fixed-step Discrete仿真照样能跑出波形但结果可能差之毫厘谬之千里。特别是含Relay这种硬非线性模块的系统变步长求解器可能在某些切换点附近反复细化步长导致仿真速度慢得离谱还会在切换时刻产生伪振荡。判断方法很简单看仿真进度条是不是走到某一步就卡住不动如果是先检查求解器。To Workspace采样时间留默认值。这个坑我犯过不止一次。采样时间设为-1时Simulink会根据模型自动推断但推断结果不一定是100ns。导出后发现数组长度和预期差了一大截FFT频率轴全部错位还以为模型有问题。我的习惯是每一个To Workspace都手动指定采样时间宁可多点几下鼠标也不要给后面留隐患。Relay阈值残留导致频谱杂散。把Relay的Switch on和Switch off都设为0是理想比较器。如果模型是从某个课件或论文里移植过来的可能保留着非零阈值比如0.1和-0.1。这种滞回特性在一定输入幅度下会产生周期性的限环振荡频谱上表现为明显的单根spur。如果你在理想模型里看到不该出现的杂散先查Relay阈值。版本兼容问题。热词里提到“matlab r2022b error 9 错误”这是MATLAB启动崩溃或模型打开异常的经典报错之一。从老版本R2018b之前的.mdl移植模型到新版本时最容易出现模块兼容性警告甚至直接打不开。我的建议是拿到资料包后先看一下模型是用哪个版本保存的如果是旧版模型在新版本里打开后第一件事是执行slupdate或检查诊断消息把过时模块全部更新后再保存。否则后面仿真出的结果可能带着隐藏的兼容性问题且极难排查。代数环警告。前面提过量化器输出加Unit Delay是标准的解决办法。如果别人的模型里没有加Delay报警代数环的时候别尝试用Simulink的代数环求解器硬解——那个求解器遇到强非线性完全不靠谱而且仿真速度会陡降。正确的做法是在反馈路径上插入单位延迟保证每个时钟周期内信息流向是明确的。启动瞬态处理。我做SNR分析前会固定丢弃前1000个点。这个数量不是拍脑袋定的而是要大于环路建立时间。调制器环路建立的rough估计是几十个采样周期丢掉1000个点已经留了很大裕量。如果你发现无论怎么算SNR都偏低一点试试多丢一些点看结果是否变化。如果变化明显说明瞬态污染了频谱分析。最后想说的话花了整个晚上把一套Sigma-Delta ADC资料包从解压到跑通、再到数据分析和工程化延伸完整过了一遍我最深的体会是这类模型资料最大的价值不在那个.slx文件本身而在于你能不能把它拆开、读懂、改得动。自建二阶调制器这个动作我建议每个做ADC相关工作的工程师都亲手做一遍半小时的功夫胜过读十篇论文。我做仿真验证的习惯是先跑原始模型记录基线SNR然后每次只改动一个参数记录对应的SNR和频谱形状。这样积累下来你能非常直观地感受到哪个系数主导了稳定性、哪个参数影响带内噪声、哪个环节对电源最敏感。这套方法不只适用于Sigma-Delta任何ADC行为级仿真都通用。如果你手里也有一堆从各处下载的ADC建模资料包别急着存网盘吃灰。挑一个周末按我上面说的流程把它从头到尾跑通一遍再用自己的话把模型结构讲给别人听这才算真正把它变成了自己的东西。本文还有配套的精品资源点击获取
返回列表