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 // sdata.cc 00031 // 00032 // Change history: 00033 // 11/2/00: Added passive_noise_temp() 00034 // 10/28/99: Fixed normalization Z == 0 handling in ydata and zdata 00035 // 10/22/99: Changes to handling of z_norm and device::Z0; fixed math 00036 // in conversion constructors 00037 // 10/8/99: Slight speedup in sdata::change_norm() 00038 // 11/11/98: Changed table access to new syntax 00039 // 10/7/98: Speeded up sdata conversion constructors 00040 // 9/25/98: Speeded up sdata::passive_noise() 00041 // 9/15/98: Fixed a nasty bug: wrong argument order in 00042 // passive noise calculations. 00043 // 8/27/98: Added SdB, tn, and NF (JSW) 00044 // 7/28/98: added <math.h> to includes, since SIScmplx.h doesn't 00045 // 7/8/98: Added sdata::reindex(); ydata_ptr 00046 // 6/22/98: Added indexing mode flexibility, changed size to 00047 // size() 00048 // 2/10/98: Modified definitions of current, voltage noise 00049 // correlation matrices to be in "ordinary" rather 00050 // than temperature units. (J.Z.) 00051 00052 #include "units.h" 00053 #include "error.h" 00054 #include "nport.h" 00055 #include "Amath.h" 00056 #include <math.h> 00057 00058 // 00059 // passive_noise_temp() 00060 // 00061 00062 double passive_noise_temp(double freq, double Temp) 00063 { 00064 if(Temp < 0.0) 00065 { 00066 error::warning("Can't compute passive noise for negative temperature."); 00067 Temp = -Temp; 00068 } 00069 00070 if(freq < 0.0) 00071 { 00072 error::warning("Can't compute passive noise for negative frequency."); 00073 freq = -freq; 00074 } 00075 00076 if(Temp < Tiny) Temp = Tiny; 00077 double h_f_over_2_kB = 0.5 * hPlanck * freq / BoltzK; 00078 00079 // in the limit freq -> 0, d is simply the temperature: 00080 return (freq == 0.0) ? Temp : h_f_over_2_kB / tanh(h_f_over_2_kB / Temp); 00081 } 00082 00083 00084 // 00085 // sdata member functions 00086 // 00087 00088 sdata::sdata(int s, v_index_mode t) : 00089 z_norm(0.0), S(s,t), C(s,t), B(s,t) // if s < 0, size 0 objects are created (cf table.cc) 00090 { 00091 if(s<0) error::fatal("Cannot create sdata for negative number of ports."); 00092 } 00093 00094 sdata::sdata(const sdata &sd) : 00095 z_norm(sd.z_norm), S(sd.S), C(sd.C), B(sd.B) 00096 { } 00097 00098 sdata::sdata(const sdata &sd, double z0) : 00099 z_norm(sd.z_norm), S(sd.S), C(sd.C), B(sd.B) 00100 { change_norm(z0); } 00101 00102 sdata::sdata(const zdata &zd, double z0) : 00103 z_norm(z0), S(0), C(0), B(0) 00104 { 00105 S.resize(zd.Z); C.resize(zd.Z); B.resize(zd.Vs); 00106 00107 if(z0 <= 0.) { 00108 error::warning( 00109 "Zero or negative normalization impedance passed to sdata constructor !"); 00110 z_norm = z0 = device::Z0 ; // just use default normalization 00111 } 00112 if(S.Lmaxindex() != S.Rmaxindex()) { 00113 error::fatal( 00114 "sdata constructor: zdata::Z matrix must be square."); 00115 } 00116 00117 // use special fast matrix math subroutines 00118 Matrix Temp; Temp.resize(zd.Z); 00119 IplusM(Temp, z_norm, zd.Z); // Temp = Z + z_norm*I 00120 00121 IplusM(S, -z_norm, zd.Z); // S = Z - z_norm*I (temporarily) 00122 S = solve(Temp, S); // S = (Z + z_norm*I)^(-1) (Z - z_norm*I) 00123 00124 B = solve(Temp, zd.Vs); 00125 B *= sqrt(z_norm); // B = sqrt(z_norm) (Z + z_norm*I)^(-1) Vs 00126 00127 IminusM(Temp, 1, S); // Temp = I - S 00128 MAMdagger(C, Temp, zd.C); // C = (I - S) * Cz * dagger(I - S) 00129 C *= 1.0/(4*z_norm*BoltzK); 00130 } 00131 00132 sdata::sdata(const ydata &yd, double z0) : 00133 z_norm(z0), S(0), C(0), B(0) 00134 { 00135 S.resize(yd.Y); C.resize(yd.Y); B.resize(yd.Is); 00136 00137 if(z0 <= 0.) { 00138 error::warning( 00139 "Zero or negative normalization impedance passed to sdata constructor !"); 00140 z_norm = device::Z0 ; 00141 } 00142 if(S.Lmaxindex() != S.Rmaxindex()) { 00143 error::fatal( 00144 "sdata constructor: ydata::Y matrix must be square."); 00145 } 00146 00147 // use special fast matrix math subroutines 00148 Matrix Temp; Temp.resize(yd.Y); 00149 IplusM(Temp, 1/z_norm, yd.Y); // Temp = I/z_norm + Y 00150 00151 IminusM(S, 1/z_norm, yd.Y); // S = I/z_norm - Y (temporarily) 00152 S = solve(Temp, S); // S = (I/z_norm + Y)^(-1) (I/z_norm - Y) 00153 00154 B = solve(Temp, yd.Is); 00155 B *= -1.0/sqrt(z_norm); // B = -sqrt(z_norm) (I + z_norm Y)^(-1) Is 00156 00157 IplusM(Temp, 1, S); // Temp = I + S 00158 MAMdagger(C, Temp, yd.C); // C = (I + S) * Cy * dagger(I + S) 00159 C *= z_norm/(4*BoltzK); 00160 } 00161 00162 sdata::sdata(const ydata_ptr &yp, double z0) : 00163 z_norm(z0), S(0), C(0), B(0) 00164 { 00165 if(z0 <= 0.) { 00166 error::warning( 00167 "Zero or negative normalization impedance passed to sdata constructor !"); 00168 z_norm = device::Z0 ; 00169 } 00170 if(yp.pY == 0) { 00171 error::warning( 00172 "Initializing sdata object from an uninitialized ydata_ptr object !"); 00173 return; 00174 } 00175 00176 S.resize(*(yp.pY)); C.resize(*(yp.pY)); B.reallocate(yp.pY->Rsize, yp.pY->Rmode); 00177 if(S.Lmaxindex() != S.Rmaxindex()) { 00178 error::fatal( 00179 "sdata constructor: ydata_ptr::pY must point to a square matrix."); 00180 } 00181 00182 Matrix Temp; Temp.resize(S); 00183 IplusM(Temp, 1/z_norm, (*yp.pY)); // Temp = I/z_norm + Y 00184 00185 IminusM(S, 1/z_norm, (*yp.pY)); // S = I/z_norm - Y (temporarily) 00186 S = solve(Temp, S); // S = (I/z_norm + Y)^(-1) (I/z_norm - Y) 00187 00188 if(yp.pIs) { 00189 B = solve(Temp, (*yp.pIs)); 00190 B *= -1.0/sqrt(z_norm); // B = -sqrt(z_norm) (I + z_norm Y)^(-1) Is 00191 } 00192 00193 if(yp.pC) { 00194 IplusM(Temp, 1, S); // Temp = I + S 00195 MAMdagger(C, Temp, (*yp.pC)); // C = Temp * C * dagger(Temp) 00196 C *= z_norm/(4*BoltzK); 00197 } 00198 } 00199 00200 sdata & sdata::resize(int n) 00201 { 00202 if(n < 0) { 00203 error::warning( 00204 "Cannot resize sdata to a size < 0. Using size = 0 !") ; 00205 n = 0; 00206 } 00207 S.resize(n); C.resize(n); B.resize(n); 00208 return *this; 00209 } 00210 00211 double sdata::SdB(int i, int j) const 00212 { 00213 return 10.0 * log10(norm(S.read(i, j))); 00214 } 00215 00216 double sdata::tn(int i, int j) const 00217 { 00218 return abs(C.read(i, i)) / norm(S.read(i, j)); 00219 } 00220 00221 double sdata::NF(int i, int j) const 00222 { 00223 return 10.0 * log10(1.0 + tn(i, j)/(290.0*Kelvin)); 00224 } 00225 00226 sdata & sdata::set_znorm(double z) 00227 { 00228 if(z < 0.) { 00229 error::warning( 00230 "Cannot set sdata to a normalization impedance < 0. Using absolute value !") ; 00231 z = -z; 00232 } 00233 00234 z_norm = z; 00235 return *this; 00236 } 00237 00238 sdata & sdata::change_norm(double new_z0) 00239 { 00240 if(new_z0 <= 0.) { 00241 error::warning( 00242 "Cannot change_norm sdata to a normalization impedance <= 0. !") ; 00243 return *this; 00244 } 00245 if((new_z0 == z_norm)||(z_norm == 0.0)) 00246 return *this; // no action required 00247 00248 // if we get here, then new_z0 > 0 and new_z0 != z_norm != 0 00249 if(S.Lmaxindex() != S.Rmaxindex()) { 00250 error::fatal( 00251 "sdata::change_norm(): S matrix must be square."); 00252 } 00253 00254 double rho = sqrt(new_z0/z_norm) ; 00255 z_norm = new_z0 ; 00256 double Sigma = 0.5*(1./rho + rho) ; 00257 double Delta = 0.5*(1./rho - rho) ; 00258 00259 Matrix I = identity_matrix(S) ; 00260 Matrix Factor = Sigma*I - Delta*S ; 00261 B = Factor * B ; 00262 C = Factor * C * dagger(Factor) ; 00263 Factor += (2*Delta) * S ; // now Factor == Sigma*I + Delta*S 00264 S = solve(Factor, Delta*I + Sigma*S); 00265 return *this; 00266 } 00267 00268 00269 sdata & sdata::passive_noise(double freq, double Temp) 00270 { 00271 if(Temp < 0.0) 00272 { 00273 error::warning("Can't compute passive noise for negative temperature."); 00274 Temp = -Temp; 00275 } 00276 00277 if(freq < 0.0) 00278 { 00279 error::warning("Can't compute passive noise for negative frequency."); 00280 freq = -freq; 00281 } 00282 00283 if(Temp < Tiny) Temp = Tiny; 00284 double h_f_over_2_kB = 0.5 * hPlanck * freq / BoltzK; 00285 00286 // in the limit freq -> 0, d is simply the temperature: 00287 double d = (freq == 0.0) ? Temp : h_f_over_2_kB / tanh(h_f_over_2_kB / Temp); 00288 // C = d*(I - S*dagger(S)); this is calculated in the code that follows: 00289 00290 // size the C matrix and set some index limits 00291 int min = S.Lminindex(), max = S.Lmaxindex(); 00292 if ((min != S.Rminindex())||(max != S.Rmaxindex())) 00293 // then S isn't square 00294 error::fatal("S matrix isn't square in sdata::passive_noise."); 00295 C.resize(S); 00296 int len = max - min + 1; len = (len < 0) ? 0 : len; // length of a row of S 00297 complex *ai, *aj; 00298 double neg_d = -d; 00299 for (int i = min; i <= max; ++i) { 00300 ai = & S[i][min]; 00301 C[i][i] = d*(complex(1) - Adot(ai,ai,len)); 00302 for (int j = i + 1; j <= max; ++j) { 00303 aj = & S[j][min]; 00304 C[j][i] = conj( C[i][j] = neg_d * Adot(aj,ai,len) ); 00305 } 00306 } 00307 00308 return *this; 00309 } 00310 00311 //************************************************************* 00312 // zdata member functions 00313 // 00314 00315 zdata::zdata(int s, v_index_mode t) : 00316 Z(s,t), C(s,t), Vs(s,t) // vector and table classes handle s < 0 gracefully 00317 { 00318 if(s<0) error::fatal("Cannot create zdata for negative number of ports."); 00319 } 00320 00321 zdata::zdata(const zdata &zd) : 00322 Z(zd.Z), C(zd.C), Vs(zd.Vs) 00323 { } 00324 00325 zdata::zdata(const sdata &sd) : 00326 Z(0), C(0), Vs(0) 00327 { 00328 double z0 = sd.get_znorm() ; 00329 if(z0 < 0.) { 00330 error::warning( 00331 "Normalization impedance < 0. in sdata to zdata constructor!"); 00332 } 00333 else { 00334 if (z0 == 0.0) z0 = device::Z0; // z0 == 0 means impedance doesn't matter 00335 Matrix I = identity_matrix(sd.size(),sd.mode()) ; 00336 Matrix Temp = inverse(I - sd.S) ; 00337 if (Temp.maxindex() < sd.size()) { 00338 // then (I - sd.S) is singular; 00339 error::warning( 00340 "Impedance representation does not exist in sdata to zdata constructor!"); 00341 } 00342 else { 00343 Z = z0*(Temp * (I + sd.S)) ; 00344 C = (4.0 * BoltzK *z0)*(Temp * sd.C * dagger(Temp)) ; 00345 Vs = (2.0 * sqrt(z0))*(Temp * sd.B) ; 00346 } 00347 } 00348 } 00349 00350 zdata::zdata(const ydata &yd) : 00351 Z(0), C(0), Vs(0) 00352 { 00353 Z = inverse(yd.Y) ; 00354 if (Z.maxindex() < yd.size()) { 00355 // then yd.Y is singular; 00356 error::warning( 00357 "Impedance representation does not exist in ydata to zdata constructor!"); 00358 } 00359 else { 00360 C = Z * yd.C * dagger(Z) ; 00361 Vs = -Z * yd.Is ; 00362 } 00363 } 00364 00365 zdata & zdata::passive_noise(double freq, double Temp) 00366 { 00367 if(Temp < 0.0) 00368 { 00369 error::warning("Can't compute passive noise for negative temperature."); 00370 Temp = -Temp; 00371 } 00372 00373 if(freq < 0.0) 00374 { 00375 error::warning("Can't compute passive noise for negative frequency."); 00376 freq = -freq; 00377 } 00378 00379 if(Temp < Tiny) Temp = Tiny; 00380 double h_f_over_2 = 0.5 * hPlanck * freq ; 00381 double h_f_over_2_kB = h_f_over_2 / BoltzK; 00382 00383 // in the limit freq -> 0, d is simply the temperature: 00384 double d = (freq == 0.0) ? BoltzK*Temp : 00385 h_f_over_2 / tanh(h_f_over_2_kB / Temp); 00386 00387 C = (2.0 * d) * (Z + dagger(Z)) ; 00388 return *this; 00389 } 00390 00391 00392 //************************************************************* 00393 // ydata member functions 00394 // 00395 00396 ydata::ydata(int s, v_index_mode t) : 00397 Y(s,t), C(s,t), Is(s,t) 00398 { 00399 if(s<0) error::fatal("Cannot create ydata for negative number of ports."); 00400 } 00401 00402 ydata::ydata(const ydata &yd) : 00403 Y(yd.Y), C(yd.C), Is(yd.Is) 00404 { } 00405 00406 ydata::ydata(const sdata &sd) : 00407 Y(0), C(0), Is(0) 00408 { 00409 double z0 = sd.get_znorm() ; 00410 if(z0 < 0.) { 00411 error::warning( 00412 "Normalization impedance < 0. in sdata to ydata constructor!"); 00413 } 00414 else { 00415 if (z0 == 0.0) z0 = device::Z0; // z0 == 0 means impedance doesn't matter 00416 Matrix I = identity_matrix(sd.size(),sd.mode()) ; 00417 Matrix Temp = inverse(I + sd.S) ; 00418 if (Temp.maxindex() < sd.size()) { 00419 // then (I + sd.S) is singular; 00420 error::warning( 00421 "Admittance representation does not exist in sdata to ydata constructor!"); 00422 } 00423 else { 00424 Y = (1.0 / z0)*(Temp * (I - sd.S)) ; 00425 C = (4.0 *BoltzK / z0)*(Temp * sd.C * dagger(Temp)) ; 00426 Is = (-2.0 / sqrt(z0))*(Temp * sd.B) ; 00427 } 00428 } 00429 } 00430 00431 ydata::ydata(const zdata &zd) : 00432 Y(0), C(0), Is(0) 00433 { 00434 Y = inverse(zd.Z) ; 00435 if (Y.maxindex() < zd.size()) { 00436 // then Y is singular; 00437 error::warning( 00438 "Admittance representation does not exist in zdata to ydata constructor!"); 00439 } 00440 else { 00441 C = Y * zd.C * dagger(Y) ; 00442 Is = -Y * zd.Vs ; 00443 } 00444 } 00445 00446 ydata & ydata::passive_noise(double freq, double Temp) 00447 { 00448 if(Temp < 0.0) 00449 { 00450 error::warning("Can't compute passive noise for negative temperature."); 00451 Temp = -Temp; 00452 } 00453 00454 if(freq < 0.0) 00455 { 00456 error::warning("Can't compute passive noise for negative frequency."); 00457 freq = -freq; 00458 } 00459 00460 if(Temp < Tiny) Temp = Tiny; 00461 double h_f_over_2 = 0.5 * hPlanck * freq ; 00462 double h_f_over_2_kB = h_f_over_2 / BoltzK; 00463 00464 // in the limit freq -> 0, d is simply the temperature: 00465 double d = (freq == 0.0) ? BoltzK*Temp : 00466 h_f_over_2 / tanh(h_f_over_2_kB / Temp); 00467 00468 C = (2.0 * d) * (Y + dagger(Y)); 00469 return *this; 00470 }
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7