ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

三阶连续时间Delta-Sigma ADC的Matlab仿真:从环路综合到非理想性验证

三阶连续时间Delta-Sigma ADC的Matlab仿真:从环路综合到非理想性验证

简介:这份资源是面向模拟集成电路与信号处理学习者的3阶连续时间Delta-Sigma ADC Matlab仿真模型,适合具备一定ADC理论基础、希望深入理解CTSDM架构与性能评估的中高级学习者。包内共10个文件,以m脚本、mdl模型、pdf参考文献为主,辅以xlsx数据表、txt说明与png操作图示,压缩包约3.14MB,结构紧凑便于快速上手。代码覆盖时序仿真、频域分析与功率谱计算,可直观观察采样、量化与滤波过程,并借助FFT与PSD评估量化噪声分布与信噪比表现。随附的多篇论文涉及低功耗、高SNDR的CTSDM设计案例,为参数调优与架构对比提供参考。目前已有960人学习下载,适合用于课程设计、科研入门或工程验证时快速搭建可运行的仿真环境,并对照文档理解三阶调制器的工作机理与性能瓶颈。

1. 三阶连续时间 Delta-Sigma ADC:为什么它比离散时间版本更难调

很多人第一次在 Matlab 里搭连续时间 Delta-Sigma ADC 时,都会经历一个反直觉的翻车现场:明明离散时间版本跑得好好的系数,换成连续时间结构后,信噪比直接掉十几 dB,甚至环路直接发散。问题不在代码写错了,而在于连续时间环路里藏着一个离散时间版本没有的黑匣子——反馈 DAC 的脉冲形状和环路滤波器的连续时间响应之间,存在一个必须精确匹配的等效关系。

这份 Matlab 仿真代码要解决的,正是这个匹配问题。它把三阶连续时间 Delta-Sigma 调制器从环路参数综合、RC 积分器建模、反馈 DAC 非理想性注入,到最终频谱验证的完整链路都摊开在脚本里。对于已经会用 Simulink 拖模块、但说不清“为什么系数要这么算”的开发者来说,这份代码的价值在于:它让你看到每一个系数背后的时域约束,而不是只给你一个能跑的框图。搞懂它,你就能回答面试里那个经典追问——连续时间 Delta-Sigma 的环路延迟到底补偿了什么。

2. 环路参数综合:从噪声传递函数到 RC 积分器系数

2.1 为什么不能直接照搬离散时间的系数

离散时间 Delta-Sigma 的环路滤波器是开关电容电路,传递函数在 z 域里描述,系数直接对应电容比。连续时间版本用的是 RC 或 Gm-C 积分器,传递函数在 s 域里描述,系数对应的是时间常数。两者之间不是简单的双线性变换就能打通的,因为反馈 DAC 输出的是一个持续半个或一个时钟周期的脉冲,而不是离散时间里的瞬时采样。

常见的实现思路是:先设计一个满足目标噪声传递函数(NTF)的离散时间环路滤波器,然后用脉冲响应不变法或直接综合法,把离散时间系数映射到连续时间系数。映射的关键约束是——在每个采样时刻,连续时间环路的积分器输出增量,必须等于离散时间环路对应节点的增量。这个约束直接决定了反馈 DAC 的脉冲形状:不归零(NRZ)脉冲对应半周期延迟,归零(RZ)脉冲对应全周期延迟,而延迟的大小会改变环路的相位裕度。

代码里通常会先定义过采样率 OSR、信号带宽、目标信噪比,然后反推所需阶数和 NTF。三阶结构在 OSR 为 32 到 64 时,理论上能提供 80 到 100 dB 的带内信噪比,但这是理想积分器的结果。实际代码会在综合阶段就引入积分器增益带宽积和有限直流增益的约束,避免后面仿真时才发现环路增益不够。

2.2 从 NTF 到 s 域系数的推导路径

代码中一般会用一个函数把 NTF 的零极点转换成连续时间环路滤波器的系数。以三阶为例,NTF 通常写成:

NTF(z) = (1 - z^-1)^3 / (1 + a1*z^-1 + a2*z^-2 + a3*z^-3)

