module: dac2real
description: 
timing_sensitivity: 
parameters:  int wid_in, int signed_in
             double out_pp_sngl, double out_cm
             double fbw, int en_noise
             double thermal_noise, double flicker_corner
inputs:  double in, double_interp clk
outputs:  double out_p, double out_m
classes:  EdgeDetect pos_clk_edge()
          Filter lpf("1","1 + 1/wp*s","wp,Ts",2.0*pi*fbw,Ts)
          OneOverfPlusWhiteNoise gnoisep()
          OneOverfPlusWhiteNoise gnoisem()
static_variables:  int edge_flag, double in_scaled, 
                   double in_filt, double scale,
                   double noise_scale
init:  
double slope;

if (wid_in < 1)
  {
   printf("error in 'dac2real':  wid_in must be >= 1\n");
   printf("  -> in this case, wid_in = %d\n", wid_in);
   exit(1);
  }
if (signed_in != 0 && signed_in != 1)
  {
   printf("error in 'dac2real':  signed_in must be 0 or 1\n");
   printf("  -> in this case, signed_in = %d\n", signed_in);
   exit(1);
  }
out_p = out_cm;
out_m = out_cm;
edge_flag = 0;
scale = out_pp_sngl/(pow(2.0,(double) wid_in)-1.0);
in_scaled = 0.0;
in_filt = 0.0;

// assume slope of 1/f noise is -10db/decade
slope = -10.0;
gnoisep.set(flicker_corner,slope,Ts);
gnoisem.set(flicker_corner,slope,Ts);
// thermal_noise given as single-sided spectral density
noise_scale = thermal_noise*sqrt(0.5/Ts);

end:  
code:  
double filt_in;

// put in one sample delay
out_p =  lpf.out + out_cm;
out_m = -lpf.out + out_cm;

if (en_noise != 0)
  {
   out_p += noise_scale*gnoisep.inp();
   out_m += noise_scale*gnoisem.inp();
  }

if (pos_clk_edge.inp(clk))
   {
    edge_flag = 1;
    if (signed_in == 0)
       in_scaled = scale*((double) in) - out_pp_sngl/2.0;
    else
       in_scaled = scale*((double) in);
    in_filt = (in_filt*(1.0 - clk) + in_scaled*(1.0 + clk))/2.0; 
   }
else if (edge_flag == 1)
   {
    edge_flag = 0;
    in_filt = in_scaled;
   }
lpf.inp(in_filt);
