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
1.2.7