其中分母系数决定了带外增益的整形。代码会先根据稳定性要求选择分母系数,再用d2c或自定义的脉冲响应不变法转换成 s 域传递函数。转换时要注意:连续时间环路滤波器的直流增益必须是无穷大(理想积分器),但实际代码里会用有限增益近似,比如 60 dB,来模拟运放的非理想性。

% 定义离散时间 NTF 分母系数(三阶) a = [1, -2.8, 2.6, -0.8]; % 示例系数,实际由稳定性优化得到 % 脉冲响应不变法转换到连续时间 sys_d = tf(1, a, 1); % 离散时间环路滤波器 sys_c = d2c(sys_d, 'tustin'); % 双线性变换,注意频率预畸变 % 提取连续时间系数,映射到 RC 积分器时间常数 [num_c, den_c] = tfdata(sys_c, 'v');

这段代码的关键在于d2c的转换方法选择。双线性变换会引入频率畸变,在 OSR 较高时影响不大,但代码里通常会加一个预畸变步骤,把信号带宽边缘的频率对齐。转换后的 s 域系数对应的是每个积分器的时间常数,代码会进一步把它们映射成 RC 乘积或 Gm/C 比值。参数说明:a是 NTF 分母系数,sys_d是离散时间环路滤波器,sys_c是转换后的连续时间模型,num_c和den_c是 s 域分子分母系数。

2.3 系数缩放与动态范围优化

直接转换出来的系数往往会导致积分器输出摆幅过大,尤其是第一级积分器,因为它要处理最大的量化噪声。代码里会做一个系数缩放步骤,把各级积分器的输出摆幅控制在运放线性范围内。常见的做法是给每个积分器分配一个缩放因子,使得各级输出最大值大致相等。

这个缩放不改变环路传递函数,因为它是通过调整反馈 DAC 的增益和积分器输入系数同时完成的。代码里通常用一个对角矩阵来表示缩放,然后重新计算所有系数。缩放后的系数会写回积分器模型,确保仿真时不会因为运放饱和而出现虚假的频谱抬升。这一步在离散时间版本里也存在,但连续时间版本更敏感,因为 RC 积分器的输出摆幅直接受时间常数和输入电流影响。

3. 连续时间积分器建模:RC 非理想性怎么注入

3.1 理想积分器与真实积分器的差距

理想积分器的传递函数是1/(s*τ),但真实 RC 积分器有有限直流增益、有限增益带宽积、寄生电容和输出电阻。代码里会用两种方式建模:一种是行为级模型,用tf加零极点;另一种是电路级模型,用lsim或状态空间描述。行为级模型跑得快,适合参数扫描;电路级模型更准,适合最终验证。

常见的实现思路是:先用行为级模型确定系数,再用电路级模型验证非理想性带来的信噪比下降。代码里会定义一个积分器函数,输入是差分输入电压、反馈 DAC 电压、时间常数和运放参数,输出是积分器输出电压。这个函数内部用状态空间方程描述:

function [vout, state] = integrator_rc(vin, vfb, state, tau, A0, GBW, Ts) % vin: 输入电压,vfb: 反馈 DAC 电压 % tau: RC 时间常数,A0: 运放直流增益,GBW: 增益带宽积 % Ts: 仿真步长 % 状态空间:dvout/dt = (vin - vfb)/tau - vout/(A0*tau) % 离散化更新 vout = state + Ts * ((vin - vfb)/tau - state/(A0*tau)); % 增益带宽积限制:输出摆率受限 max_slew = GBW * 2 * pi * 1e6; % 示例转换 if abs(vout - state) > max_slew * Ts vout = state + sign(vout - state) * max_slew * Ts; end state = vout; end

这段代码的核心是状态更新方程。tau决定了积分速率,A0决定了直流增益误差,GBW决定了输出摆率限制。参数说明:vin和vfb是积分器的两个输入,state是上一时刻的输出电压,Ts是仿真步长。代码后的逻辑说明:有限直流增益会导致带内噪声抬升,因为积分器在低频不再提供无穷大增益;增益带宽积限制会导致大信号时输出跟不上,产生谐波失真。这两个非理想性在连续时间 Delta-Sigma 里比离散时间更明显,因为信号是连续变化的,没有采样保持阶段。

