The Designer's Guide Community Forum
https://designers-guide.org/forum/YaBB.pl
Analog Verification >> Analog Performance Verification >> how to make sdm based fractional pll's transient simulation more accurate?
https://designers-guide.org/forum/YaBB.pl?num=1571970292

Message started by lwzunique on Oct 24th, 2019, 7:24pm

Title: how to make sdm based fractional pll's transient simulation more accurate?
Post by lwzunique on Oct 24th, 2019, 7:24pm

Hi,everyone!

the problem is as following:
1. this fractional pll is based on veriloga. all blocks are veriloga model.
2. charge pump current is Icp=16uA, VCO gain kvco=100Mhz, LPF ’s C1=36pf, R1=100K, C2=3.6pf,R3=65K,C3=1pf。
3.when doing transient simulation,after pll locked, using freq function in viva calculator to measure the vco’s frequency, the frequency‘s fluctuation is about 200khz peak to peak, and the center frequency is 4.8G.

it should have fluctuation, but isn't  this value  too large? which magnitude should this fluctuation should
be?

if the magnitude is about 10khz or less, what's wrong with my model.

the model is as below:


PFD code:

Code:
`include "constants.vams"
`include "disciplines.vams"

module PFD_V1_VA (ref_clk, fb_clk, up_out, down_out);
inout ref_clk, fb_clk, up_out, down_out;
electrical ref_clk, fb_clk, up_out, down_out;
parameter real vdd=3.3,
ttol=10f,
ttime=0.2n ;
integer state; // state=1 for down, -1 for up
real td_up, td_down ;
/*
analog begin
@(cross( V(ref_clk) - vdd/2 , 1 , ttol )) begin
state = state - 1;
if(V(up_out)>vdd/2) td_up=480p; else td_up=1005p;
if(V(down_out)<vdd/2) td_down=480p; else td_down=1090p;
end
@(cross( V(fb_clk) - vdd/2 , 1 , ttol )) begin
state = state + 1;
if(V(up_out)>vdd/2) td_up=480p; else td_up=1005p;
if(V(down_out)<vdd/2) td_down=480p; else td_down=1090p;
end
if ( state > 1 ) state = 1 ;
if ( state < -1 ) state = -1;
V(down_out) <+ transition( (state + 1)/2*vdd , td_down , ttime );
V(up_out) <+ transition( (state - 1)/2*vdd+vdd , td_up , ttime );
end
*/
analog begin
@(cross( V(ref_clk) - vdd/2 , 1 , ttol )) begin
if(state<1) state = state + 1;
end
@(cross( V(fb_clk) - vdd/2 , 1 , ttol )) begin
if(state>-1) state = state - 1;
end
V(up_out) <+ transition( (state==1)?1.2:0 , 0 , 10p );
V(down_out) <+ transition( (state==-1)?1.2:0 , 0 , 10p );
end
endmodule


CP code:

Code:
`include "constants.vams"
`include "disciplines.vams"

module CP_VA(up,down,iout);
input up,down;
output iout;
electrical up,down,iout;
parameter Vhigh=1 from[0:inf);
parameter Vlow=0 from[0:inf);
parameter Vtrans=0.5;
parameter vp_h=1.2;
parameter vp_l=0;
/*
real iuptemp,idowntemp,chargecurrent;
analog begin
 chargecurrent=50u;
 iuptemp=(V(up)>Vtrans)?1:0;
 idowntemp=(V(down)>Vtrans)?-1:0;
 I(iout)<+ -iuptemp*chargecurrent-idowntemp*chargecurrent;
 end
endmodule
*/
real iuptemp,idowntemp,chargecurrentdown,chargecurrentup;
analog begin
 if(V(iout)>(vp_l+200m))
    chargecurrentdown=16u;
 if(V(iout)>vp_l && V(iout)<=(vp_l+200m) )
    chargecurrentdown=V(iout)*80u;
 if(V(iout)<=vp_l)
    chargecurrentdown=0;

  if(V(iout)<(vp_h-200m))
    chargecurrentup=16u;
 if(V(iout)>=(vp_h-200m) && V(iout)<vp_h )
    chargecurrentup=(vp_h-V(iout))*80u;
 if(V(iout)>=vp_h)
    chargecurrentup=0;
/*
 iuptemp=(V(up)>Vtrans)?1:0;
 idowntemp=(V(down)>Vtrans)?-1:0;
*/

