In response to Calcul of SNR in CADENCE

I generally don’t like Cadence’s FFT command as it only computes a radix-2 FFT. This is great if your sampling frequency happens to be a power of two of your input frequency. Most of the time, this is the case (or close enough to be immaterial). That’s not the case with me.

I’ll save how I get a non-radix-2 FFT into Cadence for later (I use Matlab). However, here’s how I compute SNR/SNDR when I have an FFT already provided:

- I run the simulation for a time period of (kcyc+ncyc)/fS. fS is the sampling frequency. kcyc is the number of cycles to leave for startup transients.
- I do an FFT over the last ncyc samples. So, even though I run the ADC for (kcyc+ncyc)/fS, I exclude the first kcyc samples. I generally use a minimum 4-term Blackman-Harris window. In simulation, if you ahve the ability to pick your sample frequenciy and input frequency, you don’t need to window; your FFT frequencies will be right-on with the FFT bins. I window anyway.
- I sum up +/- 5 FFT bins around the nominal input frequency. This is because I use the BH4 window, which extends the main lobe of the signal out. I’ve found that +/- 5 bins definitely catches the signal. Any additional noise it catches if usually immaterial.
- For an SNR (versus an SNDR) measurement, I subtract out any distortion. I define distortion as any odd-order harmonics of the signal (odd multiples of the input frequency) that fall within the bandwidth of interest.
- After summing up signal power, noise power, and noise+distortion power, I comute the ratios to get SNR or SNDR.

Anyway. Here’s the code to do it. Once again, I relase it under the GNU Public License to encourage others to contribute back their improvements:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
; Compute SNR based on an FFT of the output ; Copyright (c) 2008 Poojan Wagh (poojanwagh {at} circuitdesign [dot] info) ; http://www.circuitdesign.info ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see <http://www.gnu.org/licenses/>. |

1 2 3 4 5 6 |
ncyc = 1024; % number of points for fft kcyc = 512; % number of points for startup (excluded for fft) simtime = (ncyc+kcyc)/fS % total simulation time fbin = fS/ncyc; % FFT bin width (Hz) fin = 13*fbin; % Input frequency (arbitrary) bw = round(2E6/fbin)*fbin; % bandwidth (rounded to FFT bin) |

1 2 3 4 5 6 7 |
procedure( sumpsd( psd fstart fend) if(fstart < fend then integ( clip(psd fstart fend) ) else 0.0 ) ) |

1 2 3 4 5 6 |
; get power of signal centered at fc procedure( getpow( psd fc fbin ) let( list( (speclobew 5) ) sumpsd(psd fc-speclobew*fbin fc+speclobew*fbin) ) ) |

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
; compute PSD of output (abs(FFT)^2) ; I'm currently using Matlab to do this (procedure matpsd) ; However, Cadence/Ocean's fft() function will do equally well: psdoutput = matpsd( dumpfile fS ncs ncyc ) ; PSig = sumpsd(psdoutput fin-5*fbin fin+5*fbin) ; Signal Power PSig = getpow(psdoutput fin fbin) ; Signal Power PND = sumpsd(psdoutput 0 min(bw fin-6*fbin)) + sumpsd(psdoutput fin+6*fbin bw) ; Noise Power PN = PND; exbw = 0; ; for SNR measurement, exclude odd-mode distortion ; from 3*fin to bw for( k 1 floor(bw/2/fin) fex1 = (2*k+1)*fin-5*fbin fex2 = min(bw (2*k+1)*fin+5*fbin) psdex = sumpsd(psdoutput fex1 fex2); ; printf("k = %u Excluding distortion from %f kHz to %f kHz (%g - %g)\n" 2*k+1 fex1 fex2 PN psdex) PN = PN - psdex; exbw = exbw + (fex2-fex1); ; printf("Excluding distortion from %f kHz to %f kHz (%f kHz)\n" fex1/1.0k fex2/1.0k (fex2-fex1)/1.0k); ) PN = PN / (1 - exbw/bw) ;compensate for frequencies we have excluded ;(assuming white noise) SNDR = PSig/PND; SNR = PSig/PN; SNDRdB = db10(SNDR); SNRdB = db10(SNR); printf("SNDR [%s/%s/%s]= %.2f dB\n" library cell view SNDRdB); printf("SNR [%s/%s/%s]= %.2f dB\n" library cell view SNRdB); sprintf(wintitle "PSD of Digitized PWM [%s/%s/%s] SNDR = %.0f dB NSR = %.0f dB" library cell view SNDRdB SNRdB) plot(db10(clip(psdoutput, fin-5*fbin, fin+5*fbin)) db10(psdoutput) ?expr list("Desired Signal" wintitle)) xLimit(list(0 bw)) |

## One Comment

Hi, I am doing project on a similar topic of this, which is to design a DEM circuit for feedback DAC of delta-sigma modulator. And I found the post here is useful for me. many thanks for your work.