资讯动态

SAR ADC行为级建模实战:基于Matlab的模型搭建与性能评估

发布时间:2026/9/1 18:58:52 来源:尧图企业网站定制
简介本资源是一套面向电子工程与集成电路设计初学者的SAR ADC建模实践材料聚焦MATLAB环境下的逐次逼近型模数转换器原理仿真与性能分析解决理论理解与算法实现脱节的问题。压缩包共2个文件1个MATLAB源码文件、1份PDF技术文档总大小1.98MB其中SAR_ADC.m完整实现了SAR逻辑控制、DAC比较迭代、量化输出及误差统计等核心流程SAR ADC-MIT.pdf则系统梳理了工作原理、关键指标如ENOB、SNR、量化误差定义及建模步骤适合作为课程实验、毕业设计或自学进阶的参考依据。已有2863人学习下载读者可直接运行脚本观察逐位逼近过程、修改分辨率/输入信号参数进行对比实验并结合PDF文档深入理解电路级行为与数字建模的映射关系快速掌握SAR ADC系统级仿真方法。 搞混合信号设计这块很多人一听到给SAR ADC写Matlab模型就觉得是仿真工程师的杂活其实完全不是。我这些年做SAR ADC的项目不管是最开始的架构选型、电容阵列尺寸估算还是后来校准算法的验证全部都是在Matlab里先跑通、跑透才敢往晶体管级走。SAR ADC的行为级建模本质上就是把模拟电路里那些繁琐的电荷转移、比较器判断、逻辑时序用几行数学运算和一个循环代替让我们在几分钟内得到原本要仿真几天的结果。这篇文章我会把用Matlab给SAR ADC建模时最关键的东西讲清楚模型骨架怎么搭、电容失配和噪声怎么加进去、跑完仿真之后INL/DNL和频谱怎么算。这里说的sar数据指的是SAR ADC在一次转换过程中生成的那些数字码序列不是合成孔径雷达的回波数据这两个东西名字缩写一样含义完全不同别弄混。1. 为什么要在Matlab里给SAR ADC做行为级建模1.1 行为级模型和晶体管级仿真的差距在哪里做全定制模拟芯片的人最熟悉的仿真工具是Spectre、HSPICE这些。晶体管级仿真精度是真的高能把每个MOS管的沟道长度调制、电容寄生、温度漂移全部还原出来。但代价就是慢慢到什么程度呢我举个例子一个10位SAR ADC采样率50MSPS你要看它在特定输入频率下的频谱至少要采集65536个点然后做FFT。这意味着ADC至少要完成65536次完整的转换而每一次转换都要走10次比较、10次电容阵列的电荷再分配。用晶体管级仿真器跑完这65536次转换在服务器上挂着跑几天都是常事运气不好跑崩了还得从头来。行为级模型完全不一样。它不关心每个晶体管长什么样只关心输入端给了一个电压输出端应该吐出什么码字这个数学关系。SAR ADC的行为级模型核心就是几个数组和一层循环。跑同样的65536点FFTMatlab里通常只要几秒钟。这中间差了好几个数量级的仿真速度意味着你可以快速做架构探索想知道10位和12位的面积、功耗、性能差别改一个参数重跑一遍就行想知道电容失配从0.1%变到0.5%INL会恶化多少几秒钟就能看到结果想知道不同的校准算法管不管用直接把算法加在模型后面跑我用一个不太恰当的类比来说晶体管级仿真就像你要验收一栋楼每一块砖、每一根钢筋都要做承重测试精密但极其耗时。行为级仿真则是先看户型图、先用模拟人偶走一遍动线确认布局合理了再开始施工。这两件事在完整的设计流程里缺一不可但行为级建模跑在前面帮你在开始砌砖之前就避开大量方案性的错误。1.2 我在实际项目中用Matlab建模的典型时机建模不是作品出来之后才做的事。我的习惯是一个项目刚有初步规格时就开始搭行为级模型后面几乎所有大决策都参考模型的结果。下面这张表是我自己总结的不同设计阶段Matlab行为级模型发挥的作用设计阶段主要用途典型任务规格定义阶段验证指标可行性根据目标ENOB、采样率推算比较器噪声和电容失配上限架构选型阶段对比不同DAC结构比较单端CDAC、差分CDAC、带冗余位的CDAC的非理想性敏感度电路参数设计阶段指导具体电路尺寸通过INL/DNL蒙特卡洛结果确定单位电容大小校准算法阶段验证算法收敛性和效果在模型上加上失配、噪声跑后台校准算法系统集成阶段与前端数字接口对接生成SV模型给数字验证提供参考向量1.3 一个模型跑多久算合格很多刚开始接触行为级建模的人最关心的问题往往是模型精度够不够。但根据我的经验一个合格的Matlab SAR ADC行为级模型最先要满足的是速度要求。如果模型跑一次完整的码密度测试要几分钟那你的调试效率会非常低因为每次改动参数后都需要等待。我一般给自己定的标准是跑单次转换毫秒级基本是瞬间完成跑一个斜坡输入的全部码字例如10位ADC1024个码字几秒钟跑64K点FFT的频谱测试数据1分钟以内跑一次200次蒙特卡洛仿真只统计INL/DNL几分钟内完成2. SAR ADC的工作原理拆解从采样到逐次逼近2.1 二分查找与电荷再分配DAC的关系SAR ADC之所以叫逐次逼近本质上是在做一个二分查找。想象你面前有一个1V到0V的电压区间你要猜输入电压是多少。最笨的办法是从0V开始一点一点加但那样做256次才能找到答案。二分查找的思路是先把区间中点0.5V拿出来跟输入比如果输入大说明答案在0.5V到1V之间接着取0.75V如果输入小说明答案在0到0.5V之间接着取0.25V。每比较一次就可以把搜索范围缩小一半。N位转换就是N次比较依次锁定最高位到最低位。在具体的电路实现里这个取区间中点的动作是靠电荷再分配DACCDAC完成的。CDAC由一组二进制权重的电容组成最高位对应的电容大小是最高位权重的一半次高位是四分之一以此类推。把所有电容的上极板连在一起接到比较器输入端转换开始前下极板全部接到输入电压完成采样转换过程中每一位根据比较器的结果把对应电容的下极板从参考电压切换到地或者反过来这样上极板电压就会按照二进制权重偏移。2.2 一个N位转换的完整动作序列我以8位SAR ADC、参考电压1V为例具体过一遍一个输入电压0.3V的转换过程。为方便理解我把所有电压归一化到LSB1LSB等于1V除以256大约3.9mV。第一步采样阶段。输入电压0.3V被采样到DAC电容阵列上极板。第二步保持阶段把下极板全部接地此时上极板电压约为0.3V。第三步逐次逼近开始第1次比较假设最高位权重对应0.5VDAC输出尝试0.5V比较器拿0.3V跟0.5V比0.3V小于0.5V最高位置0。第2次比较次高位权重对应0.25VDAC输出尝试0.25V0.3V大于0.25V次高位置1DAC输出保持在0.25V。第3次比较第三位权重对应0.125VDAC输出尝试0.375V0.3V小于0.375V此位置0。第4次比较第四位权重对应0.0625VDAC输出尝试0.3125V0.3V小于0.3125V此位置0。第5次比较第五位权重对应0.03125VDAC输出尝试0.28125V0.3V大于0.28125V此位置1DAC输出保持在0.28125V。依此类推8次比较结束后输出码字是01001000对应的十进制72。你看看0.3V除以0.00390625V等于76.8所以0.3V对应的理想码字应该是76或者77附近。上面简化推算只是示例真实权重排布和LSB位置会影响具体码值但二分查找逐步逼近的思路就是这样。2.3 输出sar数据到底是什么每一轮转换结束SAR逻辑里保存的那一串二进制码就是我们常说的sar数据。在Matlab建模场景里这个数据有两种用法第一种用法是直接看码字比如做斜坡测试时给ADC输入从负满量程到正满量程的斜坡电压把每一级转换产生的二进制码记录下来就得到了一串码字序列。对这些码字做统计可以算出静态指标INL和DNL。第二种用法是给ADC输入一个精确的正弦波转换完成后得到一串码字序列对它做FFT可以从频域上看到信号的基波、谐波和噪声分量进而算出SNR、SNDR、SFDR、ENOB这些动态指标。很多做雷达、遥感的人听到sar数据第一反应是合成孔径雷达的回波数据那是另一套东西数据格式和用途完全不同。在这里SAR ADC的sar数据就是模数转换器吐出来的一串数字码千万别混淆。3. Matlab模型骨架搭建从理想模型到可量化误差3.1 顶层模块划分与数据流写行为级模型之前先在脑子里把SAR ADC拆成几个功能模块。我习惯把它分成四块采样保持器在采样时刻把输入电压锁住供后续比较使用。DAC权重阵列决定每次逼近的电压步进。理想情况下权重是二进制递减实际中会引入失配。比较器判断当前DAC电压与输入电压的大小关系输出1或0。理想比较器没有失调和噪声实际中它们会带来误差。SAR逻辑负责记录每一位的比较结果控制逼近流程。典型实现就是循环。模型的数据流非常直接——采样后输入电压保持不变然后循环N次每次用DAC试探一个电压比较器判断大小SAR逻辑记录下来最后集中输出码字。3.2 理想DAC模型的代码实现理想DAC的权重非常好写就是一组按二进制递减的数组。在Matlab中我通常这样定义N 10; % 10位SAR ADC W 0.5.^(1:N); % 理想权重最大值0.5逐位减半 Vref 1.0; % 参考电压W(1)是0.5W(2)是0.25W(3)是0.125一直到最后一位。这个权重就是每次比较时DAC可以改变的电平大小。这里有一个容易想不明白的点为什么权重从0.5开始而不是从1开始。因为输入信号范围是±Vref也就是满量程是2Vref而DAC的搜索区间是从-Vref到Vref从0开始朝正方向试探第一步自然是跨度一半所以是0.5倍的Vref。如果你建模的是单端SAR ADC输入范围0到Vref那第一步可以直接试探0.5Vref如果是差分结构的第一步试探就是在正负方向各0.5Vref。3.3 加入电容失配的DAC建模理想模型只能用来跑通流程真正有价值的是非理想模型。电容失配是SAR ADC里最先需要建模的非理想因素也是后面做校准算法时最主要的处理对象。在Matlab里模拟电容失配最常用的方法是给每个理想权重乘上一个随机扰动sigma_mismatch 0.001; % 电容失配标准差0.1% W_real W .* (1 sigma_mismatch * randn(1, N));这里的randn生成的是标准正态分布随机数每个电容的实际权重会在理想值附近上下浮动浮动的标准偏差由sigma_mismatch决定。为什么可以用这个方式来模拟电容失配因为实际生产中单位电容的尺寸会因为光刻、刻蚀等工艺波动产生随机偏差这种偏差在统计上基本服从正态分布。当电容阵列包含不同倍数的单位电容时每个加权电容的绝对失配标准差也不同权重越大绝对标准差越大。如果所有电容都用同一个sigma_mismatch其实是一种近似处理。想要更精确应该写成% 更精细的失配模型每个权重对应的单位电容个数不同 C_unit 1; C_weights C_unit * 2.^(N-1:-1:0); % 每个权重位对应电容值 sigma_c 0.001; % 单位电容失配 C_real C_weights .* (1 sigma_c * randn(1, N)); % 归一化权重 W_real C_real / sum(C_real) * 0.5;这样做的逻辑是最高位电容由2^(N-1)个单位电容并联组成它的失配是单位电容失配的sqrt(2^(N-1))倍不是所有电容都一样。在要求不高的早期评估里用第一种简单模型就够了如果你要做的结论很看重INL曲线形状建议用第二种精细化模型。3.4 比较器与SAR逻辑的循环实现核心转换循环可以写成一个函数输入是采样电压和权重数组输出是最终的数字码字。下面这段代码是一个基础的SAR ADC单次转换函数function [code, vdac_final] sar_adc_single(v_in, W, N, v_offset, v_noise_rms) % 输入 % v_in: 归一化输入电压范围[-1, 1] % W: DAC权重数组长度N % N: 比特位数 % v_offset: 比较器失调电压相对Vref归一化 % v_noise_rms: 比较器噪声标准差相对Vref归一化 % 输出 % code: 转换后的十进制码字 % vdac_final: DAC最终输出电压 vdac 0; % DAC当前输出电压 bits zeros(1, N); % 存储每一位结果 for i 1:N vdac_try vdac W(i); % 先试探当前位为1 % 比较器加上失调和噪声 v_cmp v_in - vdac_try v_offset v_noise_rms * randn(); if v_cmp 0 bits(i) 1; % 输入大于DAC输出保留该位 vdac vdac_try; else bits(i) 0; % 输入小于DAC输出不保留该位 end end code bi2de(bits, left-msb); % 二进制转十进制 vdac_final vdac; end这里面有几个细节值得说一下。第一循环的次数就是比特数N每循环一次确定一位。比较器每一次判断都是一个二分查找的决策点N次循环就是N个决策点。第二DAC试触顺序是从高到低所以权重数组W的排列顺序必须和位的顺序一致。W(1)是最高位W(N)是最低位。第三code转换成十进制用的是left-msb也就是说数组里的第一个元素对应最高有效位。这里最容易出错的就是方向搞反关于这个问题我在第六节详细展开。第四比较器噪声用randn乘上噪声标准差来模拟这是高斯白噪声的近似。实际比较器噪声可能不是完全高斯的但在行为级建模阶段用高斯噪声近似已经足够准确。4. 非理想效应建模电容失配、噪声、比较器失调4.1 电容失配的统计模型与蒙特卡洛仿真电容失配引入后ADC的静态性能会出现明显恶化最直接的表现是DNL和INL变差。DNL指的是实际码宽与理想码宽(1LSB)的偏差INL则是积累误差。在二进制电容阵列里失配最大的危害在于高位权重偏离理想值后后续所有位都在一个错误的基准上做试探造成明显的跳变码。用Matlab做蒙特卡洛仿真可以非常直观地看到这种恶化程度。做法很简单把带失配权重的转换函数循环跑几百次每次重新生成一组随机权重记录每组的INL/DNL最后画成分布直方图或者直接看最大绝对值。N_mc 200; % 蒙特卡洛次数 inl_max zeros(1, N_mc); dnl_max zeros(1, N_mc); for mc 1:N_mc % 重新生成失配权重 C_weights C_unit * 2.^(N-1:-1:0); C_real C_weights .* (1 sigma_c * randn(1, N)); W_real C_real / sum(C_real) * 0.5; % 跑斜坡测试计算INL/DNL ... inl_max(mc) max(abs(inl)); dnl_max(mc) max(abs(dnl)); end实际跑完之后你会发现一个规律DNL的最差情况通常出现在权重跳变最大的码字附近比如最高位翻转的那个点也就是从0111111111变成1000000000的地方。原因很好理解最高位电容失配直接导致这个跳变处的步进偏离1LSB。这个结论在实际流片中也会遇到很多芯片测试时看到的DNL尖峰都集中在高位翻转点的码字上。4.2 kT/C噪声和比较器噪声的建模方式采样保持环节有一个噪声逃不掉那就是kT/C噪声。采样电容C在采样开关断开时开关沟道中的热噪声会被采样到电容上。这个噪声的方差是k*T/C其中k是玻尔兹曼常数T是绝对温度。在Matlab行为级模型里不需要去算一个电容器件有多大的热噪声只需要把这个噪声的标准差折算成相对于满量程的比例然后加在输入信号上。具体操作k 1.380649e-23; % 玻尔兹曼常数 T 300; % 温度 C_s 2e-12; % 采样电容 Vref 1.0; v_kTC_rms sqrt(k * T / C_s) / Vref; % 归一化到Vref % 每次采样时加入噪声 v_in_sampled v_in v_kTC_rms * randn();再来看看比较器噪声。比较器噪声的机理比kT/C噪声复杂它来自比较器内部多个晶体管的热噪声和闪烁噪声最终表现为在阈值点附近判断不稳定。在行为级模型中只需要把它当作一个额外的高斯噪声源加在比较器输入端即可。这个噪声的大小需要根据目标ENOB来推算。一个经验公式是比较器噪声的标准差要低于0.5LSB才能保证不会因为比较器噪声而显著损失有效位数。LSB 2 * Vref / 2^N; v_cmp_noise_rms 0.2 * LSB / Vref; % 0.2LSB比较器噪声4.3 比较器失调与参考电压误差比较器失调是另一个典型的非理想因素。它的本质是比较器的两个输入管存在阈值电压和尺寸失配导致输入电压等于DAC电压时比较器不一定会输出正确的判断结果。在行为级模型里失调电压就是一个固定偏移量直接加在比较器输入端。失调的坏处是会使整个ADC的输入输出特性平移产生固定的码字偏移如果失调大到超过0.5LSB还会导致部分码字永远不会被输出也就是所谓的丢码。参考电压误差同样需要建模。SAR ADC的每一位比较都以参考电压Vref为基准如果Vref本身有误差哪怕你的电容阵列绝对匹配很好最终的增益也是错的。参考电压误差最常见的表现是增益误差所有码字的宽度被整体缩放。在Matlab里建模参考电压误差很简单直接把权重数组乘以一个误差因子Vref_actual Vref * 1.001; % 参考电压偏大0.1% W_actual W * Vref_actual / Vref;我在下面整理了一张常用的非理想效应与性能指标的对应关系表方便你建模时对照非理想因素数学建模方式主要影响的性能指标电容失配权重数组乘随机扰动INL、DNL、SFDRkT/C噪声采样值加高斯噪声SNR、ENOB比较器噪声比较器判断前加高斯噪声SNR、误码率比较器失调比较器输入端加固定偏移码字偏移、丢码参考电压误差权重数组整体缩放增益误差采样时钟抖动采样时刻随机偏差SNR、SNDR5. 仿真跑通之后怎么评估性能5.1 静态指标INL/DNL的计算方法模型能跑出码字之后第一件事就是验证静态性能。最常用的方法是斜坡测试给ADC输入一个均匀覆盖满量程的斜坡电压采集每个输入电压对应的输出码字然后通过统计每个码字出现的输入电压区间宽度来计算DNL和INL。我一般是这样写的% 斜坡测试 n_codes 2^N; % 码字总数 vin_ramp linspace(-1, 1, n_codes * oversample 1); vin_ramp(end) []; codes zeros(size(vin_ramp)); for i 1:length(vin_ramp) codes(i) sar_adc_single(vin_ramp(i), W_real, N, 0, 0); end % 统计每个码字出现的次数 counts histcounts(codes, -0.5:1:n_codes0.5); % 实际码宽每个码字对应的输入电压范围 bin_width diff(vin_ramp) .* counts; % 这里需要结合斜坡步进计算 % 归一化到LSB bin_width_lsb bin_width / mean(bin_width(2:end-1)); dnl bin_width_lsb - 1; inl cumsum(dnl);上面的bin_width_lsb计算是基于每个码字占用了多少个斜坡步进来近似码宽的不是最严格的统计方法但用来做行为级模型的初步评估已经完全够用。更精确的做法是使用码密度测试输入一个已知概率密度函数的正弦波或三角波从码字分布推导转移电平。不过斜坡测试简单直观适合刚跑通模型的阶段。5.2 动态指标相干采样与FFT谱分析评估ADC的动态性能需要给ADC输入一个高质量的正弦波把输出码字做FFT从频谱上读出基波功率、谐波功率和噪声功率。这里有个必须注意的点采样必须满足相干采样的条件否则FFT会漏能量到相邻频点导致测试结果偏悲观。相干采样的条件是有理数关系fin / fs M / Nfft其中M和Nfft是互质的整数Nfft是FFT点数M是信号在Nfft个采样点内包含的完整周期数。M通常选一个奇数值比如1、3、5这样可以避开FFT栅栏效应导致的频谱泄漏。Nfft一般取2的整数次方比如4096、65536。我常用的模型测试代码是这样的Nfft 65536; M 1021; % 质数周期数 fin M / Nfft; % 归一化输入频率 A 0.9; % 输入幅度略低于满量程避免过载 phi rand * 2 * pi; % 随机初始相位 % 生成输入正弦 n 0:Nfft-1; vin_sin A * sin(2*pi*fin*n phi); % 跑ADC模型 codes_sin zeros(1, Nfft); for i 1:Nfft codes_sin(i) sar_adc_single(vin_sin(i), W_real, N, 0, 0); end % 转回模拟电压值并做FFT v_out (codes_sin / (2^(N-1)) - 1) * Vref; spectrum fft(v_out); spectrum_power abs(spectrum).^2; % 找到基波、谐波、噪声分量计算SNR/SNDR/SFDR/ENOB关于频谱分析有几个细节要强调第一输入幅度不要给满一般给到-0.1dBFS或者-0.5dBFS。因为满量程输入容易让码字在正负峰值处出现削波影响失真测试结果。第二基波附近的频率分量要全部计入基波功率不能只取单根谱线。实际做法是把基波频率前后几个频点的功率加起来。第三谐波分量取哪些通常取前5到7次谐波就够了。但在SAR ADC里由于容性DAC的非线性高次谐波通常很小主要看二次和三次谐波。5.3 常见性能曲线怎么看模型跑完之后我最常画的两张图是INL/DNL曲线和FFT频谱图。INL/DNL曲线上首先看最大绝对值是否满足规格。如果DNL最大值接近甚至超过1LSB那么这个ADC一定会出问题至少会在某些码字上出现明显的非线性。INL如果超过0.5LSB对于高精度应用来说也是不能接受的。这些指标直接决定了你要求的单位电容大小和比较器噪声上限。FFT频谱图上重点看基波和最高谐波之间的差值这就是SFDR。基波附近的噪声底高度决定了SNR。算出来的ENOB如果和目标ENOB差距很大就需要回头调模型参数看看是噪声主导还是失真主导。6. 建模过程中的典型坑与调试经验6.1 输入范围与过载问题搭建模型时最容易忽略的问题之一就是输入范围。我在早期建模时吃过亏直接用0到1的输入去测一个差分的SAR ADC模型结果输出的码字全是0或者全是满量程码。原因很简单差分SAR ADC的输入范围是-1到1你把0.5当成正常信号输入其实已经超出模型假设的合理信号范围之外了吗严格来说并没有0.5仍在-1到1之间但如果你在模型里用了单端结构的权重逻辑那么输入范围就要调整。所以写模型前先搞清楚自己建模的是单端还是差分结构这个选择直接决定权重数组的处理方式。还有一个常见问题输入信号的幅度超过满量程。二分查找算法是假设输入落在搜索区间内的一旦输入超出上限或下限SAR逻辑的收敛方向就会错乱最终输出的码字会莫名其妙。调试时如果发现DNL曲线在边缘处出现很大的异常尖峰先检查输入信号是否越界往往一看一个准。6.2 权重顺序与码字映射错误权重顺序搞反是我见过最多的错误没有之一。在二进制转十进制的函数里bi2de的左右顺序如果不一致就会导致高低位互换。比如权重数组从高位到低位排列但bi2de用了right-msb选项那高位权重对应的码字会被当成低位来算整个输出码就反了。这类错误的表现很典型DNL曲线会出现规律的锯齿状重复图案因为高低位互换后权重最大的位被错误地当成最小位码宽会出现周期性的异常。排查方法很简单给模型输入一个已知电压手动推演一遍二进制码再对比模型输出的十进制是不是同一个码字。6.3 仿真时长与随机种子蒙特卡洛仿真如果没有固定随机种子每次跑出来的结果都不一样这会让你很难判断参数的修改是否真的带来了改善。我的习惯是在脚本开头固定随机种子rng(2024); % 固定随机种子保证结果可复现关于仿真时长如果你的模型里做了很多层次的循环比如外层200次蒙特卡洛、中层2的16次方点FFT、内层10位转换循环Matlab的串行运行时间会变得不可忽视。在这种情况下可以考虑用parfor把蒙特卡洛循环改成并行循环。但在改并行之前先把模型本身的速度优化好因为parfor的通信开销在一些场景下可能让速度不升反降。最后分享一个我自己的经验。行为级模型做得再复杂也不是为了取代晶体管级仿真而是为了在最快的时间里回答这个架构和参数能不能满足性能指标这样的问题。我见过很多人在模型里堆砌各种非理想因素最后模型精度没提高多少运行速度倒是慢了十倍。我的建议是先把理想模型跑通然后每次只加一个非理想因素观察它对指标的影响全部加完后再整体验证一遍。这个方法看起来笨但能让你对每个因素的作用都有清醒的认知而不是模型一旦出问题就不知道从哪查起。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价