Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

matchivfts.cc

Go to the documentation of this file.
00001 // matchivfts.cc
00002 // Optimize parameters to simultaneously match laboratory pumped IV and
00003 // Fourier Transform Spectrometer (FTS) response data, to evaluate the
00004 // deviation between design and production receiver characteristics.  
00005 //
00006 // Familiarize yourself with hotcold.cc before studying this example,
00007 // which uses the same mixer model (specs.h and build_mixer.inc).
00008 //
00009 // Review the descriptions of the fts_match and iv_match error term
00010 // classes found in the SuperMix header file error_terms.h
00011 
00012 #include "specs.h"
00013 
00014 
00015 int main(int argc, char** argv)
00016 {
00017 
00018 # include "build_mixer.inc"
00019 
00020   // ==========================================================================
00021   // Information regarding the FTS and IV match
00022 
00023   // The FTS measured data info:
00024   char   *ftsname = "fts.data";   // file with the FTS data set
00025   double Vbias    = 2.4*mVolt;    // bias voltage for the data set
00026   double power    = 1*Nano*Watt;  // LO power to simulate FTS
00027 
00028   // The FTS match RF frequency range:
00029   double LO_min   = 500*GHz;
00030   double LO_max   = 1300*GHz;
00031   double LO_step  = 20*GHz;
00032 
00033 
00034   // The Pumped IV measured data info:
00035   char   *ivname = "pumpediv.data"; // file with the IV data set
00036   double freq    =  750*GHz;        // LO freq for the data
00037 
00038   // The Pumped IV match bias voltage range:
00039   double V_min   = -VGAP * 1.2;
00040   double V_max   =  VGAP * 1.2;
00041   double V_step  =  0.2*mVolt;
00042 
00043 
00044   // ==========================================================================
00045   // Error function declarations and Parameters to Optimize
00046 
00047   error_func ef;
00048 
00049   // Here are the physical SIS parameters which we figure might be different
00050   // from their design values and which could significantly affect the
00051   // measured behavior of the circuit. We'll use the optimizer to get an
00052   // estimate of their actual values by matching the model to the measured
00053   // data. We set the initial value of each parameter to its current value,
00054   // assigned in specs.h
00055 
00056   AREA     = ef.vary(AREA*0.7, AREA, AREA*1.3);
00057   RNA      = ef.vary( RNA*0.8,  RNA,  RNA*1.2);
00058 
00059 
00060   // Since our lab setup for the pumped IV measurement had no capability
00061   // to determine the LO power, we must include it as a parameter to be
00062   // determined during the optimization:
00063 
00064   LO_POWER = ef.vary(50, 100, 200, Nano*Watt);
00065 
00066 
00067   // Lastly, the measured IV data has unknown current and voltage offset
00068   // errors. We include these as additional parameters controlled by the
00069   // optimizer:
00070 
00071   parameter I_off = 0.0, V_off = 0.0;
00072     I_off  = ef.vary( -10, 0, 10, Micro*Amp),
00073     V_off  = ef.vary( -.1, 0, .1, mVolt);
00074 
00075 
00076   // ==========================================================================
00077   // The FTS match sweeper and error term
00078 
00079 
00080   // The FTS match sweeper needs to control two parameters:
00081   //   (1) Set the SIS bias voltage to the value used in the data set
00082   //   (2) Sweep the LO frequency over the RF range of the FTS data
00083   //
00084   // We need to set the bias voltage because the sweeper for the pumped
00085   // IV term will be changing it. We need to keep setting it back to
00086   // the FTS value with each iteration of the FTS sweep. The initialize()
00087   // member function was included for just such a contingency. As many
00088   // parameters as you need may be reset at each sweeper iteration by
00089   // adding more initialize() calls for the sweeper setup. 
00090 
00091   sweeper fts_sweep;
00092     fts_sweep.initialize(V_BIAS, Vbias);
00093     fts_sweep.sweep(LO_FREQ, LO_min, LO_max, LO_step);
00094 
00095 
00096   // The FTS match error term is a special one designed to be used
00097   // specifically to match measured FTS data (see error_terms.h). Given
00098   // an FTS data file with an arbitrary scale factor in its response,
00099   // it compares the calculated mixer DC bias current response from the
00100   // model to the FTS file data. Note that in the code below we directly
00101   // access the interpolator of the FTS data to change it to linear
00102   // interpolation mode. The purpose of the f_correct() member function
00103   // is described in error_terms.h
00104 
00105   fts_match fts_term(mix, LO_FREQ, LO_POWER, ftsname, GHz, power);
00106     fts_term.f_correct();
00107     fts_term.measured.linear().build(); // since data is noisy, don't spline
00108 
00109   // Add the term to the error function. Since class fts_match always
00110   // returns an error value for the curve match between 0 and 1, we
00111   // use the error term weight (100 in this case) to scale its return value.
00112   ef.add_term(100.0, fts_term, fts_sweep);
00113 
00114 
00115   // ==========================================================================
00116   // The IV match sweeper and error term
00117 
00118   // The IV match sweeper needs to control two parameters:
00119   //   (1) Set the LO frequency to the value used in the data set
00120   //   (2) Sweep the SIS bias voltage over the bias range of the data
00121   //
00122   // We need to set the LO frequency because the sweeper for the FTS term
00123   // will be changing it. We need to keep setting it back to the proper
00124   // value with each iteration of the IV sweep. Again, the initialize()
00125   // member function was included for just such a contingency.
00126 
00127   sweeper iv_sweep;
00128     iv_sweep.sweep(V_BIAS, V_min, V_max, V_step);
00129     iv_sweep.initialize(LO_FREQ, freq);
00130 
00131 
00132   // The IV match error term is another special one whose class is
00133   // described in error_terms.h  Again we directly access the data
00134   // interpolator to use linear interpolation. Note that we have to
00135   // call build() following the call to linear() in order to actually
00136   // affect the behavior of the interpolator. We also set the offsets to
00137   // shadow the parameters the optimizer will be controlling.
00138 
00139   iv_match iv_term(mix, V_BIAS, ivname, mVolt, Micro*Amp);
00140     iv_term.measured.linear().build();
00141     iv_term.i_offset(&I_off);
00142     iv_term.v_offset(&V_off);
00143 
00144   // Add the iv term to the error function. The weight should result in an
00145   // error term value of ~1.0 for an average error of 1 uA.
00146   ef.add_term(1.0/(Micro*Amp*Micro*Amp), iv_term, iv_sweep);
00147 
00148 
00149   // ==========================================================================
00150   // Optimize:
00151 
00152   // We use the powell optimizer since we expect the design values to be
00153   // pretty close to the actual values. A local optimizer should be just what
00154   // we need, rather than a global optimizer like montecarlo. See the example
00155   // file lna/lna_opt.annotated.cc for more details about using powell.
00156 
00157   powell opt(ef);
00158     opt.verbose();
00159     opt.FTOL = 0.0001;
00160 
00161   // Initial error function stats:
00162   cerr << "Initial error function and parameter stats:" << endl;
00163   cerr << ef() << " : ";
00164   cerr << ef.get_func_breakdown() << endl
00165        << "Parameter values: " << ef.get_parms_user() << endl;
00166 
00167   cerr << "Starting optimization. This may take a while..." << endl;
00168   double final_error = opt.minimize();
00169 
00170   // final error function stats:
00171   cerr << "Final error function and parameter stats:" << endl;
00172   cerr << final_error << " : " << ef.get_func_breakdown() << endl
00173        << "Parameter values: " << ef.get_parms_user() << endl;
00174 
00175   // ==========================================================================
00176   // Here we generate and output the optimized response
00177 
00178   Vector currents;  // Used to temporarily hold SIS bias currents
00179 
00180   // Output a nice header giving details and the final parameter values
00181   // found by the optimizer:
00182 
00183   cout << fixed << setprecision(3);
00184   cout << "# " << argv[0] << ":" << endl
00185        << "# Match Pumped IV and FTS response" << endl
00186        << "# IV  data file: " << ivname << endl
00187        << "# FTS data file: " << ftsname << endl
00188        << "# Control Parameter Values:" << endl
00189        << "#     LO freq    = " << LO_FREQ/GHz << " GHz" << endl
00190        << "#     Min Bias   = " << V_min/mVolt << " mV" << endl 
00191        << "#     Max Bias   = " << V_max/mVolt << " mV" << endl 
00192        << "#     FTS Bias   = " << Vbias/mVolt << " mV" << endl 
00193        << "#     FTS LO pwr = " << power/(Nano*Watt) << " nW" << endl
00194        << "# Optimized Parameters:" << endl
00195        << "#     SUB1_T     = " << SUB1_T/Angstrom << " Angstrom" << endl 
00196        << "#     AREA       = " << AREA/(Micron*Micron) << " sq uM" << endl 
00197        << "#     RNA        = " << RNA/(Ohm*Micron*Micron) << " Ohm sq uM"
00198        << endl 
00199        << "#     IV LO pwr  = " << LO_POWER/(Nano*Watt) << " nW" << endl
00200        << "#     I offset   = " << I_off/(Micro*Amp) << " uA" << endl
00201        << "#     V offset   = " << V_off/(mVolt) << " mV" << endl;
00202 
00203 
00204   // Now output the pumped IV response using the optimized values:
00205   cout << "# V(mV)" << "\t" << "I(uA)" << endl;
00206 
00207   LO_FREQ = freq;
00208 
00209   // We sweep over the Bias Voltage range, generating the response
00210   for(V_BIAS = -1.5*VGAP; V_BIAS <= 1.5*VGAP; V_BIAS += 0.02*mVolt) {
00211 
00212     // Here's where we calculate the total bias current
00213     mix.balance();             // calculate the SIS operating state
00214     currents = mix.I_junc(0);  // vector of DC bias currents
00215     int min = currents.minindex();
00216     int max = currents.maxindex();
00217 
00218     // Sum the junction currents
00219     double resp = 0.0;
00220     for(int i=min; i<=max; i++) resp += currents[i].real;
00221 
00222     // Include offsets in the output, so it can be compared directly
00223     // with the measured data
00224     cout << fixed << setprecision(3)
00225          << (V_BIAS + V_off)/mVolt
00226          << "\t"
00227          << scientific << setprecision(3) << (resp + I_off)/(Micro*Amp)
00228          << endl;
00229   }
00230 
00231 
00232   // Now for the FTS response
00233   cout << "#" << endl;
00234   cout << "# f(GHz)" << "\t" << "response" << endl;
00235 
00236   V_BIAS = Vbias;
00237 
00238   // First we need the dark current, which is independent of input RF (LO)
00239   // frequency, since the RF power is zero:
00240   LO_POWER = 0;
00241   mix.balance();
00242   currents = mix.I_junc(0);
00243   int min = currents.minindex();
00244   int max = currents.maxindex();
00245   double dark_current = 0.0;
00246   for(int i=min; i<=max; i++) dark_current += currents[i].real;
00247 
00248   // Now we sweep over the LO frequency range, generating the response
00249   LO_POWER = power;
00250   for(LO_FREQ = LO_min; LO_FREQ <= LO_max; LO_FREQ += LO_step) {
00251     mix.balance();
00252     currents = mix.I_junc(0);
00253     double resp = 0.0;
00254     for(int i=min; i<=max; i++) resp += currents[i].real;
00255     resp -= dark_current;
00256 
00257     // Scale the response by a freq "correction" factor, since the data
00258     // set included such a factor:
00259     resp *= LO_FREQ;
00260 
00261     // Scale the response so that it matches the FTS data. Use the scale
00262     // value found by fts_term during the final error function calculation.
00263     resp *= fts_term.scale();
00264 
00265     // Output the generated response
00266     cout << fixed << setprecision(0) << LO_FREQ/GHz
00267          << "\t"
00268          << scientific << setprecision(2) << resp
00269          << endl;
00270   }
00271 
00272 }

Please direct comments and corrections to supermix@submm.caltech.edu
Go to the supermix home page
Generated by doxygen1.2.7