@(cross(V(up)-Vtrans,1)) iuptemp=1;
@(cross(V(up)-Vtrans,-1)) iuptemp=0;
@(cross(V(down)-Vtrans,1)) iuptemp=-1;
@(cross(V(down)-Vtrans,-1)) iuptemp=0;
 I(iout)<+ -iuptemp*chargecurrentup-idowntemp*chargecurrentdown;
   

end
endmodule


VCO code:

Code:
`include "constants.vams"
`include "disciplines.vams"

module VCO_BITS_TP_FD_VA(loopin,tp,bits,freqout);
input loopin,tp;
input [3:0] bits;
output freqout;
electrical loopin,tp;
electrical [3:0] bits;
electrical freqout;
parameter vhigh=1.2;
parameter vlow=0;
parameter vtrans=(vhigh+vlow)/2;
real tempbits;
real freq;
real fmax;
real fmin;
real vmax;
real vmin;
real initial_freq;
real space;
real kvco;
real gain;
analog begin
kvco=100M;
initial_freq=4720M;
space=20M;
vmax=800m;
vmin=400m;

tempbits=0;
tempbits=tempbits+((V(bits[3])>vtrans)?1:0)*8;
tempbits=tempbits+((V(bits[2])>vtrans)?1:0)*4;
tempbits=tempbits+((V(bits[1])>vtrans)?1:0)*2;
tempbits=tempbits+((V(bits[0])>vtrans)?1:0)*1;
case(tempbits)
0,1,2,3 : gain=1.6M;
4,5,6,7: gain=1.8M;
8,9,10,11:gain=2M;
12,13,14,15:gain=2.4M;
default gain=1.6M;
endcase
fmin=initial_freq+tempbits*space;
fmax=initial_freq+(vmax-vmin)*kvco+tempbits*space;

freq=(V(loopin)-vmin)*kvco+fmin+(V(tp)-0.6)*gain;


if (freq > fmax) freq = fmax;
if (freq < fmin) freq = fmin;
//$bound_step(1/(freq*100));

V(freqout) <+   freq/1e6;


end
endmodule


freq to sin wave conversion code:

