Calculation of ADC SNR in Cadence Skill/Ocean

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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:

; 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/>.
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)
procedure( sumpsd( psd fstart fend)
  if(fstart < fend then
    integ( clip(psd fstart fend) )
  else
    0.0
  )
)
; get power of signal centered at fc
procedure( getpow( psd fc fbin )
  let( list( (speclobew 5) )
    sumpsd(psd fc-speclobew*fbin fc+speclobew*fbin)
  )
)
  ; 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))
This entry was posted in Analog Professional and tagged , , , , , , , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. Jack Wang
    Posted December 12, 2008 at 7:11 am | Permalink

    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.

Post a Comment

You must be logged in to post a comment.