00001 // SuperMix version 1.0 C++ source file 00002 // 00003 // Copyright (c) 1999 California Institute of Technology. 00004 // All rights reserved. 00005 // 00006 // Redistribution and use in source and binary forms for noncommercial 00007 // purposes are permitted provided that the above copyright notice and 00008 // this paragraph are duplicated in all such forms and that any 00009 // documentation and other materials related to such distribution and 00010 // use acknowledge that the software was developed by California 00011 // Institute of Technology. Redistribution and/or use in source or 00012 // binary forms is not permitted for any commercial purpose. Use of 00013 // this software does not include a permitted use of the Institute's 00014 // name or trademark for any purpose. 00015 // 00016 // DISCLAIMER: 00017 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT 00018 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR 00019 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET 00020 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE 00021 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE 00022 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO 00023 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC 00024 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF 00025 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN 00026 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK 00027 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED 00028 // MATERIALS. 00029 // 00030 // ************************************************************************ 00031 // error_terms.h 00032 // 00033 // Concrete classes for calculating error function terms to be used with 00034 // class error_func, in error_func.h. All are derived from abstract error 00035 // term classes also defined in that header file. 00036 // 00037 // Class: Derived from: Used to optimize: 00038 // gain_dB error_term_mode gain in dB 00039 // s_mag " S parameter magnitude 00040 // input_tn " input noise temperature 00041 // amp_k " amplifier stability "k" 00042 // amp_mag_delta " amplifier stability "delta" 00043 // two_match error_term match two circuit S matrices 00044 // fts_match scaled_match_error_term match FTS response to data 00045 // iv_match error_term match mixer pumped IV to data 00046 // 00047 // 4/21/99 by John Ward 00048 // 00049 // Based on err_term.h written 7/22/98 by J.Z. 00050 // 00051 // 9/15/00: Tweaks to the code. 00052 // 00053 // ************************************************************************ 00054 // classes gain_dB, s_mag, and input_tn 00055 // 00056 // These classes are convenient for optimizing the gain, the input or 00057 // output match, or the noise performance of a circuit. Each requires that 00058 // an nport (circuit) be provided as the first argument in its constructor. 00059 // Addtional arguments may be provided, but are optional. The default 00060 // behavior of each of these classes assumes: 00061 // 00062 // Input port number = 1 change using member function in(int port) 00063 // Output port number = 2 change using member function out(int port) 00064 // Error term mode = MATCH change using error_term_mode functions 00065 // Error term target = 0.0 change using error_term_mode functions 00066 // 00067 // The error_term_mode member functions are described in file error_func.h. 00068 // 00069 // Here are a few examples. Note that here we only provide the circuit as the 00070 // constructor argument. Changes to the ports and/or mode are done using 00071 // member function calls. If you wish to use additional arguments with the 00072 // constructor, consult the actual class declarations in this file. 00073 // 00074 // circuit ckt; // this is the circuit to be optimized. Assume it is 00075 // // a 2-port with input at port 1 and output at port 2. 00076 // 00077 // gain_dB gain(ckt); 00078 // gain.above(+20); // This term generates an error if gain < 20 dB. 00079 // 00080 // gain_dB flat(ckt); 00081 // flat.flat(); // Error proportional to the variation around the mean 00082 // // gain in dB. 00083 // 00084 // input_tn noise(ckt); 00085 // noise.below(4*Kelvin); // Error if input noise > 4K 00086 // 00087 // gain_dB in_match(ckt); 00088 // in_match.in(1).out(1).below(-20); // Error if input reflection > -20 dB. 00089 // 00090 // When concatenating member function calls using ".", always put in() and 00091 // out() calls before calls to error_term_mode functions which set the mode 00092 // and/or target (otherwise the compiler will complain... try it and see!). 00093 // 00094 // ************************************************************************ 00095 // classes amp_k and amp_mag_delta 00096 // 00097 // These two error term classes are used to optimize the stability of a 00098 // 2-port amplifier design. Each requires that an nport (circuit) be 00099 // provided as the first argument in its constructor. Addtional arguments 00100 // may be provided, but are optional. Both use the functionality of class 00101 // ampdata (see ampdata.h) to perform their calculations. 00102 // 00103 // Class amp_k compares the 2-port stability factor "K", which must be > 1 00104 // for an unconditionally stable design, to a specified target. The default 00105 // amp_k object assumes: 00106 // 00107 // Input port number = 1 change using member function in(int port) 00108 // Output port number = 2 change using member function out(int port) 00109 // Error term mode = ABOVE change using error_term_mode functions 00110 // Error term target = 3.0 change using error_term_mode functions 00111 // 00112 // Class amp_mag_delta compares the magnitude of the determinant of the 00113 // 2-port scattering matrix, which must be < 1 for an unconditionally stable 00114 // design, to a specified target. The default amp_mag_delta object assumes: 00115 // 00116 // Input port number = 1 change using member function in(int port) 00117 // Output port number = 2 change using member function out(int port) 00118 // Error term mode = BELOW change using error_term_mode functions 00119 // Error term target = 0.5 change using error_term_mode functions 00120 // 00121 // ************************************************************************ 00122 // class two_match 00123 // 00124 // Class two_match simply takes the matrix difference of the scattering 00125 // matrices returned by two nports, then totals the squared magnitudes of 00126 // the elements of the difference. Its constructor requires two nport 00127 // arguments. 00128 // 00129 // ************************************************************************ 00130 // classes fts_match and iv_match 00131 // 00132 // These classes are used to compare the predictions of an SIS mixer 00133 // model to measured FTS (Fourier Transform Spectrometer) or DC IV curve 00134 // file data. Each has a fairly complicated constructor argument list 00135 // which must include a mixer object (see mixer.h) one or more parameter 00136 // objects, and a data file name, as well as additional options. When 00137 // constructed, the error term reads in the file data and builds an 00138 // internal real_interp (real_interp.h) interpolator of the data. When 00139 // the error term value is calculated, it sets the operating state of 00140 // the mixer by calling mixer::balance(), calculates the total DC bias 00141 // current for the mixer junctions (see junction.h) and compares the 00142 // calculation with the interpolated file data. 00143 // 00144 // Both classes include a public member variable named "measured", which 00145 // is the real_interp object used to interpolate the file data. This 00146 // interpolator is made public so that the user may adjust its behavior 00147 // using its own member functions (see interpolate.h). If the measured 00148 // data has a significant amount of noise, for example, it would be 00149 // prudent to use linear rater than spline interpolation (the default). 00150 // This interpolation mode may be set for an error term "term" by calling: 00151 // 00152 // term.measured.linear().build(); 00153 // 00154 // which rebuilds the interpolation tables for linear interpolation. 00155 // 00156 // 00157 // USAGE: fts_match 00158 // 00159 // fts_match is derived from class scaled_match_error_term. Here's what it 00160 // does: 00161 // 1. At construction, read in the file data and build an interpolation 00162 // of it as a function of mixer LO frequency. 00163 // 2. When reset(), set the LO power to zero, call mixer's balance() to 00164 // set its operating state, and get and save the total junction dark 00165 // current. Restore the LO power variable to its previous state. 00166 // 3. When get() is called, set the LO power to a small value specified 00167 // at construction. Call the mixer's balance() and again get the total 00168 // junction current. Subtract off the dark current; the result is the 00169 // simulated response from the mixer model. Interpolate the FTS data 00170 // for the current LO frequency and compare the simulated and 00171 // interpolated values using the scaled_match_error_term algorithm 00172 // (see error_func.h). 00173 // 00174 // Here's an example of how to create an fts_match error term: 00175 // 00176 // fts_match fts_term(mix, LO_f, LO_p, name, GHz, 1*Nano*Watt); 00177 // // mix: the mixer object 00178 // // LO_f: a parameter object which contains the LO frequency 00179 // // LO_p: a parameter object which controls the LO power 00180 // // name: a char pointer to the data file name (C-style string) 00181 // // GHz: a double value which gives the frequency units in the file 00182 // // (in this case, the file uses GHz as its units) 00183 // // 1*Nano*Watt: a double value for the LO power to set when 00184 // simulating the FTS response with the mixer. 00185 // 00186 // The last two arguments are optional. If omitted, GHz and 10*Nano*Watt 00187 // are assumed. 00188 // 00189 // The measured FTS data must be in a 2 column file, frequency and 00190 // response. Units for frequency can be set with the constructor, as shown. 00191 // The units for the response are arbitrary. 00192 // 00193 // The abstract_real_parameter LO_f will only be accessed using its get() 00194 // function; it will not be written to. The parameter LO_p, on the other 00195 // hand, will be set by the error term whenever the term's reset() or get() 00196 // is executed. The LO_p parameter will be copied and restored to its 00197 // original state by the the functions, however, so other parts of the 00198 // program should not be affected. 00199 // 00200 // The mixer object mix will be modified whenever the term's reset() or 00201 // get() is executed. On reset(), mix.balance() will be called with LO_p 00202 // set to0. On get(), mix.balance() will be called with LO_p set to the LO 00203 // power value specified at construction. Consequently, every call to the 00204 // term's reset() or get() will change the operating state of the junctions 00205 // used by the mixer mix. 00206 // 00207 // Additional member functions of fts_match: 00208 // 00209 // pump(double p); 00210 // sets the LO power to p whenever get() is called. 00211 // 00212 // f_correct(bool f); 00213 // f_correct(); // same as f_correct(true) 00214 // sets an internal flag which affects the comparison to the measured 00215 // data. If f is true, then apply a frequency correction to the 00216 // simulated response by multiplying the response value by the value of 00217 // the LO frequency. If f is false, then don't apply the frequency 00218 // correction (the default behavior). This feature is included because 00219 // some FTS laboratory data acquisition software applies such a 00220 // correction to the measured data set. If this compensation has been 00221 // applied to the data set in the file, then call this member function 00222 // before performing error function calculations to compensate for 00223 // this adjustment to the data. 00224 // 00225 // 00226 // USAGE: iv_match 00227 // 00228 // iv_match is derived from class error_term. Here's what it does: 00229 // 1. At construction, read in the file data and build an interpolation 00230 // of it as a function of mixer DC bias voltage. 00231 // 2. When get() is called, call the mixer's balance() and get the total 00232 // junction current. Interpolate the IV file data for the current 00233 // bias voltage and return the square of the difference between the 00234 // calculated and interpolated currents. 00235 // 00236 // Here's an example of how to create an iv_match error term: 00237 // 00238 // iv_match iv_term(mix, V_bias, name, mVolt, Micro*Amp); 00239 // // mix: the mixer object 00240 // // V_bias: a parameter object which contains the DC bias voltage 00241 // // name: a char pointer to the data file name (C-style string) 00242 // // mVolt: a double value which gives the voltage units in the file 00243 // // (in this case, the file uses millivolts as its units) 00244 // // Micro*Amp: a double value which gives the file's current units 00245 // // (in this case, the file uses microamps as its units) 00246 // 00247 // The last two arguments are optional. If omitted, mVolt and Micro*Amp 00248 // are assumed. 00249 // 00250 // The measured IV data must be in a 2 column file, bias voltage 00251 // and bias current. Units for voltage and current can be set with the 00252 // constructor. Measured data offset error corrections can be specified 00253 // using member functions described below. 00254 // 00255 // The abstract_real_parameter V_bias will only be accessed using its get() 00256 // function; it will not be written to. 00257 // 00258 // The mixer object mix may be modified whenever the term's get() is 00259 // executed. On get(), mix.balance() will be called. Consequently, every 00260 // call to the get() may change the operating state of the junctions 00261 // used by the mixer mix. 00262 // 00263 // Additional member functions of iv_match: 00264 // 00265 // v_offset(v); 00266 // i_offset(i); 00267 // set voltage (v_offset) or current (i_offset) offset corrections 00268 // to be applied to the file data. The sign convention on the offset 00269 // corrections is as follows: the measured data point is the true 00270 // data value + offset, so that: 00271 // I(V) == I_measured(V + V_offset) - I_offset 00272 // The argument may be either a double value or a pointer to an 00273 // abstract_real_parameter object, so that the offsets can shadow 00274 // external parameter objects (and thusly be controlled by the 00275 // optimizer). The default offsets are 0. 00276 // 00277 // ************************************************************************ 00278 00279 #ifndef ERROR_TERMS_H 00280 #define ERROR_TERMS_H 00281 00282 #include "error_func.h" 00283 #include "nport.h" 00284 #include "sdata.h" 00285 00286 // The following are required for class fts_match: 00287 #include "mixer.h" 00288 #include "real_interp.h" 00289 00290 00291 // ************************************************************************ 00292 // 00293 // Gain in dB 00294 // 00295 // ************************************************************************ 00296 class gain_dB : public error_term_mode 00297 { 00298 public: 00299 gain_dB(nport & ckt, // Circuit to optimize 00300 int input = 1, // Input port index 00301 int output = 2, // Output port index 00302 error_term_mode::mode etm = MATCH, // Mode 00303 double tar = 0.0) : // Target value 00304 error_term_mode(etm, tar), 00305 in_port(input), 00306 out_port(output), 00307 np(&ckt) 00308 { } 00309 00310 gain_dB & in(int i) { in_port = i; return *this; } 00311 gain_dB & out(int i) { out_port = i; return *this; } 00312 00313 double get(state_tag); 00314 00315 private: 00316 int in_port, out_port ; 00317 nport *np; 00318 }; 00319 00320 00321 // ************************************************************************ 00322 // 00323 // magnitude of S parameter 00324 // 00325 // ************************************************************************ 00326 class s_mag : public error_term_mode 00327 { 00328 public: 00329 s_mag(nport & ckt, // Circuit to optimize 00330 int input = 1, // Input port index 00331 int output = 2, // Output port index 00332 error_term_mode::mode etm = MATCH, // Mode 00333 double tar = 0.0) : // Target value 00334 error_term_mode(etm, tar), 00335 in_port(input), 00336 out_port(output), 00337 np(&ckt) 00338 { } 00339 00340 s_mag & in(int i) { in_port = i ; return *this ; } 00341 s_mag & out(int i) { out_port = i ; return *this ; } 00342 00343 double get(state_tag); 00344 00345 private: 00346 int in_port, out_port ; 00347 nport *np; 00348 00349 } ; 00350 00351 00352 // ************************************************************************ 00353 // 00354 // input noise temperature 00355 // 00356 // ************************************************************************ 00357 class input_tn : public error_term_mode 00358 { 00359 public: 00360 input_tn(nport & ckt, // Circuit to optimize 00361 int input = 1, // Input port index 00362 int output = 2, // Output port index 00363 error_term_mode::mode etm = MATCH, // Mode 00364 double tar = 0.0) : // Target value 00365 error_term_mode(etm, tar), 00366 in_port(input), 00367 out_port(output), 00368 np(&ckt) 00369 { } 00370 00371 input_tn & in(int i) { in_port = i ; return *this ; } 00372 input_tn & out(int i) { out_port = i ; return *this ; } 00373 00374 double get(state_tag); 00375 00376 private: 00377 int in_port, out_port ; 00378 nport *np; 00379 00380 } ; 00381 00382 00383 // ************************************************************************ 00384 // 00385 // Amplifier "k," useful for optimizing for unconditional stability. 00386 // 00387 // ************************************************************************ 00388 class amp_k: public error_term_mode 00389 { 00390 public: 00391 amp_k(nport & ckt, // Circuit to optimize 00392 int input = 1, // Input port index 00393 int output = 2, // Output port index 00394 error_term_mode::mode etm = ABOVE, // Mode should usually be ABOVE 00395 double tar = 3.0) : // Target value 00396 error_term_mode(etm, tar), 00397 in_port(input), 00398 out_port(output), 00399 np(&ckt) 00400 { } 00401 00402 amp_k & in(int i) { in_port = i ; return *this ; } 00403 amp_k & out(int i) { out_port = i ; return *this ; } 00404 00405 double get(state_tag); 00406 00407 private: 00408 int in_port, out_port ; 00409 nport *np; 00410 00411 } ; 00412 00413 00414 // ************************************************************************ 00415 // 00416 // Amplifier "delta," useful for optimizing for unconditional stability. 00417 // 00418 // ************************************************************************ 00419 class amp_mag_delta: public error_term_mode 00420 { 00421 public: 00422 amp_mag_delta(nport & ckt, // Circuit to optimize 00423 int input = 1, // Input port index 00424 int output = 2, // Output port index 00425 error_term_mode::mode etm = BELOW, // Mode usually BELOW 00426 double tar = 0.5) : // Target value 00427 error_term_mode(etm, tar), 00428 in_port(input), 00429 out_port(output), 00430 np(&ckt) 00431 { } 00432 00433 amp_mag_delta & in(int i) { in_port = i ; return *this ; } 00434 amp_mag_delta & out(int i) { out_port = i ; return *this ; } 00435 00436 double get(state_tag); 00437 00438 private: 00439 int in_port, out_port ; 00440 nport *np; 00441 00442 } ; 00443 00444 00445 // ************************************************************************ 00446 // 00447 // match the S-matrices of two circuits 00448 // 00449 // ************************************************************************ 00450 class two_match : public error_term 00451 { 00452 public: 00453 two_match(nport &ckt1, nport &ckt2) : np1(&ckt1), np2(&ckt2) { } 00454 00455 double get(state_tag); 00456 00457 private: 00458 nport *np1, *np2; 00459 00460 } ; 00461 00462 00463 // ************************************************************************ 00464 // 00465 // Match a simulated mixer response to a measured FTS curve. 00466 // 00467 // ************************************************************************ 00468 class fts_match : public scaled_match_error_term 00469 { 00470 public: 00471 00472 // The constructor. 00473 // The data file must have 2 columns, frequency and measured response. 00474 fts_match(mixer &m, // The mixer to simulate. 00475 const abstract_real_parameter 00476 &freq, // Parameter controlling the LO frequency. 00477 parameter &pow, // Parameter controlling the LO power. 00478 const char*const filename, // File holding measured FTS response. 00479 double units=GHz, // Units of frequency used in data file. 00480 double pump=10.*Nano*Watt) // Value of LO power to simulate FTS. 00481 : 00482 measured(freq, filename, units), mix(&m), f(false), LO_power(&pow), 00483 LO_freq(&freq), pumped_power(pump), dark_current(0), currents(0) 00484 { } 00485 00486 // Set a different value for the pump LO power 00487 fts_match & pump(double p) { pumped_power = p; return *this; } 00488 00489 // Set the frequency "correction" factor flag; If true, the 00490 // calculated response is multiplied by the LO frequency to 00491 // compensate for a similar factor in the measued data. 00492 fts_match & f_correct(bool flag = true) { f = flag; return *this; } 00493 00494 // The measured curve is interpolated from the data read from the file 00495 // as a function of LO frequency. This is a public member variable, so 00496 // the user can access it to set special options, the interpolation 00497 // mode, etc. 00498 real_interp measured; 00499 00500 // Reset the base class; calculate and save the dark current. 00501 void reset(); 00502 00503 // Return the measured FTS response at the LO frequency. 00504 double get_a(state_tag) { return measured; } 00505 00506 // Return the simulated FTS response = pumped current - dark current. 00507 double get_b(state_tag); 00508 00509 private: 00510 mixer *mix; // The mixer. 00511 bool f; // If true, measured response has a freq "correction" factor. 00512 00513 // Setting this parameter sets the LO power in the mixer. 00514 parameter *LO_power; 00515 00516 // This parameter tells us the LO frequency 00517 const abstract_real_parameter *LO_freq; 00518 00519 // Value of the LO power to use for simulating the FTS response. 00520 double pumped_power; 00521 00522 // The dark current is calculated by method reset(). 00523 double dark_current; 00524 00525 // Hold the mixer's junction DC currents 00526 Vector currents; 00527 }; 00528 00529 00530 // ************************************************************************ 00531 // 00532 // Match a simulated mixer IV curve to a measured IV curve 00533 // (pumped or unpumped IV data can be matched) 00534 // 00535 // The error term value is the square of the difference between the 00536 // file's bias current and the calculated bias current at the specified 00537 // bias voltage. 00538 // 00539 // ************************************************************************ 00540 class iv_match : public error_term 00541 { 00542 public: 00543 00544 // The constructor. 00545 // The data file must have 2 columns, frequency and measured response. 00546 iv_match(mixer &m, // The mixer to simulate. 00547 const abstract_real_parameter 00548 &bias, // Parameter controlling bias voltage 00549 const char *const filename,// File holding measured pumped IV. 00550 double V_units=mVolt, // Units of file's bias voltage data 00551 double I_units=Micro*Amp) // Units of file's current data 00552 : 00553 measured(bias, filename, V_units, I_units), mix(&m), V(&bias), 00554 V_off(0.0), I_off(0.0) 00555 { } 00556 00557 // The measured curve is interpolated from the data read from the file 00558 // as a function of bias voltage. This is a public member variable, so 00559 // the user can access it to set special options, the interpolation 00560 // mode, etc. 00561 real_interp measured; 00562 00563 // Set offset errors for the measured data. A measured value is given by 00564 // the actual value + the offset. Note that you can give a pointer to an 00565 // abstract_real_parameter so that the offsets can shadow external 00566 // parameters (and be determined by the optimizer). Be sure to include 00567 // units when providing a value! 00568 iv_match & v_offset(double v) { V_off = v; return *this; } // bias voltage 00569 iv_match & i_offset(double i) { I_off = i; return *this; } // bias current 00570 iv_match & v_offset(const abstract_real_parameter *pv) 00571 { V_off = pv; return *this; } 00572 iv_match & i_offset(const abstract_real_parameter *pi) 00573 { I_off = pi; return *this; } 00574 00575 // Return the measured pumped IV at the bias voltage corrected for offsets 00576 double get_a() { return measured(V_off + *V) - I_off; } 00577 00578 // Return the simulated pumped IV at the bias voltage 00579 double get_b(); 00580 00581 // Return the error term value 00582 double get(state_tag); 00583 00584 private: 00585 mixer *mix; // The mixer. 00586 00587 // This parameter tells us the bias voltage 00588 const abstract_real_parameter *V; 00589 00590 // These are offset errors in the measured data, using the formula: 00591 // (measured value) = (real value) + (offset) 00592 parameter V_off; // measured bias voltage offset error 00593 parameter I_off; // measured bias current offset error 00594 00595 // Hold the mixer's junction DC currents 00596 Vector currents; 00597 }; 00598 00599 #endif /* ERROR_TERMS_H */ 00600
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7