3.2 反馈 DAC 的脉冲形状与时序错配

反馈 DAC 在连续时间 Delta-Sigma 里不是理想脉冲源,它的输出是一个持续一定时间的脉冲。代码里会显式建模 DAC 的脉冲形状,常见的有 NRZ、RZ 和 SC(开关电容)三种。NRZ 脉冲持续整个时钟周期,RZ 脉冲只持续半个周期,SC 脉冲有上升沿和下降沿。

脉冲形状直接影响环路的等效延迟。NRZ 脉冲引入半个时钟周期的延迟,RZ 脉冲引入一个时钟周期的延迟。代码里会用pulse_train函数生成 DAC 输出,然后把它加到积分器输入。时序错配指的是 DAC 脉冲的上升沿和时钟采样沿之间的偏差,这个偏差在代码里通常用一个抖动参数模拟。

% 生成 NRZ 反馈脉冲 t = 0:Ts:Tsim; dac_pulse = zeros(size(t)); for k = 1:length(quantized) start_idx = round((k-1)*Tclk/Ts) + 1; end_idx = round(k*Tclk/Ts); dac_pulse(start_idx:end_idx) = quantized(k) * Vref; end % 加入时序抖动 jitter = 0.01 * Tclk * randn(1, length(quantized)); for k = 1:length(quantized) start_idx = round(((k-1)*Tclk + jitter(k))/Ts) + 1; % 重新赋值,模拟上升沿抖动 end

这段代码展示了 NRZ 脉冲的生成方式。quantized是量化器输出,Vref是参考电压,Tclk是时钟周期。时序抖动通过给每个脉冲的起始位置加随机偏移来模拟。参数说明:Tclk是时钟周期,Ts是仿真步长,jitter是抖动幅度。代码后的逻辑说明:时序抖动会调制 DAC 脉冲的宽度,等效于在反馈路径上注入噪声,这个噪声在带内会直接降低信噪比。连续时间 Delta-Sigma 对时钟抖动的敏感度比离散时间高,因为离散时间版本在采样时刻之外不关心信号,而连续时间版本一直在积分。

3.3 量化器与环路延迟补偿

量化器在代码里通常是一个比较器加一个多比特量化电平表。三阶连续时间 Delta-Sigma 常用 3 到 5 比特量化,以降低量化噪声对环路稳定性的影响。代码里会用quantiz函数或自定义的量化表来实现。

环路延迟补偿是连续时间 Delta-Sigma 特有的问题。由于反馈 DAC 的脉冲不是瞬时的,环路里存在一个固有的延迟,这个延迟会降低相位裕度。代码里会在积分器路径上插入一个可调延迟,或者调整反馈 DAC 的时序,来补偿这个延迟。常见的做法是在第一级积分器后面加一个超前补偿零点,或者在反馈路径上加一个比例项。

% 量化器实现 function q_out = quantizer(v_in, nbits, Vref) L = 2^nbits; delta = 2*Vref / L; q_out = round(v_in / delta) * delta; q_out = max(min(q_out, Vref - delta/2), -Vref + delta/2); end % 环路延迟补偿:在第一级积分器后加零点 zero_comp = 1 + s * tau_z; % tau_z 是补偿零点时间常数

这段代码展示了量化器和延迟补偿的基本实现。nbits是量化位数,Vref是参考电压,delta是量化步长。延迟补偿的零点时间常数tau_z通常取时钟周期的一半左右,具体值由仿真优化确定。代码后的逻辑说明:量化器输出是离散电平,延迟补偿零点在环路传递函数里引入相位超前,抵消 DAC 脉冲带来的相位滞后。这个零点的位置直接影响环路的稳定性,太大会放大带外噪声,太小则补偿不足。

4. 仿真验证与频谱分析:怎么确认环路真的稳了

4.1 瞬态仿真与稳态判据

代码里会用lsim或自定义的循环来做瞬态仿真。仿真步长通常取时钟周期的 1/100 到 1/1000,以保证连续时间积分的精度。仿真开始时,环路需要一段时间才能进入稳态,代码里会丢弃前几千个时钟周期的数据,只分析后面的稳态部分。

