module: opamp_basic_diff_with_cm
description: 
parameters:  double dc_gain, double f_unity, double voffset
             double input_thermal_noise, double input_flicker_corner_frequency,
             int noise_enable, double vsat_pos, double vsat_neg
inputs:  double in_pos, double in_neg, double out_cm
outputs:  double out_pos, double out_neg
classes:  OneOverfPlusWhiteNoise gnoise(), Filter first_order_filt()
static_variables:  double noise_scale
init:  
double slope, dc_gain_converted, filter_bw;

if (dc_gain <= 0.0)
  {
   printf("error in 'opamp_basic':  DC gain must be set > 0dB\n");
   printf("   DC gain is currently set at %5.3g dB\n",dc_gain);
   printf("--> please change this parameter in the appropriate instance\n");
   printf("    within your schematic\n");
   exit(1);
  }
// assume slope of 1/f noise is -10db/decade
slope = -10.0;
gnoise.set(input_flicker_corner_frequency,slope,Ts);
// thermal_noise given as single-sided spectral density
noise_scale = input_thermal_noise*sqrt(0.5/Ts);

// convert gain from dB
dc_gain_converted = pow(10.0,dc_gain/20.0);
// compute bandwidth of first order filter in radians/s
filter_bw = 2*pi*f_unity/(dc_gain_converted - 1);
first_order_filt.set("K","1 + 1/wp*s","K,wp,Ts",dc_gain_converted,filter_bw,Ts);

code:  
double opamp_inp;

opamp_inp = in_pos - in_neg - voffset;

if (noise_enable == 1)
  {
   opamp_inp += noise_scale*gnoise.inp();   
  }

first_order_filt.inp(opamp_inp);
if (first_order_filt.out > vsat_pos)
    first_order_filt.reset(vsat_pos);
if (first_order_filt.out < vsat_neg)
    first_order_filt.reset(vsat_neg);

out_pos = out_cm + 0.5*first_order_filt.out;
out_neg = out_cm - 0.5*first_order_filt.out;
