码密度法测SAR ADC的DNL/INL:93000机台实战指南
简介基于码密度法实现ADC微分非线性(DNL)与积分非线性(INL)测试的MATLAB脚本面向数据转换器验证、混合信号测试以及集成电路课程实验等场景适合硬件工程师、测试工程师和电子类专业学生使用。该方法通过统计输出码直方图来评估转换器线性度适用于逐次逼近型(SAR)和流水线型(Pipeline) ADC也可用于93k等ATE平台的数据分析与辅助验证。压缩包内共1个文件类型为m脚本包体约1KB代码量精炼但结构完整便于直接阅读、修改和嵌入个人仿真流程。脚本主要实现码密度统计、DNL/INL数值计算以及线性度曲线绘制并给出了基本的使用与结果解读思路能帮助读者在短时间内掌握核心测试算法并快速产出测试结果。已有1000人学习下载适合需要实现ADC线性度快速评估、撰写实验报告或对比验证自有算法的读者参考。1. 用码密度法测SAR ADC的DNL/INL93000机台能给你什么ADC的INL和DNL很多工程师第一反应是斜坡法拿一个精确斜坡从0扫到满量程逐码记录转换电压然后线性拟合求误差。但当你手里是12位/14位逐次逼近型ADC产线测试机是泰瑞达9300093K时斜坡法的短板会被放大得很明显。93000上更常用也更快的方式是码密度法向ADC输入高精度正弦波采大量样本做直方图再借助正弦波概率密度反推出每个码的宽度。这个方法不需要精密斜坡发生器不需要逐码驻留可以把比较器噪声和DAC失配的统计特征直接映射到DNL/INL曲线里。文章不端着讲理论直接给出可落地的流程、参数、代码和排错思路适合ATE测试工程师、IC验证工程师以及用STM32或GD32做ADC采集但想验证芯片真实线性度的嵌入式开发人员。2. 码密度法原理与逐次逼近ADC的测试边界2.1 DNL和INL的量化定义为什么不能只测端点DNL微分非线性描述的是实际码宽相对于理想1 LSB的偏差DNL(i) (实际码宽(i) - 1 LSB) / 1 LSBINL积分非线性则是从最低码开始累加DNL得到INL(k) ΣDNL(i)其中i从0遍历到k这里“码宽”不是直接测电压而是ADC输入端在某一斜坡电压区间内对应同一个输出码的电压范围。对SAR ADC来说内部DAC的电容失配、比较器失调和建立残余误差都会直接改变某些码的电压区间体现为码宽偏大或偏小。如果只测端点直线拟合会把内部均匀分布的非线性误差压缩成两三个端点附近的误差漏掉“中段跳码”问题。所以产线上做静态线性度测试必须看点测之外的多码统计信息码密度法就是干这个的。2.2 码密度法如何用直方图反推DNL/INL码密度法的核心是把输入信号看作一个电压随时间变化的激励源通常用正弦波。对每个ADC输出码统计一段时间内该码出现的次数就能得到直方图。直方图的形状由输入信号的幅度概率密度决定正弦波在峰顶附近停留时间长在过零点附近穿过快所以中间码出现次数远低于靠近满幅的码。这个“非线性概率分布”是已知的可以从直方图反推出输入电压在第i个码区间停留的时间从而得到第i个码的电压宽度。如果把正弦波幅度设计成略微超过ADC满量程过驱可以保证所有码都被访问到并且两端自然留下削波样本便于校正。理想情况下第i个码的计数可以写成P_ideal(i) TotalSamples × (1/π) × [arcsin((Vi1 - 0.5)/Vref) - arcsin((Vi - 0.5)/Vref)]其中Vi是第i个码对应的理想中心电压Vref是正弦波归一化到LSB的幅度。实际使用中不需要真的算每一步arcsin可以先用最小二乘或“除概率密度系数”的方式归一化。工程上更通用的做法是先把所有码的直方图除以对应正弦波概率密度得到码密度曲线再对码密度曲线做两端削波归一化然后计算DNL和INL。2.3 斜坡法和码密度法的对比以及SAR ADC最适合哪边斜坡法的思路是给ADC输入一个缓慢上升的斜坡同时用高精度万用表或线性DAC读取输入电压当输出码跳变时记录电压值。这个方法的测量逻辑直观但有两个问题一是需要同步跟踪输入电压和输出码93000机台需要额外的模拟测量单元或外部SMU才能做到测试时间随码数量线性增长二是斜坡的线性度必须远优于ADC分辨率否则测出来的DNL会混入斜坡本身误差。对一个14位SAR ADC若要求DNL误差小于0.1 LSB斜坡源的线性度得优于0.6 ppm满量程这已经接近标准实验室校准源的水平。码密度法把压力从“斜坡线性度”转移到了“正弦波纯度”和“软硬件同步”上。它不需要逐码等待只要采样时序稳定波形的THD够好就能在固定时间内完成全码统计。对于SAR结构比较器噪声和DAC失配是随机的、与输入电压相关的码密度法天然用统计平均把它们揉进直方图里比斜坡法更容易暴露“临界跳码”问题。SAR ADC的另一特点是转换结果按位输出数字端容易在每通道设置统一的ADC采样周期方便和机台时钟做相干采样从而避免FFT泄漏的前提下做码密度统计。这就是为什么在93000上测SAR ADC的静态参数码密度法是优先方案。对比项斜坡法码密度法正弦波激励源高线性斜坡低失真正弦波测试时间逐码扫描时间长按固定样本数采样速度快对噪声容忍度低噪声会掩盖边沿高统计平均可抑制随机噪声需要同步电压表/ADC码同步时钟与采样点数互质典型资源线性DAC/SMU波形发生器、数字通道捕获适合ADC类型低速、高分辨率中高速SAR、流水线对SAR ADC我更建议把码密度法作为首选斜坡法只用来做小批量抽检或校准模型时交叉验证。3. 93000上配置码密度法测试的步骤与代码3.1 93000测试硬件拓扑信号源、滤波器和引脚映射在93000上做码密度法至少需要三类通道模拟波形输出、数字激励/响应捕获、以及为DUT供电的电压源。波形输出常见做法是用93000的模拟仪器通道WaveGen或其他模拟源产生正弦波经过外部无源低通滤波板卡后接到DUT的VIN输入数字通道连接DUT的CLK、片选CS和数据输出DOUT。如果DUT是带串行接口的SAR ADC93000数字通道需要配合SCMU/CDMA等资源模拟主机时序读取转换结果。下面是一个典型的引脚映射表信号DUT引脚93000资源类型备注正弦波输入VIN / AIN模拟波形通道串联50Ω反向并联电容滤波采样时钟SCLK / CLK数字通道频率可编程稳定优先串行数据DOUT / SDO数字捕获通道捕获模式选择Clear/Capture片选CS数字通道低有效配合SCLK驱动模拟电源AVDDDPS电压源低噪声模式数字电源DVDDDPS电压源与AVDD分别走线检查硬件时我一般会先看模拟电源和数字电源是否用了单独的93000电压源再查前端滤波器电容是否贴近DUT引脚。时钟线不要跨越模拟地和数字地的分割区这是规避时钟抖动传染到模拟测量的关键。ADC采样周期由SCLK频率决定如果93000的数字通道频率抖动偏大建议用外部低抖动时钟源替换机台时钟。3.2 相干采样参数如何定Fs、Fin、样本数码密度法不强制要求相干采样因为最终统计的是直方图而不是频谱。但如果后续要做FFT动态参数对比或者要复用同一组波形数据算SNR/SINAD/ENOB那么Fin和Fs必须满足相干条件。相干采样的基本公式是Fin / Fs M点 / 总样本数其中M素数与总样本数互质。为了给码密度法留足样本总样本数往往取2的幂乘以每码命中数。以12位SAR ADC为例Fs 1 MSPS每码期望命中数HitsPerCode 64码数量为4096那么总样本数 4096 × 64 262144。取M素数 265则Fin Fs × M / TotalSamples 1E6 × 265 / 262144 ≈ 1010.6 Hz这样输入频率只比1 kHz略高周期数是整数分之一直方图统计时每个相位都被覆盖。如果ADC采样周期本身可以微调也可以固定Fin 1 kHz反推Fs。参数设计表如下参数典型值调节原则ADC位数12/14位数越高每码命中数要越多每码命中数64至少16推荐64~256总样本数2^N × Hits和M素数组合避免周期性漏码M素数与总样本互质尽量接近总样本的1/3保证相位数输入过驱量1% ~ 3%过驱太大会导致两端直方图拥挤3.3 从93000数字捕获到统计直方图的C语言示例93000测试程序通常用C/C在SmarTest环境下编译不同版本有各自的API头文件。下面的代码是算法层面的示例可以嵌入到测试程序主流程里函数名不绑定具体机台API#define ADC_BITS 12 #define CODE_NUM (1 ADC_BITS) // 4096 #define HITS_PER_CODE 64 #define TOTAL_SAMPLES (CODE_NUM * HITS_PER_CODE) // 262144 void build_histogram_from_capture(uint16_t *capture_buf, uint32_t total_cnt, uint32_t *histogram) { uint32_t i; uint16_t code; // 清空直方图 for (i 0; i sizeof(histogram); i) { histogram[i] 0; } // 从93000捕获内存里顺序读取转换结果 for (i 0; i total_cnt; i) { // 常规SAR ADC输出位于[0, CODE_NUM-1] code capture_buf[i] (CODE_NUM - 1); histogram[code]; } }这段代码先清空直方图计数再从机台捕获内存读取原始转换结果按码值累加。关键点在于total_cnt必须至少等于TOTAL_SAMPLES并且捕获内存里不能有多余的无效数据。93000数字捕获如果配置成“每转换周期采集一个样本”可以打开Clear/Capture模式保证每一次转换对应一个有效样本。参数ADC_BITS决定了码数量HITS_PER_CODE是目标命中数实际命中数会因为信号过驱和量化噪声有小幅偏差不需要强制一致。3.4 初始化、采样的顺序以及“捕获数据与直方图错位”的坑在93000上跑码密度法初始化顺序一般是先开模拟电源和数字电源等待电压稳定再加载并启动波形发生器等正弦波建立稳定最后拉低片选发送连续采样命令。整个过程需要给每个阶段留足“等待ADC采样周期”的时间不能用一条Delay指令蒙混。常见坑是波形刚启动就去读ADC数据导致直方图里前几百个样本是建立过程的瞬态反映到DNL曲线就是起始段出现尖刺。处理方法是丢弃前5%10%的捕获数据或者让波形的起始相位处于满幅过驱区这样瞬态样本不会污染中间码统计。另一个坑是93000数字捕获的起始位与ADC数据输出位没有对齐导致bit错位直方图出现两个尖峰。排查方法是先跑一条固定码直流测试打开捕获窗口看原始bit确认DOUT的MSB位置无误后再跑全波形统计。4. 从直方图反算DNL/INL三个必调参数与93000排错4.1 正弦波概率密度校正与理想计数的推导拿到原始直方图后不能直接计算DNL必须先做正弦波概率密度校正。对满量程正弦波输入电压u在某个位置附近的驻留时间正比于1 / sqrt(1 - (u/Vref)^2)。所以码计数要先乘以该位置的校正系数再归一化。工程上更简单的做法是直接对直方图做“积分直方图”转换先把每个码的计数除以其对应的正弦波概率密度系数得到码密度序列。这个序列在理想情况下是均匀的因为ADC量化区间均匀而输入正弦波的概率密度已被校正。然后对码密度序列做累计积分再对两端进行线性拟合得到的拟合残差就是INL。DNL则通过对码密度序列直接与理想值比较得到DNL(i) 校正后计数(i) / 理想计数 - 1这里“理想计数”是总样本数、码数量和数据格式共同作用的结果。若总样本数为M码数量为C则理想计数 M / C。当输入信号有1%过驱时两端的削波码计数会显著偏大计算时需要把过驱造成的溢出码剔除出去。校正核心用C写逻辑如下#include math.h #include stdint.h #define ADC_BITS 12 #define CODE_NUM (1 ADC_BITS) #define TOT_SAMPS 262144u // histogram 由采集阶段填充 void convert_histogram_to_density(uint32_t *hist, double *density, uint32_t total_count) { uint32_t i; double v_in, coeff; double *prob_sin malloc(sizeof(double) * CODE_NUM); // 计算每个码中心电压对应的正弦概率密度倒数 for (i 0; i CODE_NUM; i) { v_in 2.0 * (i 0.5) / CODE_NUM - 1.0; // 归一化到[-1, 1] v_in fmin(fmax(v_in, -0.9999), 0.9999); coeff sqrt(1.0 - v_in * v_in); // 概率密度分母 prob_sin[i] coeff; } // 直方图除以概率密度倒数得到码密度 for (i 0; i CODE_NUM; i) { density[i] (double)hist[i] / prob_sin[i]; } }逻辑说明代码先把码索引映射到归一化电压域映射范围是[-1, 1]对应正弦波幅度与ADC满量程一致。prob_sin[i]是正弦波在码中心电压处的概率密度相关项码密度法校正就是把计数除掉这一项。注意这里用fmin/fmax把电压夹到±0.9999防止在正弦波峰顶处sqrt(0)导致除零。参数方面TOT_SAMPS主要用于后续归一化不是本段代码的硬约束如果ADC不是12位需要同步调整ADC_BITS和CODE_NUM否则计算出的码密度会错位。4.2 最小DNL/INL计算代码含失码检测校正完成后进入DNL/INL计算。下面代码包含失码检测逻辑void calc_dnl_inl(double *density, uint32_t total_count, double *dnl, double *inl) { uint32_t i; double ideal_cnt, max_abs_dnl; double sum_inl 0.0; ideal_cnt (double)total_count / CODE_NUM; // 先找最大计数值用于归一化阈值 max_abs_dnl 0.0; for (i 0; i CODE_NUM; i) { dnl[i] density[i] / ideal_cnt - 1.0; if (dnl[i] -0.9) { // 失码实际计数远低于理想值 dnl[i] -1.0; } if (fabs(dnl[i]) max_abs_dnl) { max_abs_dnl fabs(dnl[i]); } } // INL 由 DNL 累加得到起点为0 for (i 0; i CODE_NUM; i) { sum_inl dnl[i]; inl[i] sum_inl; } }逻辑说明理想计数值用总样本数除以码数对于12位、262144样本理想计数就是64。DNL计算时把每个码的密度与理想值相比减1后就是LSB单位。失码检测使用dnl[i] -0.9作为阈值意思是该码实际宽度不足理想宽度的10%基本可以判定为失码。实际项目中失码阈值可以放宽到-0.5但那样会把DNL轻度偏小的码误判成失码。INL的累加从0开始因此起始码的INL被强制为0这是码密度法默认以最低码为参考点的做法如果测试规范要求以中点或端点拟合为参考需要在线性拟合后额外修正。4.3 三个必调参数过驱量、窗口范围、每码命中数测试中我最先调的是三个参数它们对结果影响最直接。参数作用调节起点调整依据正弦波过驱量确保满幅两端码都被访问2%两端计数明显过大说明过驱偏大中间码计数偏低说明过驱不足直方图窗口范围剔除削波端的不可靠码保留[0.5%, 99.5%]窗口过窄会丢失真实DNL信息过宽会把削波噪声带入计算每码命中数决定统计置信度64噪声越大命中数越要增加生产节拍紧时可降到32过驱量可以这样快速判断观察直方图两端码的计数。如果0码和4095码计数远高于相邻码说明正弦波峰顶在满量程之外停留太长过驱多了。如果两端计数还低于中间区域说明信号没有覆盖满量程中间的码会有接近0的计数导致DNL图上出现假失码。窗口范围一般用码数量百分比来切12位ADC保留码2~409414位ADC保留码4~16382具体要结合过驱量和信号质量调整。4.4 93000排错先看直方图两端再调过驱量93000上遇到DNL曲线全乱我第一步不是看代码而是把直方图打印出来先看两端计数。如果两端计数差一个数量级不用查波形纯度先查模拟信号链路。常见原因有三个第一是波形发生器输出走线穿过数字控制区导致正弦波带上了数字串扰第二是电源纹波在ADC采样周期附近有低频分量表现为直方图出现周期性起伏第三是参考电压引脚滤波电容离芯片太远RAM效应被忽略在低频率下DSO端吸收电流造成参考漂移。另一个容易被忽略的是“捕获内存溢出”。93000数字通道捕获深度有限如果总样本数超过了捕获内存前段数据会被覆盖或末尾补零直方图末端会出现一整段计数为0的码。遇到这种问题检查捕获起始地址和样本数把总样本数拆成多段捕获累加。时钟抖动引起的直方图异常很难直接看可以先把输入正弦波频率抬高到奈奎斯特频率附近如果DNL曲线出现规律性的峰谷多半是采样时钟的边沿抖动被调制到输入电压上这时候优先优化PCB布局而不是调软件滤波参数。5. 进阶把码密度法延伸到动态参数与冷码复测码密度法的好处是拿到的直方图本身包含着ADC的静态和部分动态信息。同一个数据样本既可以算DNL/INL也可以送给FFT流程算SNR/SINAD/ENOB。我倾向于把码密度法和动态参数测试放在同一个pattern里完成用同一组样本交替验证静态和动态性能这样能快速分辨线性度恶化来自DAC失配还是采样保持/比较器的动态问题。做法很简单采集完成后先做FFT得到SINAD再看DNL曲线是否存在“离散尖峰”。如果DNL尖峰对应码的位置正好落在特定DAC段位说明DAC电容失配是主因如果SINAD差而DNL没有明显尖峰问题更可能出在采样时钟抖动或输入驱动不够。具体到93000机台可以这样操作把4.2节计算出的DNL曲线排序找出最大的三个正DNL码和最大的三个负DNL码然后在同一个DUT上只灌入对应这三组码附近的直流电压用93000的模拟测量单元精读跳变电压。如果精读电压差与DNL计算结果一致说明码密度法数据可信如果不一致优先怀疑正弦波在校正时引入了谐波误差。这个方法还有一个实用场景当测试规范要求“失码”不是硬失败而是分等级时可以用冷码复测来决定Bin/等级划分。另一个技巧是窗口法的动态加窗配合。码密度法对码计数没有加窗要求但FFT动态参数需要加窗以避免泄漏。我的做法是先用相干采样条件让总样本数等于FFT长度再做汉宁窗或平顶窗FFT窗函数不影响直方图因为码密度法只看码计数不管时间顺序。这样一套流程在93000上可以同时输出DNL、INL、SNR、SINAD和ENOB五个参数节省一次插拔测试的时间。如果想要更高置信度的DNL结果最后补充一次“双样本对比”分别用正弦波码密度法和斜坡法测同一个DUT的某几个码宽把两者偏差控制在0.1 LSB以内就能确认码密度法的过驱校正和概率密度校正在该项目里是正确的。本文还有配套的精品资源点击获取