稳态判据通常看积分器输出是否在预期范围内周期性波动,以及量化器输出的频谱是否稳定。代码里会计算滑动窗口内的信噪比,如果连续几个窗口的信噪比变化小于 0.5 dB,就认为进入稳态。这个判据比单纯看时间波形更可靠,因为连续时间环路的瞬态可能持续很久,尤其是高 Q 值的 NTF。

% 瞬态仿真主循环 for n = 1:Nsim % 更新积分器状态 [v1, state1] = integrator_rc(vin(n), vfb(n), state1, tau1, A0, GBW, Ts); [v2, state2] = integrator_rc(v1, 0, state2, tau2, A0, GBW, Ts); [v3, state3] = integrator_rc(v2, 0, state3, tau3, A0, GBW, Ts); % 量化 q_out(n) = quantizer(v3, nbits, Vref); % 反馈 DAC vfb(n+1) = q_out(n) * Vref; end % 丢弃前 Nsettle 个点 q_steady = q_out(Nsettle:end);

这段代码展示了三阶环路的瞬态仿真结构。三个积分器级联,每个积分器的输出作为下一级的输入,最后一级输出到量化器,量化器输出反馈到第一级积分器的反馈输入端。参数说明:Nsim是总仿真点数,Nsettle是丢弃的瞬态点数,tau1到tau3是各级时间常数。代码后的逻辑说明:这个循环是连续时间 Delta-Sigma 的核心,每个时钟周期更新一次量化器和 DAC,但积分器在每个仿真步长都更新。这种多速率仿真结构是连续时间版本和离散时间版本在代码层面的主要区别。

4.2 频谱计算与信噪比提取

频谱分析用 FFT 加窗函数。代码里通常用 Hann 窗或 Blackman 窗来减少频谱泄漏。采样点数取 2 的整数次幂,比如 65536 或 131072。信噪比的计算方式是:在信号带宽内积分信号功率,在同样的带宽内积分噪声功率,两者比值取 dB。

% 频谱分析 Nfft = 2^16; window = hann(length(q_steady)); q_windowed = q_steady .* window; spectrum = fft(q_windowed, Nfft); spectrum = abs(spectrum(1:Nfft/2+1)).^2; freq = (0:Nfft/2) * fs / Nfft; % 信号带宽内的信噪比 signal_bin = round(fin / fs * Nfft) + 1; signal_power = sum(spectrum(signal_bin-1:signal_bin+1)); noise_power = sum(spectrum(1:round(fbw/fs*Nfft))) - signal_power; snr = 10*log10(signal_power / noise_power);

这段代码展示了频谱计算和信噪比提取的流程。Nfft是 FFT 点数,window是窗函数,spectrum是功率谱,freq是频率轴。参数说明:fin是输入信号频率,fs是采样频率,fbw是信号带宽。代码后的逻辑说明:信号功率取信号频率附近的几个 bin 之和,噪声功率取带宽内所有 bin 之和减去信号功率。这个计算方式要小心信号泄漏,窗函数的主瓣宽度要小于信号 bin 的间隔,否则信号功率会泄漏到噪声里,导致信噪比偏低。

4.3 非理想性扫描与设计裕度

代码里通常会做一个参数扫描,改变运放直流增益、增益带宽积、时钟抖动幅度,看信噪比怎么变化。这个扫描的目的是找到设计裕度:在什么参数范围内,信噪比下降不超过 3 dB。常见的实现思路是写一个循环,每次改变一个参数,跑一次仿真,记录信噪比,最后画成曲线。

这个扫描在连续时间 Delta-Sigma 里特别重要,因为它的非理想性敏感度比离散时间高。比如运放直流增益从 60 dB 降到 40 dB,离散时间版本可能只掉 2 dB 信噪比,连续时间版本可能掉 6 dB。代码里会用parfor加速扫描,或者用行为级模型快速迭代。扫描结果会指导电路设计:如果 40 dB 增益下信噪比不够,就需要在运放设计里保证至少 50 dB 增益。

5. 避坑与排查:连续时间 Delta-Sigma 仿真里最容易翻车的几个点

