module: ring_vco15
inputs: double vin_p, double vin_m, double vdd, double gnd
outputs:  bool out[14:0]
parameters: double fnom, double kv, int noise_enable, double noise_at_foffset, double foffset, double fcorner

static_variables:  double noise_var, double noiseout


classes:  Vco vco("fc + Kv*x","fc,Kv,Ts",1.0,1.0,Ts),
          OneOverfPlusWhiteNoise gnoise();
init:  
double slope;

slope = -10.0;
gnoise.set(fcorner,slope,Ts);
noise_var = foffset*foffset/(kv*kv)*pow(10.0,noise_at_foffset/10.0);
noiseout = 0.0;

// initially set vco to be linear to allow proper settling
vco.set("fc + Kv*x","fc,Kv,Ts,Min,Max",fnom,kv,Ts,1e3,1.0/(Ts*4.0));


code:  
int i;
double noise_val, vtune_delta, phase_threshold;

if (noise_enable == 1)
  {
   gnoise.inp();
   noise_val = sqrt(noise_var/Ts)*gnoise.out;
  }
else
  {
   noise_val = 0.0;
  }

vtune_delta = vin_p - vin_m;
vco.inp(vtune_delta + noise_val);
noiseout = kv*(vtune_delta + noise_val);

if (vco.phase < pi)
   {
    for (i = 0; i < 15; i++)
       {
       phase_threshold = ((double) i)/15.0*pi;
       if (vco.phase < phase_threshold)
            out.set_elem(14-i,1);
       else
            out.set_elem(14-i,0);
       }
  }
else
   {
    for (i = 0; i < 15; i++)
       {
       phase_threshold = ((double) i)/15.0*pi;
       if ((vco.phase-pi) < phase_threshold)
            out.set_elem(14-i,0);
       else
            out.set_elem(14-i,1);
       }
  }
for (i = 0; i < 15; i += 2)
  out.set_elem(i,(out.get_elem(i) == 1) ? 0 : 1);

