00001 // ivcurve.cc 00002 // SuperMix version 1.0 C++ source file 00003 // 00004 // Copyright (c) 1999 California Institute of Technology. 00005 // All rights reserved. 00006 // 00007 // Redistribution and use in source and binary forms for noncommercial 00008 // purposes are permitted provided that the above copyright notice and 00009 // this paragraph are duplicated in all such forms and that any 00010 // documentation and other materials related to such distribution and 00011 // use acknowledge that the software was developed by California 00012 // Institute of Technology. Redistribution and/or use in source or 00013 // binary forms is not permitted for any commercial purpose. Use of 00014 // this software does not include a permitted use of the Institute's 00015 // name or trademark for any purpose. 00016 // 00017 // DISCLAIMER: 00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT 00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR 00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET 00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE 00022 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE 00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO 00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC 00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF 00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN 00027 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK 00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED 00029 // MATERIALS. 00030 // 00031 // Change history: 00032 // 6/21/00: Added capability to read in ivcurve data after creation 00033 // 9/22/99: Changed msglen to static 00034 // 4/12/99: Changed ivcurve to use interpolator<> template class; 00035 // changed interface to ivcurve::I_prime(); added oper() 00036 // 1/19/99: Fixed the file name arguments to ivcurve (added const) 00037 // 12/2/98: Using a cubic interpolation 00038 // 11/11/98: Changed table access to new syntax 00039 // 9/8/98: enhanced to support more realistic iv curves 00040 // 7/28/98: added <math.h> to includes, since SIScmplx.h doesn't 00041 // 7/10/98: Added slope to return value from ivcurve: Iprime() 00042 // 7/2/98: changed header file to junction.h from ivcurve.h 00043 // 6/29/98: finally tested - fixed MAJOR BUGS with indexing 00044 // 6/16/98: removed <String.h> 00045 00046 #include "global.h" 00047 #include "datafile.h" 00048 #include "junction.h" 00049 #include "error.h" 00050 #include <math.h> 00051 #include <stdio.h> // for snprintf() 00052 00053 // Maximum error message string length (in characters) 00054 static const int msglen = 2000 ; 00055 00056 00057 // Constructors: 00058 00059 ivcurve::ivcurve() : valid(false) 00060 { } 00061 00062 ivcurve::ivcurve(const char * const Idc_filename, const char * const Ikk_filename) 00063 { data(Idc_filename, Ikk_filename); } 00064 00065 /* Will add this one later... 00066 ivcurve::ivcurve(char *filename) 00067 { 00068 } 00069 */ 00070 00071 00072 // initialize from data files: 00073 00074 void ivcurve::data(const char * const Idc_filename, const char * const Ikk_filename) 00075 { 00076 datafile Idc_data(Idc_filename), Ikk_data(Ikk_filename); 00077 real_table const * pdata; 00078 int i, max, ix, iy; 00079 00080 // set up interpolators 00081 Idc.clear().no_extrapolation_warning(1).type(interpolator<double>::SPLINE); 00082 Ikk.clear().no_extrapolation_warning(1).type(interpolator<double>::SPLINE); 00083 00084 // load in Idc data: 00085 00086 pdata = Idc_data.table(); 00087 ix = pdata->Lminindex(); // index to get voltage variable 00088 iy = pdata->Lmaxindex(); // index to get current variable 00089 i = pdata->Rminindex(); // start of data 00090 max = pdata->Rmaxindex(); // end of data 00091 00092 // Now do some data validity checks: 00093 if(iy - ix != 1) { 00094 // Then improper number of columns in Idc data file 00095 char errmsg[msglen]; 00096 snprintf(errmsg, msglen, 00097 "Couldn't read correct data from file: %s", 00098 Idc_filename); 00099 error::fatal(errmsg); 00100 } 00101 if(max - i < 3) { 00102 // Then not enough data to deal with 00103 char errmsg[msglen]; 00104 snprintf(errmsg, msglen, 00105 "Not enough IV data in file: %s", 00106 Idc_filename); 00107 error::fatal(errmsg); 00108 } 00109 00110 while (i <= max) { 00111 Idc.add((*pdata)[ix][i],(*pdata)[iy][i]); 00112 ++i; 00113 } 00114 Idc.build(); 00115 00116 // load in Ikk data: 00117 00118 pdata = Ikk_data.table(); 00119 ix = pdata->Lminindex(); // index to get voltage variable 00120 iy = pdata->Lmaxindex(); // index to get current variable 00121 i = pdata->Rminindex(); // start of data 00122 max = pdata->Rmaxindex(); // end of data 00123 00124 // Now do Ikk data validity checks: 00125 if(iy - ix != 1) { 00126 // Then improper number of columns in Idc data file 00127 char errmsg[msglen]; 00128 snprintf(errmsg, msglen, 00129 "Couldn't read correct data from file: %s", 00130 Ikk_filename); 00131 error::fatal(errmsg); 00132 } 00133 if(max - i < 3) { 00134 // Then not enough data to deal with 00135 char errmsg[msglen]; 00136 snprintf(errmsg, msglen, 00137 "Not enough IV data in file: %s", 00138 Ikk_filename); 00139 error::fatal(errmsg); 00140 } 00141 00142 while (i <= max) { 00143 Ikk.add((*pdata)[ix][i],(*pdata)[iy][i]); 00144 ++i; 00145 } 00146 Ikk.build(); // this build is only useful to allow access to the sorted data 00147 00148 // before completing the build of the Ikk interpolator, we need to provide endpoint 00149 // slopes, since the endpoint conditions don't have vanishing Ikk''(V). 00150 // To do this we need to calculate the extrapolation parameters for 00151 // the Ikk data. Derivation on pp 120,121 of FR's notebook. These will also be used 00152 // to get the slope for the final Ikk point; see notebook pg 109. 00153 // Usually, the iv curve data will be normalized so that Rn = Vgap = 1, but this 00154 // isn't necessary. 00155 00156 // To determine Io, the current offset, use the slope and value at the final Idc 00157 // point; we scale by 2/Pi so we don't have to later 00158 00159 double x = Idc.x(Idc.size()-1); // largest voltage in the Idc table 00160 Idc.val_prime(x,Io,c0); // use c0 to temporarily hold slope 00161 00162 Io = x*c0 - Io; // now Io has the offset of I 00163 Io *= 2.0/Pi; // scale now so we save some time later 00164 00165 // now we need to access the sorted Ikk points (that's why we had to build it) 00166 // We convert the last 3 points in the Ikk table to: 00167 // {1/v^2, Ikk(v) - Io Log(v)} == {y,f}: 00168 double y[3], f[3]; 00169 for(i = 1; i <= 3; ++i) { 00170 double v = Ikk.x(Ikk.size() - i); 00171 y[i-1] = 1/(v*v); 00172 f[i-1] = Ikk[Ikk.size() - i] - Io*log(v); 00173 } 00174 00175 // Now we're able to calculate c0, c2, c4: 00176 double M21 = (f[2]-f[1])/(y[2]-y[1]); 00177 double M02 = (f[0]-f[2])/(y[0]-y[2]); 00178 double F = (M02-M21)/(y[0]-y[1]); 00179 00180 // with these definitions, the quadratic approximation is (FR notes, pg 121): 00181 // f[1] + (y-y[1])*(M21+F*(y-y[2])) == c0 + c2*y + c4*y*y 00182 c4 = F; 00183 c2 = M21 - F*(y[2]+y[1]); 00184 c0 = f[1] - y[1]*(M21-F*y[2]); 00185 00186 // Finally, the slope at the final Ikk point, using the approximating fcn: 00187 x = (Io - 2*y[0]*(c2 + 2*c4*y[0]))/Ikk.x(Ikk.size()-1); // use x to hold it temporarily 00188 00189 Ikk.left_slope(0.0).right_slope(x).build(); 00190 00191 // all finished 00192 valid = true; 00193 } 00194 00195 00196 // various ways to fetch IV data 00197 00198 double ivcurve::idcinterp(double v) const 00199 { 00200 return (v < 0.0) ? -Idc(-v) : Idc(v); // Idc(v) is an odd function 00201 } 00202 00203 void ivcurve::idcinterpslope(double v, double & y, double & yp) const 00204 { 00205 // Idc(v) is odd, Idc'(v) is even 00206 if (v < 0.0) { 00207 Idc.val_prime(-v,y,yp); 00208 y *= -1; 00209 } 00210 else { 00211 Idc.val_prime(v,y,yp); 00212 } 00213 } 00214 00215 double ivcurve::ikkinterp(double v) const 00216 { 00217 if (v < 0.0) v *= -1; // Ikk(v) is even 00218 00219 if (v < Ikk.x(0)) { 00220 // v is below table lower limit, slope is horizontal here 00221 return Ikk[0]; // just use first current value in table 00222 } 00223 else if (v > Ikk.x(Ikk.size()-1)) { 00224 // v is beyond table upper limit, so do nonlinear extrapolation 00225 // formula: y = Io*log(v) + c0 + c2/v^2 + c4/v^4 00226 double y = 1/(v*v); 00227 return c0 + y*(c2 + y*c4) + Io*log(v); 00228 } 00229 else { 00230 return Ikk(v); 00231 } 00232 } 00233 00234 void ivcurve::ikkinterpslope(double v, double & y, double & yp) const 00235 { 00236 double av = fabs(v); 00237 // fetch results from interpolator; test if an extrapolation to the right 00238 if ( Ikk.val_prime(av,y,yp) > 0) { 00239 // use special extrapolation formulas 00240 double temp = 1/(av*av); 00241 y = Io*log(av) + c0 + temp*(c2 + temp*c4); 00242 yp = (Io - 2*temp*(c2 + 2*temp*c4))/v; // note divide by v vice av; gets sign right 00243 } 00244 else { 00245 // correct sign of yp 00246 if (v < 0.0) yp *= -1; 00247 } 00248 }
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7