Code:
`include "constants.vams"
`include "disciplines.vams"
`define PI        3.14159265358979323846264338327950288419716939937511
module FREQ2VOL_V1_VA(vin, rst, vout);
input vin, rst;
output vout;

electrical vin, rst, vout;

parameter real amp=0.6;
parameter integer steps_per_period=32;
parameter real vco_gain=1e6;

real phase, inst_freq, phase_modulus;
analog begin
     if(V(rst)>0.6) begin
           inst_freq=1e6;
           phase_modulus=1e-3;
           end
     else begin
           inst_freq=vco_gain*V(vin);
           phase_modulus=1;
           end
     $bound_step(1.0 / (steps_per_period*inst_freq));
     phase=idtmod(inst_freq, 0, phase_modulus);
     V(vout) <+ 0.6+amp*sin(2*`PI*phase-`PI);
     end


endmodule


DIVIDER code:

Code:
// VerilogA for nb1820_t55lp_lwz_v01, DIV_VAR_FD_VA, veriloga

`include "constants.vams"
`include "disciplines.vams"

module DIV_VAR_FD_VA(ratio,freqin,freqout);
input freqin,ratio;
output freqout;
electrical freqin,ratio, freqout;

real tempratio;

analog begin

   tempratio=2*V(ratio);

   
   V(freqout) <+ V(freqin)/tempratio;

end


endmodule




Title: Re: how to make sdm based fractional pll's transient simulation more accurate?
Post by lwzunique on Oct 24th, 2019, 7:29pm

mash code:

Code:
`include "constants.h"
`include "discipline.h"

module MASH_VA(fset, cp, f, f_av);
output f;
output f_av;
input cp;
input fset;

electrical f;
electrical cp;
electrical f_av;
electrical fset;

parameter integer BIT = 8;
parameter real vtrans = 0.5;
parameter real outOffset = 0;

  integer out_value;
  real av_out_value;
  integer sum1, sum3, sum2;
  integer sum1_d, sum2_d, sum3_d;
  integer c1, c2, c3;
  integer c3_d;
  integer c2c3, c2c3_d;
  integer c1c2c3;
  integer j, n,  m , k;

  real unconverted;
  real vref;
  real halfref;
  integer vd[0:BIT-1];
  integer w[0:BIT-1];

  analog begin
     @(initial_step ) begin
       
       for ( j = 0; j <= BIT-1 ; j=j+1 ) begin
         w[j] = 1;
       end
       for ( j = 1; j <= BIT-1 ; j=j+1 ) begin
          for ( n = 1; n <= j; n=n+1 ) begin
            w[j] = 2*w[j];
          end
       end
       for ( j = 0; j <= BIT-1 ; j=j+1 ) begin
        //  $strobe("w[%d]=%d\n",j,w[j]);
       end
       vref = 1.0;
       halfref = vref / 2;
       out_value = 0;
       av_out_value = 0;
       n = 1;
       m = 1;
       for ( j = 1; j <= BIT ; j=j+1 ) begin
         m = m * 2;
       end  
       k = 0;
       if ( k >= m ) begin
          $strobe("k must be less than 2^%d", BIT);
          $finish;
       end
       
       c1 = 0;
       c2 = 0;
       c3 = 0;
       sum1 = 0;
       sum2 = 0;
       sum3 = 0;
       sum1_d =0;
       sum2_d =0;
       sum3_d =0;
       c3_d = 0;
       c2c3 = 0;
       c2c3_d = 0;
       c1c2c3 = 0;
     end

     sum1 = k + sum1_d;
     sum2 = sum1_d + sum2_d;
     sum3 = sum2_d + sum3_d;

     if ( sum1 >= m ) begin
      c1 = 1;
      sum1 = sum1 - m;
     end else begin
      c1 = 0;
     end

     if ( sum2 >= m ) begin
      c2 = 1;
      sum2 = sum2 - m;
     end else begin
      c2 = 0;
     end

     if ( sum3 >= m ) begin
      c3 = 1;
      sum3 = sum3 - m;
     end else begin
      c3 = 0;
     end
     c2c3 = c2 + c3 - c3_d;
     c1c2c3 = c1 + c2c3 - c2c3_d;
     out_value = c1c2c3;

     @(cross(V(cp)-vtrans, 1, 10f, cp.potential.abstol) ) begin
       n = n + 1;
       // update k , it is input analogue to digital
       unconverted = V(fset);
       for (j = (BIT-1); j >= 0 ; j = j - 1) begin
          vd[j] = 0;
          if (unconverted >= halfref) begin
             vd[j] = 1;
             unconverted = unconverted - halfref;
          end else begin
             vd[j] = 0;
          end
          unconverted = unconverted * 2;
       end
       k = 0;
       for ( j = 0; j <= BIT-1 ; j=j+1 ) begin
         k = k + vd[j]*w[j];
       end
        // $strobe("k=%d\n",k);
       av_out_value = av_out_value + out_value;
       sum1_d = sum1;
       sum2_d = sum2;
       sum3_d = sum3;
       c3_d = c3;
       c2c3_d = c2c3;
     end

     V(f) <+ out_value + outOffset;
     V(f_av) <+ outOffset + av_out_value/n;

  end

Title: Re: how to make sdm based fractional pll's transient simulation more accurate?
Post by Ken Kundert on Oct 26th, 2019, 11:43am

If you are asking other people to help you with your code, you should take a little time and clean it up to make it easy to read.

If you are going to create a 5kV signal, be sure to run transient with relref=alllocal or errpreset=conservative. Otherwise the simulator will not control errors on normal sized signals.

-Ken

Title: Re: how to make sdm based fractional pll's transient simulation more accurate?
Post by lwzunique on Oct 26th, 2019, 7:18pm


Ken Kundert wrote on Oct 26th, 2019, 11:43am:
If you are asking other people to help you with your code, you should take a little time and clean it up to make it easy to read.

If you are going to create a 5kV signal, be sure to run transient with relref=alllocal or errpreset=conservative. Otherwise the simulator will not control errors on normal sized signals.

-Ken


thanks for reply.

after posting this question,I have done a simulation, changing the bandwidth of pll from 100k to 10k, the fluctuation changed from about 150khz to 2khz. which means 100khz bandwidth can't suppress the quantization noise of sdm. so maybe it's not errors in the code that caused bad accuracy, it's bad system parameters that matters.

I have always thought it was the code and simulation accuracy caused this fluctuation,it seems to be the mis-understanding of thinking.

in my model, vco's output is its frequency ,so  5kv means its freq is 5Ghz, and divider is also frequency domain, after the divider, the freq_to_vol block will change frequency to voltage to form the feedback signal for pfd block.

I will change relref and errpreset to check if this can make the result more accurate.

The Designer's Guide Community Forum » Powered by YaBB 2.2.2!
YaBB © 2000-2008. All Rights Reserved.