ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Virtuoso中基于相干采样的FFT与THD分析方法

Virtuoso中基于相干采样的FFT与THD分析方法 做模拟IC的人都不会对Virtuoso陌生但很多人对它的认知停留在画原理图、跑版图和LVS。事实上用Virtuoso里的Spectre瞬态仿真配合FFT分析来看电路的线性度是我这几年验证放大器、ADC输入级和Buffer最常用的手段。尤其在需要给出THD、SFDR这类指标时如果对相干采样没有概念直接拉一段波形丢进FFT频谱必然是糊的算出来的THD比真实值差出几个数量级还会被当成“仿真收敛问题”排查半天。这篇文章就完整走一遍流程从相干条件计算、瞬态仿真参数设置、Calculator里的FFT操作到最终THD的取值和自动化计算把每一步背后的为什么也讲清楚。适合刚接触Virtuoso仿真、或者已经会用但总是被FFT结果困扰的工程师参考。1. 相干采样为什么是FFT和THD分析的前提1.1 非相干采样带来的频谱泄漏很多人第一次用Virtuoso做FFT习惯是瞬态仿真跑完把输出波形往Calculator的fft函数里一扔选个1024或4096点直接看频谱。结果往往很打击人——基波附近的能量散成一大片“裙边”像是信号被调频了一样原本应该尖锐的谱线变成了一座小山丘小信号谐波干脆被埋在泄漏能量里。这就是典型的频谱泄漏。FFT的本质是把一段有限时长的信号当成一个周期信号来做傅里叶展开。如果我们截取的这段波形里恰好包含整数个信号周期那么基波、谐波都精确落在对应的FFT频率点上能量集中在一根根谱线里。但一旦窗口长度不是信号周期的整数倍哪怕差了百分之零点几基波的能量就会泄漏到相邻的几十上百个频率bin里产生一大片伪频谱谐波读数自然不准THD算出来就是个笑话。这里还牵扯到栅栏效应。FFT只在离散频率点上采样真实频谱这些频率点的间隔是fs/N_fft。如果信号频率恰好落在两个bin之间峰值幅度会被低估读出来的谐波大小也有偏差。1.2 相干采样的数学条件和参数选择相干采样的核心条件可以写成这样一个关系fin (N / M) × fs其中fin是信号频率fs是采样频率M是FFT采样点数N是这段分析窗口内包含的完整信号周期数。N必须是正整数M也必须是正整数而且最好让N和M互质。M和N互质这一点很容易被忽略却很重要。如果M和N有公因子等效于采样点只是在重复落在信号周期的某几个相位上白白浪费了采样点提供的独立信息而互质能保证M个采样点均匀覆盖整个信号周期频谱更干净。举个例子假设我们要分析一个10MHz的正弦信号想用1024点FFT取N13个完整周期。那么fs (M × fin) / N (1024 × 10MHz) / 13 ≈ 787.6923077 MHz对应的采样周期Ts 1/fs ≈ 1.26953237 ns。窗口总时长 M × Ts 1024 / 787.6923077 MHz ≈ 1.3 μs同时也等于N/fin 13 × 100ns 1.3μs两边严格对齐。这就是相干采样的几何意义分析窗口正好含整数个信号周期。N为什么取13而不是16因为1024是2的10次方如果N取16两者有公因子采样相位分布不均匀而13是一个与1024互质的质数能获得最好的相位覆盖。在实际工程中我一般会在N7、11、13、17、19这些质数里挑优先选那些让fs落在合理范围的值。1.3 采样率、谐波次数和抗混叠约束光满足相干条件还不够还得考虑谐波会不会混叠。假设我们要看前10次谐波最高频率就是10×fin100MHz。根据奈奎斯特采样定理采样率必须大于100MHz的两倍。上面算出来的fs≈787.7MHz远高于200MHz分析带宽fs/2≈393.8MHz10次谐波妥妥落在带内没有混叠风险。但如果信号频率很高、采样点又取得很密谐波次数一高就可能超过fs/2折回到低频区域冒充其他谐波这时候THD结果也会错。所以记住一个不等式fs 2 × K_max × fin其中K_max是你要看的最高谐波次数。选采样率的时候先把它算清楚后面能少踩很多坑。2. Virtuoso瞬态仿真参数设置给FFT喂干净的数据2.1 三个关键参数tstab、tstop、tstrobe确定了相干采样的频率关系接下来要把这些参数“翻译”成Spectre瞬态仿真的设置。打开ADE L或ADE Explorer里的tran分析有三个参数需要特别在意tstab、tstop、tstrobe。tstab是电路稳定时间。实际电路上电瞬间会有毛刺和建立过程直接把这段波形丢进FFT会引入极大的直流偏置和瞬态误差。常规做法是先跑一段让电路完全建立再从稳定后的某个时刻开始做相干分析。比如电路在2μs后完全建立就设tstab2μs。tstop是总仿真结束时间至少要等于tstab加上相干窗口长度。针对上面的例子相干窗口是1.3μststop可以设成tstab 1.3μs 3.3μs也可以再多留一点余量比如3.5μs方便在Calculator里微调起始点。tstrobe是Spectre里非常有用的一个参数设置后仿真器会以固定时间间隔输出数据而不是按照内部自适应步长输出。因为相干分析本质上是对信号做等间隔采样如果采样点时间间隔不均匀FFT结果会有额外的误差。设tstrobeperiod 1/fs 1.26953237 nsSpectre就会严格按照这个步长“打点”这等于在仿真层面做了采样保持后面做FFT时干净得多。2.2 maxstep和errpreset对谐波精度的影响很多人容易忽略maxstep。Spectre的瞬态仿真用的是自适应步长如果maxstep设置得太宽松仿真器为了速度会在某些区间大步跳过产生了数值截断误差这种误差会在频谱里表现为低频噪声抬升甚至出现看起来像谐波的虚假谱线。我一般采用errpresetconservative同时把maxstep设成最高关心谐波周期的1/20到1/50。看10次谐波周期是10nsmaxstep可以取0.2ns~0.5ns取0.2ns更稳。不要担心maxstep太小导致仿真慢百纳秒级别的仿真在Virtuoso里通常只要几秒到几十秒这个成本完全值得。如果仿真时间窗口比较大比如做到几千个周期才需要考虑在保证精度和仿真时长之间做权衡可以把errpreset降到moderate并用tstrobe固定输出步长。但做THD分析我建议始终保守一点宁可慢不要错。2.3 后处理的STI窗口与多窗口平均Virtuoso新版本里做FFT时经常能看到STISelective Time Interval选项其实就是让你手动选择一段时域区间来做频谱分析。这个功能特别适合处理瞬态切换场景比如ADC采样过程中某一段保持稳定的数据。通过STI只选取稳定区间能有效避开建立过程和切换毛刺的影响。如果电路工作在周期性稳态比如开关电容电路还可以做多窗口平均取多个不重叠的相干窗口分别做FFT再把幅度谱平均。平均会降低随机噪声底让更小的谐波浮现出来。Virtuoso里截图波形后多取几段区间跑FFT人工对比一下就能感受到差别。3. Virtuoso中FFT分析实操从波形到频谱3.1 Calculator中FFT的详细设置与误区仿真跑完打开ADE的Calculator波形窗口选中要分析的信号比如vout然后在Calculator函数列表里找到fft函数。旧的界面是在函数面板里点fft新版本则是在波形窗口里直接右键选择Spectrum或发到计算器。操作路径略有差异但核心参数是一样的。以我常用的设置为例信号是10MHz正弦输出按照第1节的相干参数在FFT参数面板里填Sample Count1024Sample Period1.26953237 nsStart Time2.0 μsStop Time3.3 μsWindowRectangular相干采样时用矩形窗Coherent Measurement手动指定频率或关闭自动调整这里最容易踩的坑是Sample Period。很多人以为是仿真器的输出步长直接填1n或者干脆不填结果频率轴完全对不上频谱上基波位置偏了一大截。记住Sample Period必须等于1/fs也就是相干采样计算出的采样周期。如果设置了tstrobeperiod理论上Sample Period应该和它一致但由于计算器用的是double精度最好把1.26953237n这种长小数填全不要四舍五入到1.27n否则窗口长度会偏离整数周期频谱又开始泄漏。3.2 读懂频谱图bin中心、频率轴和幅度轴FFT结果出来之后默认X轴是频率Y轴是幅度。建议把Y轴切到dB20显示幅值转成dBV这样小谐波也能看得很清楚。频率轴的单位保持Hz即可但要注意查看的是单边谱还是双边谱Calculator的fft默认通常给出单边谱也就是说基波的幅值直接就是信号幅度不需要乘以2。如果看到基波在-6dBV左右对应的线性幅度就是约0.5V。每条谱线之间的间隔是频率分辨率Δf fs/M。在我们这个例子里Δf 787.6923077 MHz / 1024 ≈ 769.23 kHz正好等于fin/N 10MHz/13。所以基波会出现在第13个bin2次谐波在第26个bin3次谐波在第39个bin依此类推。这个关系非常有用找谐波的时候不需要在频谱上肉眼乱扫直接按第13、26、39个bin的位置去找又快又准。如果发现基波峰值不在整数bin上说明相干条件没完全满足或者Sample Period填错了。此时不要急着读数先回头检查参数否则提取的幅度误差很大。3.3 加窗的选择什么时候用矩形窗什么时候用汉宁窗相干采样条件下分析窗口内正好是整数个周期用矩形窗也就是不加窗就是最优选择能量全部集中在一根谱线上旁瓣泄漏最小。这一点很多从信号处理教材入门的人会疑惑因为教材里总是强调FFT要加窗。但在相干测量的前提下矩形窗反而最干净。只有一种情况我会考虑加窗信号频率没法自由选择比如被测信号来自上一个模块的输出频率是固定的我们无法通过调整采样率来满足相干条件。这时候非相干引起的泄漏会污染频谱临时救急可以用Hamming或Blackman窗压低旁瓣。但这样做有个副作用——主瓣会展宽邻近谱线之间的区分度变差而且幅度读数也需要按窗函数的相干增益校正。加窗得到的是近似结果不如回头重新设计采样参数来得干净。所以我在实际项目中的原则是能相干绝不加窗不能相干先改采样参数参数也动不了才退而求其次加窗并明确标注THD结果是带误差的。4. THD计算与自动化脚本4.1 THD定义与手算步骤THD总谐波失真衡量的是谐波能量相对于基波的比例定义是THD sqrt(V2² V3² V4² ... Vn²) / V1其中V1是基波幅度V2、V3……是各次谐波幅度。n取到多少行业内没有完全统一的标准通常取到5次、9次或10次。如果设计目标里明确提到关注某次谐波比如差动电路主要看奇次谐波那就把关注的谐波都纳入计算。标准做法是写到10次因为超过10次的谐波在绝大多数设计里已经小到对THD数值没有影响。举一个实测例子。假设频谱上读得基波V10.5V2次谐波V23.16mV3次谐波V31.78mV4次V40.5mV5次V50.28mV更高次的可以忽略。那么THD sqrt(3.16² 1.78² 0.5² 0.28²) / 500 ≈ sqrt(9.986 3.168 0.25 0.078) / 500 ≈ sqrt(13.482) / 500 ≈ 3.672 / 500 ≈ 0.00734换算成百分比就是0.734%换算成dBc就是20×log10(0.00734) ≈ -42.7 dBc。如果设计目标是THD小于1%这个结果就算通过了。在这类计算里很容易犯的一个错误是直接从频谱图上用dBV读数然后带着dB值去算THD。dB是对数域不能直接平方求和必须先转换回线性幅度再计算。4.2 在Virtuoso里提取谐波幅值的方法Virtuoso提取谐波幅值至少有三种方式。第一种是手动方式在频谱波形窗口里用Cursor工具光标放到第13、26、39个bin上直接读出对应的dBV值并记录下来。这个方法直观适合一两个测试点但多个工艺角和温度组合跑下来手都要废掉。第二种是用Calculator表达式。在Calculator里可以构造复合表达式比如取特定频率处的幅度value(v(/VOUT ?result tran) 20e6 ?intrp linear)但要注意直接对时域波形在不同频率点取value并不是提取FFT谐波的正确方式。更靠谱的是先做FFT再利用波形运算符提取特定bin的幅度。不同版本的Virtuoso在表达式语法上略有差异建议直接在计算器里点选FFT结果波形然后用value或peak函数读取该波形的特定频率点幅度。第三种就是接下来要说的Ocean脚本也是我最推荐的方式。4.3 用Ocean脚本批量计算THD、SFDR和ENOB如果需要跑多组工艺角或者多组输入幅度建议把整个流程写进Ocean脚本。Ocean是Spectre自带的交互批处理语言可以在ADE里通过Ocean窗口运行也可以在命令行直接调用。下面给一个简化版模板核心思路是跑tran、算FFT、读出各次谐波幅度、算THD和SFDR。; 加载设计、选择仿真器和工艺角 simulator( spectre ) design( /path/to/design/input.scs ) modelFile( (/path/to/model/tt.lib tt) ) ; 设置瞬态分析参数 analysis( tran ?stop 3.3u ?strobeperiod 1.26953237n ?tstab 2u ?errpreset conservative ?maxstep 0.2n ) desVar( freq 10M ) desVar( am 0.5 ) ; 运行仿真 run() ; 获取时域输出并做FFT fftResult fft( v(/VOUT ?result tran) 1024 1.26953237n 2u 3.3u ?window Rectangular ) ; 提取基波和各次谐波的幅度频率点在计算结果中可能以bin索引访问 fund peak( fftResult 10M ?xtype frequency ?peakThreshold 0.1 ) h2 peak( fftResult 20M ?xtype frequency ?peakThreshold 0.001 ) h3 peak( fftResult 30M ?xtype frequency ?peakThreshold 0.001 ) h4 peak( fftResult 40M ?xtype frequency ?peakThreshold 0.001 ) h5 peak( fftResult 50M ?xtype frequency ?peakThreshold 0.001 ) ; 计算THD线性幅度域 thd sqrt( h2*h2 h3*h3 h4*h4 h5*h5 ) / fund ; 计算SFDR最大杂散与基波之比结果用dBc表示 sfdr 20*log10( fund / max( h2 max( h3 max( h4 h5 ) ) ) ) printf(THD %.4f %%\n thd*100 ) printf(SFDR %.2f dBc\n sfdr )需要说明的是不同版本Spectre对fft结果波形的peak函数参数支持不完全一样。如果peak函数读不出值可以改用value函数结合xlim指定频率范围或者提取bin值再按Δf换算。关键是思路先把FFT结果存成波形再在目标频率附近取局部最大值这样可以避免噪声尖峰干扰读数。如果还想算ENOB可以同时采集噪声和失真也就是SINADSINAD 20×log10(V1 / V_noisedist)ENOB (SINAD - 1.76) / 6.02Virtuoso里可以用snr函数或者自己计算信号功率与噪声失真总功率的比值。因为噪声功率分布在除基波和谐波以外的所有bin中需要对全频段做积分运算Ocean里可以这样粗略处理总功率减掉基波功率和各谐波功率剩下的就是噪声加失真功率再代入公式。这个做法虽然不算严格但在快速评估时非常实用。5. 常见问题与排查实录这里整理几个我在实际项目中反复遇到的FFT/THD问题基本能覆盖大多数翻车现场建议收藏起来对照排查。现象可能原因解决方法基波周围出现大面积“裙边”频谱糊分析窗口长度不是信号周期的整数倍相干条件不满足按fin(N/M)×fs重新计算并修改Sample Period/Start/Stop基波峰不在整数bin中心读数偏低Sample Period填错或四舍五入填完整的小数采样周期确保窗口长度精确等于N个周期谐波呈阶梯状或明显底部抬高maxstep太大数值截断误差被FFT放大减小maxsteperrpreset设为conservative频谱噪声底像“高台”而非平底加窗导致主瓣展宽或非相干采样能量泄漏优先保证相干采样并使用矩形窗FFT频率轴基波位置不对Sample Period与tstrobeperiod不一致将两者统一为同一采样周期高次谐波突然消失或出现不该有的谱线谐波超过fs/2发生混叠提高采样率fs或降低关心的最高谐波次数THD计算值忽大忽小不稳定取谐波时没有对准bin用peak函数读取局部最大值而不是直接取某频率点5.1 基波旁边那摊“糊”到底是不是电路问题排查顺序要理清先排除相干条件再怀疑仿真精度最后才找电路本身。有一次我帮同事看一个LDO的PSR仿真他发现输出纹波的FFT频谱里基波旁边有一堆乱七八糟的频率分量一开始怀疑是LDO环路振荡。我让他把瞬态波形窗口的起止时间改成信号周期的整数倍再跑FFT频谱立刻干净了问题根本不在电路而在分析方法。模拟电路仿真翻车起码有一半是测量方法本身错了。Virtuoso不会主动告诉你“你这段窗口不是整数周期”它只会诚实地把频谱算出来给你看频谱长什么样完全取决于窗口怎么截。5.2 谐波被底噪淹没时该怎么办信号幅度本身就很小、或者电路线性度特别好时谐波幅度可能低到和噪声底持平。FFT的点数决定噪声底的均值点数每翻倍理想情况下噪声底降低约3dB。所以第一个手段是增加FFT采样点数比如从1024提高到8192这是最直接有效的办法代价是仿真时间和数据分析量都变大。第二个手段是多窗口平均。把时域结果均匀切成多个相干窗口分别做FFT再叠加平均可以把随机噪声底压得更低。这个方法在Virtuoso里用脚本做比较方便人工操作重复性太高。第三个手段是检查仿真精度。如果maxstep太大数值噪声就成了主要底噪来源这时候加再多的点数也压不下去先去把maxstep减小。5.3 信号频率固定时怎么找相干点真实项目里经常遇到这样的场景系统时钟是24MHz我们关心某个10MHz输入信号下的失真。理论上可以调整FFT点数M来找整数周期关系比如M32768时找N使得fin(N/M)×fsN≈13653.33并不是正好整数。这时候要么把fs微调要么允许引入少量泄漏再用窗函数补偿。我个人的习惯是如果系统允许调整输入信号频率就直接把fin设成能满足相干条件的值比如fs24MHz、M4096、N13fin76.171875kHz如果频率不能动那就尽量取更大的M来降低泄漏的绝对影响或者接受加窗结果。值得一提的是Spectre新版本自带的fft相关函数里有“Coherent Measurement”模式可以自动搜索最适合相干采样的窗口长度和采样点数原理上就是替我们在做整数周期的优化。对新手省心但它不会告诉你为什么自动选择了某个值所以我还是建议先手动把原理走通再用自动功能提速。5.4 关于Virtuoso的一些杂谈FFT只是工具链的一环Virtuoso在整个模拟设计流程里的地位当然远不止FFT从原理图输入、gmoverid辅助设计、前仿后仿到版图物理验证是一整套庞大体系。在电路结构设计阶段很多人用gmoverid方法来扫描晶体管偏置快速确定沟道长度和过驱动电压然后在相同环境里直接拉起瞬态仿真跑FFT看线性度整套流程连贯起来非常顺手。这其实是我喜欢Virtuoso的原因不需要把数据导来导去同一个设计环境里就能完成“设计—仿真—后处理”的闭环。FFT和THD分析正是这个闭环里最能体现“仿真工具是放大器”的环节。很多电路设计问题比如运放输出级交越失真、单端电路的偶次谐波、Class-AB偏置引起的交越毛刺都透过谐波分布第一时间暴露出来。看到2次谐波异常高优先怀疑失配或不对称看到3次谐波拖尾优先怀疑偏置点和转换速率不够。FFT不只是用来算一个THD数字它是在帮你做电路诊断。6. 最后一组实操建议跑FFT分析这几年我最大的体会是规范永远是“先想清楚窗口再跑仿真”。绝大多数情况下仿真本身没有任何问题问题出在分析方式。人很容易在Virtuoso的操作界面上迷失——按下run、点开波形、脑子里全是下一步按钮在哪而忘了最基础的问题这段波形里到底包含了多少个完整的信号周期。所以我每次做THD仿真前都会在纸上先算一遍相干参数把M、N、fs、tstab、tstop、maxstep这几个值写成一张便签贴在屏幕边上再打开ADE。这一系列参数它们互相印证如果采样率变了tstrobeperiod和Calculator里的Sample Period必须同步变如果窗口周期数变了tstop和Start Time也要跟着调整。只要表格里的数能对上FFT频谱通常一次就能干净利落地出结果。最后一个小技巧在Virtuoso的ADE窗口里把FFT结果波形保存成一个独立的Output再用Calculator表达式把这个FFT结果送给THD公式这样每次重新仿真、扫描工艺角THD值都会自动刷新省去了重新取数的麻烦。把第一次人工操作的流程沉淀成脚本或表达式后续效率会提升一大截。
返回列表