5.1 仿真步长太大导致积分器数值发散

现象:跑仿真时积分器输出突然跳到无穷大,或者频谱里出现大量高频杂散。原因:连续时间积分器的状态更新对步长敏感,步长太大时显式欧拉法会不稳定。解决:把仿真步长降到时钟周期的 1/500 以下,或者改用梯形法或龙格库塔法做积分。代码里可以加一个步长自适应检查,如果积分器输出变化超过阈值就自动减小步长。

5.2 反馈 DAC 时序错位导致信噪比骤降

现象:频谱里信号 bin 附近出现对称的边带,信噪比掉 10 dB 以上。原因:DAC 脉冲的上升沿和量化器更新时刻没有对齐,等效于在反馈路径上加了周期性抖动。解决:检查代码里 DAC 脉冲的起始索引是否和量化器输出索引一致,确保每个时钟周期内 DAC 脉冲的宽度严格等于时钟周期。如果用了 RZ 脉冲,要确认归零时刻和下一个采样时刻对齐。

5.3 系数缩放后忘记重新计算反馈增益

现象:环路锁定在错误的工作点,积分器输出饱和,频谱里全是谐波。原因:系数缩放时只调整了积分器输入系数,没有同步调整反馈 DAC 的增益,导致环路增益失衡。解决:缩放矩阵要同时作用于前馈路径和反馈路径,缩放后重新计算环路传递函数,确认直流增益和相位裕度没变。代码里可以加一个断言,检查缩放前后的环路增益差异小于 0.1 dB。

5.4 量化器电平数设置不当导致极限环

现象:输入信号为零时,量化器输出周期性翻转,频谱里出现离散音调。原因:量化电平数和环路阶数不匹配,三阶环路用 1 比特量化时容易进入极限环。解决:把量化器位数提高到 3 比特以上,或者在量化器前加一个抖动信号。代码里可以扫描不同量化位数,看空闲音调是否消失。如果必须用 1 比特,要在环路里加一个适当的泄漏路径。

5.5 频谱分析时窗函数长度不够导致信噪比虚高

现象:计算出的信噪比明显高于理论值,但时域波形看起来不对。原因:窗函数长度太短,信号功率泄漏到相邻 bin,被误算成噪声,或者噪声被窗函数抑制。解决:确保窗函数长度覆盖至少 10 个信号周期,FFT 点数取窗函数长度的 4 倍以上。代码里可以对比不同窗函数下的信噪比,如果差异超过 1 dB,说明窗函数选择有问题。

6. 从仿真到电路:连续时间 Delta-Sigma 的设计取舍

这份 Matlab 代码最终要回答的是一个工程问题:在给定功耗和面积约束下,连续时间 Delta-Sigma 的哪些非理想性可以容忍,哪些必须用电路技术消除。仿真阶段看到的每一个信噪比下降,背后都对应一个电路设计决策。

比如,运放直流增益不够时,可以选择增加增益级数,但这会消耗更多功耗和面积;也可以选择在环路里加一个斩波稳定,但这会引入新的时钟馈通。时钟抖动敏感时,可以选择用低抖动时钟源,但这会增加系统成本;也可以选择把量化器位数提高,降低对时钟抖动的敏感度,但这会增加量化器功耗。这些取舍在代码里体现为参数扫描的曲线,在电路里体现为设计指标的分配。

我一般会这么理解:连续时间 Delta-Sigma 的设计流程是一个从系统到电路、再从电路回到系统的迭代。Matlab 仿真在这个迭代里扮演的是快速验证的角色,它不能替代电路仿真,但能在几分钟内告诉你某个架构是否值得继续。代码里的每一个非理想性模型,都是对电路行为的一次抽象,抽象得太简单会漏掉关键效应,抽象得太复杂会拖慢仿真速度。找到这个平衡点,是这份代码最值得深挖的地方。

从那以后我每次搭连续时间 Delta-Sigma 仿真,都会先把反馈 DAC 的脉冲形状和积分器时间常数对齐检查一遍,再跑瞬态。这个习惯帮我省掉了无数次“明明系数算对了但信噪比就是不对”的排查时间。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进