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

trlines.cc

Go to the documentation of this file.
00001 // trlines.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 // 5/31/00:  fixed wrong sign in r_waveguide lossy dielectric calculation
00033 // 5/30/00:  changed zchar to zwave in r_waveguide calculations
00034 // 4/7/00:   changed trl_base::calc() for length == 0.0; some mods to
00035 //           microstrip code to improve readability and efficiency.
00036 // 11/16/99: made wavelength() and percent_loss() part of trl_base()
00037 // 11/16/99: changes to support new noise calculations
00038 // 9/29/99:  added conducting backing to cpw code (lossless calculations)
00039 // 8/23/99:  added cpw code (only lossless calculations!)
00040 // 3/22/99:  changed VERYBIG to MSTRIP_H_VERYBIG, 
00041 //           VERYSMALL to MSTRIP_H_VERYSMALL
00042 // 11/11/98: Changed table access to new syntax
00043 // 9/17/98:  changed trl to trl_base; sped up member fcns
00044 // 9/16/98:  changed the names of some members
00045 // 2/10/98:  modified by JZ
00046 //          - added Temp (temperature) parameter to class microstrip 
00047 //            This allows the temperature of a microstrip section to be
00048 //            arbitrary, not necessarily the same as device::T
00049 //          - introduced utility functions wavelength(), percent_loss()
00050 //            to calculate these quantities from the complex propagation
00051 //            constant.
00052 // 12/29/97: modified by FR for new sdata (with znorm)
00053 // 12/19/97: modified by FR for matmath classes
00054 //
00055 #include <math.h>
00056 #include "global.h"
00057 #include "units.h"
00058 #include "SIScmplx.h"
00059 #include "surfaceZ.h"
00060 #include "parameter.h"
00061 #include "nport.h"
00062 #include "mstrip.h"
00063 #include "error.h"
00064 #include "trlines.h"
00065 
00066 
00067 // ************************************************************************
00068 //
00069 // class trl_base
00070 //
00071 // ************************************************************************
00072 
00073 // calc calculates the scattering matrix
00074 void trl_base::calc(complex b, complex z, double length, double znorm)
00075 {
00076   // Note: propagation factor is taken to be exp(-b*length)
00077   // so b.real > 0 ensures attenuation of wave
00078   //
00079   // the form of the scattering matrix elements used requires only one
00080   // complex exponential evaluation:
00081   //
00082   //       (z*z - 1)*(1 - exp(-k)*exp(-k))           4*z*exp(-k)
00083   // s11 = -------------------------------  ;  s12 = -----------
00084   //                 denom                              denom
00085   //
00086   // denom = (z+1)*(z+1) - (z-1)*(z-1)*exp(-k)*exp(-k)
00087   //
00088   // k = b*length;    z = z/znorm
00089   //
00090   // NOTE: if length == 0.0, then s11 = 0 and s12 = 1 will be returned
00091 
00092   complex s11(0.0), s12(1.0);   // the values if length == 0
00093 
00094   if(length != 0.0) {
00095     z /= znorm ;                // normalize to standard impedance
00096     b *= -length; b = exp(b);   // now b = exp(-k)
00097     s12 = 4*z*b;                //   s12 = 4*z*exp(-k)
00098     b *= b;                     // now b = exp(-2*k)
00099     s11 = z + 1;                // use s11 as a temporary for now
00100     z -= 1;
00101     complex denom = s11*s11 - z*z*b;
00102     s12 /= denom;
00103     s11 *= z*(1-b)/denom;
00104   }
00105 
00106   // fill in S matrix
00107   data.set_znorm(znorm);        // added 12/29/97
00108   data.S[1][1] = s11;
00109   data.S[2][2] = s11;
00110   data.S[1][2] = s12;
00111   data.S[2][1] = s12;
00112 }
00113 
00114 double trl_base::wavelength(complex prop_constant)
00115 {
00116    return(2.*Pi/imag(prop_constant)) ;
00117 }
00118 
00119 double trl_base::percent_loss(complex prop_constant)
00120 {
00121    double alpha = real(prop_constant) ;
00122    double wvlen = wavelength(prop_constant) ;
00123    return( 100.*(1.-exp(-2.*alpha*wvlen)) ) ;
00124 }
00125 
00126 // ************************************************************************
00127 //
00128 // class microstrip:
00129 //
00130 // ************************************************************************
00131 
00132 // Default constructor
00133 microstrip::microstrip()
00134   : trl_base(), length(0.), width(0.), sub_thick(0.), Temp(&device::T),
00135     sub(0), super(0), top(0), ground(0)
00136 { }
00137 
00138 void microstrip::update(double freq, double T)
00139 {
00140    // Make sure we have valid pointers
00141    if(sub == 0)
00142      error::fatal("Substrate dielectric not defined for microstrip line !");
00143    if(super == 0)
00144      error::fatal("Superstrate dielectric not defined for microstrip line !");
00145    if(ground == 0)
00146      error::fatal("Ground plane film not defined for microstrip line !");
00147    if(top == 0)
00148      error::fatal("Top strip film not defined for microstrip line !");
00149    if(length.get() < 0.)
00150      error::fatal("Microstrip length is negative !") ;
00151    if(width.get() <= 0.)
00152      error::fatal("Microstrip width is zero or negative !") ;
00153    if(sub_thick.get() <= 0.)
00154      error::fatal("Microstrip substrate thickness is zero or negative !") ;
00155 
00156    // Set up parameters for calling mstrip
00157 
00158    double h = sub_thick.get() ;
00159    double w = width.get() ;
00160    double t1 = top->thickness() ;
00161    double t2 = ground->thickness() ;
00162 
00163    complex esubc = sub->epsilon(freq, T) ;
00164    double  esub = real(esubc) ;
00165    double  tdsub = fabs(tan(arg(esubc))) ;
00166 
00167    complex eupc = super->epsilon(freq, T) ;
00168    double  eup = real(eupc) ;
00169    double  tdup = fabs(tan(arg(eupc))) ;
00170 
00171    double  Qsub;
00172    if(tdsub < MSTRIP_H_VERYSMALL)   // These constants are defined in mstrip.h
00173       Qsub = MSTRIP_H_VERYBIG;
00174    else
00175       Qsub = 1./tdsub;   
00176 
00177    double  Qup;
00178    if(tdup < MSTRIP_H_VERYSMALL)
00179       Qup = MSTRIP_H_VERYBIG;
00180    else
00181       Qup = 1./tdup;   
00182 
00183    // create variables to hold the return values
00184 
00185    double Zms, epeff, tandel, g2 ;
00186 
00187    // call mstrip()
00188 
00189    mstrip(h, w, t1, t2, esub, eup, Qsub, Qup, freq, 
00190           Zms, epeff, tandel, g2) ;
00191 
00192    // Convert to equivalent series and shunt elements
00193    //
00194    double wavelen = cLight/(freq*sqrt(epeff)) ;
00195    double kimag = fabs(2.*Pi/wavelen) ;  // make sure we know signs
00196    double kreal = kimag*fabs(tandel) ;
00197    zchar = fabs(Zms) ;                   // uncorrected characteristic Z
00198    if(kreal < MSTRIP_H_VERYSMALL*kimag)
00199       kreal = MSTRIP_H_VERYSMALL*kimag ; // always keep tiny amount of loss 
00200 
00201    // Propagation factor is defined as exp(-beta*length)
00202    // This is consistent with exp(+j omega t) time dependence
00203    //
00204    beta = complex(kreal, kimag) ;       // uncorrected propagation const
00205    Zs = beta*zchar ;                    // guaranteed that Re(Zs) > 0
00206    Yp = beta/zchar ;                    // guaranteed that Re(Yp) > 0
00207 
00208 
00209    // Calculate corrections due to superconductor
00210    // Assume the same current distribution in ground plane and top strip
00211    //
00212    complex Ztop = top->Zsurf(freq, T) ;
00213    complex Zground = Ztop ;
00214    if(ground != top)                        // metal layers are different
00215      Zground = ground->Zsurf(freq, T) ;     // so do need to calculate
00216    complex Zsurf = 0.5*(Ztop+Zground) ;
00217    Zs += g2*Zsurf;           // corrected series impedance per length
00218 
00219    // Note: Re(Zsurf) > 0 should be true since metal films are passive
00220    // This implies Re(Zs) > 0 still true
00221    // So corrected propagation constant and characteristic impedance
00222    // should still satisfy Re(beta) > 0 and Re(zchar) > 0
00223 
00224    beta = sqrt(Zs*Yp) ;
00225    if(real(beta) < 0.)
00226      beta *= -1. ;   // choose other branch to make wave attenuate
00227 
00228    zchar = sqrt(Zs/Yp) ;
00229    if(real(zchar) < 0.)
00230      zchar *= -1. ;   // choose other branch
00231 }
00232 
00233 
00234 // ************************************************************************
00235 //
00236 // class cpw
00237 //
00238 // ************************************************************************
00239 
00240 double cpw::cefr(double k)
00241 {
00242   double power = 1;
00243 
00244   if(k < 0.7071067812)
00245   {
00246     k = sqrt(1 - k*k);
00247     power = -1;
00248   }
00249 
00250   double sqrt_k = sqrt(k);
00251   double rtval = log(2. * (1.+sqrt_k) / (1 - sqrt_k)) / Pi;     // Natural log.
00252 
00253   if (power == 1) return rtval;
00254 
00255   return 1.0 / rtval;
00256 }
00257 
00258 
00259 // constructor
00260 cpw::cpw()
00261   : trl_base(), length(0.), width(0.), space(0.), sub_thick(0.), Temp(&device::T),
00262     sub(0), top(0), bottom(0)
00263 { }
00264 
00265 void cpw::update(double freq, double /* T */ )  // lossless, so T isn't needed yet
00266 {
00267   // Make sure we have valid pointers
00268    if(sub == 0)
00269      error::fatal("Substrate dielectric not defined for cpw line !");
00270    if(top == 0)
00271      error::fatal("Top strip film not defined for cpw line !");
00272    if(length.get() < 0.)
00273      error::fatal("cpw length is negative !") ;
00274    if(width.get() <= 0.)
00275      error::fatal("cpw width is zero or negative !") ;
00276    if(space.get() <= 0.)
00277      error::fatal("cpw space is zero or negative !") ;
00278    if(sub_thick.get() <= 0.)
00279      error::fatal("cpw substrate thickness is zero or negative !") ;
00280 
00281   // The following variables are used to make the math simpler.
00282   // See "Microwave Solid State Circuit Design" by Bahl and Bhartia, page 24.
00283   double a, b, k, k1;
00284 
00285   a = width /2.;
00286   b = space + a;
00287   k = a / b;
00288 
00289   double epsilon_effective;
00290 
00291   if(bottom == 0)  // No ground plane under substrate
00292   {
00293     k1 = sinh(0.5 * Pi * a / sub_thick) / sinh(0.5 * Pi * b / sub_thick);
00294 
00295     epsilon_effective = 1. + (0.5 * (sub->epsilon(freq, Temp).real - 1.)
00296                 * cefr(k1) / cefr(k));
00297     zchar = 30. * Pi / (sqrt(epsilon_effective) * cefr(k));
00298   }
00299   else  // There is a ground plane under substrate
00300   {
00301     k1 = tanh(0.5 * Pi * a / sub_thick) / tanh(0.5 * Pi * b / sub_thick);
00302 
00303     epsilon_effective = (1. + sub->epsilon(freq, Temp).real * cefr(k1)/cefr(k))
00304                     / (1. + cefr(k1) / cefr(k));
00305 
00306     zchar = 60. * Pi / (sqrt(epsilon_effective) * (cefr(k) + cefr(k1)));
00307   }
00308 
00309   //
00310   // Convert to equivalent series and shunt elements
00311   //
00312   double wavelen = cLight/(freq*sqrt(epsilon_effective)) ;
00313   double kimag = fabs(2.*Pi/wavelen) ;  // make sure we know signs
00314 
00315   beta = complex(0., kimag);   // lossless
00316   Zs = beta*zchar ;            // guaranteed that Re(Zs) > 0
00317   Yp = beta/zchar ;            // guaranteed that Re(Yp) > 0
00318 
00319 /* This is the lossy microstrip code... needs to be checked for cpw
00320 // WHAT IS ALPHA?  (attenuation factor)
00321 // WHAT IS g2?  (geometrical factor for loss calculations)
00322 
00323    double kreal = fabs(alpha);
00324 
00325    if(kreal < MSTRIP_H_VERYSMALL*kimag)
00326       kreal = MSTRIP_H_VERYSMALL*kimag ; // always keep tiny amount of loss
00327    // 
00328    // Propagation factor is defined as exp(-beta*length)
00329    // This is consistent with exp(+j omega t) time dependence
00330    //
00331    beta = complex(kreal, kimag) ;       // uncorrected propagation const
00332    Zs = beta*zchar ;                    // guaranteed that Re(Zs) > 0
00333    Yp = beta/zchar ;                    // guaranteed that Re(Yp) > 0
00334 
00335    //
00336    // Calculate corrections due to superconductor
00337 
00338    complex Zsurf = top->Zsurf(freq, T) ;
00339    Zs += g2*Zsurf;           // corrected series impedance per length
00340 
00341    // Note: Re(Zsurf) > 0 should be true since metal films are passive
00342    // This implies Re(Zs) > 0 still true
00343    // So corrected propagation constant and characteristic impedance
00344    // should still satisfy Re(beta) > 0 and Re(zchar) > 0
00345 
00346    beta = sqrt(Zs*Yp) ;
00347    if(real(beta) < 0.)
00348      beta *= -1. ;   // choose other branch to make wave attenuate
00349 
00350    zchar = sqrt(Zs/Yp) ;
00351    if(real(zchar) < 0.)
00352      zchar *= -1. ;   // choose other branch
00353 */
00354 }
00355 
00356 // ************************************************************************
00357 //
00358 // class r_waveguide
00359 //
00360 // ************************************************************************
00361 
00362 void r_waveguide::update(double freq, double T)
00363 {
00364   // Make sure we have valid parameters
00365   if(length.get() < 0.)
00366     error::fatal("r_waveguide length is negative !") ;
00367   if(a.get() <= 0.)
00368     error::fatal("r_waveguide \"a\" dimension is zero or negative !") ;
00369   if(b.get() <= 0.)
00370     error::fatal("r_waveguide \"b\" dimension is zero or negative !") ;
00371 
00372   // the material characteristics:
00373   complex eps   = (fill_) ? fill_->epsilon(freq,T) : 1.0;    // vacuum is default
00374   double  Rs    = (wall_) ? wall_->Zsurf(freq,T).real : 0.0; // perfect is default
00375   double  n     = sqrt(eps.real);                            // index of refraction
00376   
00377   // wave propagation characteristics:
00378   double  Zfree = ZVacuum/n;                // dielectric wave impedance
00379   double  k   = 2*Pi*freq*n/cLight;         // dielectric wave number
00380   double  kc  = Pi/a;                       // cutoff wave number
00381   bool imaginary_beta = (k <= kc);          // are we at or below cutoff?
00382   double beta = (imaginary_beta) ?          // wavenumber in guide
00383     sqrt(kc*kc - k*k) : sqrt(k*k - kc*kc);  // gamma = alpha + I*beta
00384 
00385   // handle above cutoff case first:
00386   if(!imaginary_beta) {
00387     // these loss calculations are only accurate if small compared to beta
00388     double alpha_c = (wall_) ?
00389       Rs*(2*b*Pi*Pi/(a*a*a) + k*k)/(b*k*Zfree*beta) : 0.0;
00390     double alpha_d = (fill_) ?
00391       -k*k*eps.imaginary/(2*eps.real*beta) : 0.0; // eps.imaginary <= 0
00392 
00393     gamma = complex(alpha_c+alpha_d, beta);
00394     zwave = (k*Zfree/beta)*complex(1.0, (alpha_d - alpha_c*k/beta)/beta);
00395   }
00396   else {
00397     // don't include loss calulations below cutoff; too hard to figure out
00398     gamma = beta;
00399     zwave = complex(0.0, -k*Zfree/beta);
00400   }
00401 }
00402 
00403 double r_waveguide::fc(double freq, double T)
00404 {
00405   if ( a <= 0.0)
00406     error::fatal("r_waveguide \"a\" dimension is zero or negative !");
00407 
00408   double f = cLight/(2.0*a);
00409   if(fill_) f /= sqrt((fill_->epsilon(f,T)).real);
00410   return f;
00411 }
00412 
00413 const nport::data_info & r_waveguide::get_data_info()
00414 {
00415   info.noise  = (fill_ || wall_); // a real material gives noise
00416   info.active = (info.noise && Temp != device::T);
00417   return info;
00418 }

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