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

ivcurve.cc

Go to the documentation of this file.
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 doxygen1.2.7