00001 // circuit.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 // 2/24/00: Added initialization of cascade::last to constructor 00033 // 11/16/99: Changes to support new noise calculations 00034 // 10/29/99: Added better normalizing impedance handling. 00035 // 11/11/98: Changed table access to new syntax 00036 // 9/17/98: added build_tree, etc. for huge speed increase. 00037 // 8/21/98: added class cascade 00038 // 8/19/98: added check for connecting a port to itself; 00039 // added a local temperature Temp 00040 // 7/8/98: added checks for nport indexing mode and size 00041 // 7/3/98: added code to construct purely block-diagonal 00042 // circuits, using new connection constructor 00043 // 6/26/98: modified by FR for new sdata::size() 00044 // 12/29/97: modified by FR for new sdata (with znorm) 00045 // 12/19/97: modified by FR for matmath classes 00046 00047 #include "circuit.h" 00048 #include "error.h" 00049 00050 00051 //************************************************************** 00052 // construction, assignment, and destruction 00053 00054 circuit::circuit() : nport(0), tree_is_built(false), Temp(&T) 00055 { } 00056 00057 00058 circuit::circuit(const circuit & c) : nport(c), tree_is_built(false), Temp(c.Temp) 00059 { 00060 devset = c.devset; 00061 constack = c.constack; 00062 labels = c.labels; 00063 } 00064 00065 00066 circuit & circuit::operator=(const circuit & c) 00067 { 00068 // Beware of self assignment: c = c 00069 if(this != &c) 00070 { 00071 Temp = c.Temp; 00072 devset = c.devset; 00073 constack = c.constack; 00074 labels = c.labels; 00075 tree_is_built = false; 00076 } 00077 return *this; 00078 } 00079 00080 00081 circuit::~circuit() 00082 { 00083 while(!del_stack.empty()) 00084 { 00085 delete del_stack.top(); 00086 del_stack.pop(); 00087 } 00088 } 00089 00090 00091 //************************************************************** 00092 // managing the data structures 00093 00094 void circuit::connect(nport & dev1, int index1, nport & dev2, int index2) 00095 { 00096 port port1, port2; 00097 portArray p(2); 00098 00099 // Make sure build_tree gets called to include this connection in the tree. 00100 tree_is_built = false; 00101 00102 // Make sure port indices are valid. If not, exit. 00103 if(dev1.size() == 0 || dev2.size() == 0) 00104 error::fatal("Can't connect an nport which doesn't know its size in circuit."); 00105 if(dev1.mode() != Index_1 || dev2.mode() != Index_1) 00106 error::fatal("Can only connect nports with mode()==Index_1 in circuit."); 00107 if((index1 < 1) || (index2 < 1) || (index1 > dev1.size()) || (index2 > dev2.size())) 00108 error::fatal("Illegal port index at circuit::connect."); 00109 00110 port1 = port(dev1.id, index1); 00111 port2 = port(dev2.id, index2); 00112 00113 // Make sure we're not connecting a port to itself 00114 if (port1 == port2) 00115 error::fatal("Can't connect a port to itself in circuit."); 00116 00117 // Make sure neither port is already in connection list. 00118 if(constack.isPresent(port1) || constack.isPresent(port2)) 00119 error::fatal("Can't connect one port in two places in circuit::connect."); 00120 00121 // Make sure neither port is already in label list. 00122 if(labels.isPresent(port1) || labels.isPresent(port2)) 00123 error::fatal("Can't connect one port in two places in circuit::connect."); 00124 00125 // Create 2-element port array for adding to connection stack. 00126 p.set(1, port1); 00127 p.set(2, port2); 00128 00129 // Add 2-element port array to the connection stack. 00130 constack.push(p); 00131 00132 // Add the devices to the device set. The set makes sure they are only added once. 00133 devset.add(&dev1); 00134 devset.add(&dev2); 00135 } 00136 00137 00138 int circuit::add_port(nport & dev, int index) 00139 { 00140 // Make sure build_tree gets called to include this connection in the tree. 00141 tree_is_built = false; 00142 00143 // Make sure port index is valid. If not, exit. 00144 if(dev.size() == 0) 00145 error::fatal("Can't add an nport which doesn't know its size in circuit."); 00146 if(dev.mode() != Index_1) 00147 error::fatal("Can only add nports with mode()==Index_1 in circuit."); 00148 if((index < 1) || (index > dev.size())) 00149 error::fatal("Illegal port index at circuit::add_port."); 00150 00151 port p(dev.id, index); 00152 00153 // Make sure port isn't used in connection list. 00154 if(constack.isPresent(p)) 00155 error::fatal("Port is already used in connection list at circuit::add_port."); 00156 00157 // Make sure port isn't already in label list. 00158 if(labels.isPresent(p)) 00159 error::fatal("Port is already used in label list at circuit::add_port."); 00160 00161 devset.add(&dev); 00162 return(labels.add(p)); 00163 } 00164 00165 00166 void circuit::build_tree() 00167 { 00168 nportSet devset_copy(devset); 00169 portStack constack_copy(constack); 00170 tmpList tmp_devs; 00171 nport *dev1; 00172 nport *dev2; 00173 int index1; 00174 int index2; 00175 nport *tmp1; 00176 nport *tmp2; 00177 connection *tmp3; 00178 00179 portArray p; 00180 00181 // Make sure the stack of temporary connections is empty. 00182 while(!del_stack.empty()) 00183 { 00184 delete del_stack.top(); 00185 del_stack.pop(); 00186 } 00187 00188 // Pop pairs of ports off connection stack until everything is connected. 00189 while(!constack_copy.isEmpty()) 00190 { 00191 // Get a pair of ports to connect 00192 p = constack_copy.pop(); 00193 00194 // Get the first device 00195 dev1 = devset_copy.pop(p.get(1).id); 00196 if(dev1 == 0) // Keep looking. 00197 { 00198 dev1 = tmp_devs.pop(p.get(1)); 00199 if(dev1 == 0) 00200 error::fatal("Device not found in circuit::build_tree."); 00201 } 00202 index1 = dev1->get_port(p.get(1)); 00203 00204 00205 // Get the second device 00206 dev2 = devset_copy.pop(p.get(2).id); 00207 if(dev2 == 0) // Keep looking. 00208 { 00209 dev2 = tmp_devs.pop(p.get(2)); 00210 } 00211 00212 // Perform the connection 00213 if(dev2 == 0) // Intra-connection 00214 { 00215 index2 = dev1->get_port(p.get(2)); 00216 tmp1 = new connection(*dev1, index1, index2); 00217 del_stack.push((connection *)tmp1); 00218 } 00219 else // Inter-connection 00220 { 00221 index2 = dev2->get_port(p.get(2)); 00222 tmp1 = new connection(*dev1, index1, *dev2, index2); 00223 del_stack.push((connection *)tmp1); 00224 } 00225 00226 // Stick the temporary device on the temporary device list. 00227 tmp_devs.add((connection *)tmp1); 00228 } 00229 00230 // Now look for unconnected devices which are block-diagonal components. 00231 // Connect them in pairs. 00232 while(devset_copy.len() > 1) 00233 { 00234 // they must be added using connection, since circuit will delete them 00235 tmp1 = devset_copy.pop(); 00236 tmp2 = devset_copy.pop(); 00237 tmp3 = new connection(*tmp1, *tmp2); 00238 del_stack.push(tmp3); 00239 tmp_devs.add(tmp3); 00240 } 00241 00242 // There could still be a device left. If so, get it. We can tell 00243 // we have one later if tmp1 is non-zero. 00244 tmp1 = NULL; 00245 if(devset_copy.len() > 0) 00246 { 00247 tmp1 = devset_copy.pop(); 00248 } 00249 00250 // By now, if there are any devices left in devset_copy, I've made a mistake. 00251 if(devset_copy.len() > 0) 00252 { 00253 error::fatal("Extra devices left on devset_copy in circuit::build_tree!"); 00254 } 00255 00256 // Make sure tmp1 points to a device before continuing. 00257 if(tmp1 == NULL) 00258 { 00259 if(tmp_devs.len() > 0) 00260 tmp1 = tmp_devs.pop(); 00261 else 00262 error::fatal("No devices left after making connections in circuit::build_tree!"); 00263 } 00264 00265 // Connect remaining devices from tmp_devs list into block-diagonal device. 00266 while(tmp_devs.len() > 0) 00267 { 00268 tmp2 = tmp_devs.pop(); 00269 tmp3 = new connection(*tmp1, *tmp2); 00270 del_stack.push(tmp3); 00271 00272 tmp1 = tmp3; 00273 } 00274 tree_base = tmp1; 00275 00276 tree_is_built = true; 00277 } 00278 00279 00280 //************************************************************** 00281 // calculating the circuit response 00282 00283 00284 const nport::data_info & circuit::get_data_info() 00285 { 00286 if(!tree_is_built) build_tree(); 00287 00288 00289 // save the current device::T and set to local Temp 00290 parameter old_T(device::T); 00291 device::T = Temp; // if Temp shadows T, this does nothing 00292 00293 // get the info and adjust results based on temperature 00294 info = tree_base->get_data_info(); 00295 if(info.noise && Temp != old_T) info.active = true; 00296 00297 // Restore device::T and return info 00298 device::T = old_T; 00299 return info; 00300 } 00301 00302 00303 void circuit::calc(bool noise) 00304 { 00305 if(!tree_is_built) build_tree(); 00306 00307 // Verify that the number of ports left equals the size of the labels vector. 00308 if(tree_base->size() != labels.len()) 00309 error::fatal("circuit::recalc(): Number of ports left after connecting circuit does" 00310 " not equal the number of ports specified with circuit::add_port."); 00311 00312 // save the current device::T and set to local Temp 00313 parameter old_T(device::T); 00314 device::T = Temp; // if Temp shadows T, this does nothing 00315 00316 // Get the unsorted data. What function we call to get the data 00317 // depends on whether or not we need tree_base to calculate the noise. 00318 const sdata& unsorted = (noise) ? tree_base->get_data() : tree_base->get_data_S(); 00319 data.resize(unsorted.size()); 00320 00321 // sort the values into data, using the specified port assignments 00322 int i,j; 00323 int index1; 00324 int index2; 00325 for(i=1; i<=data.size(); i++) 00326 { 00327 index1 = tree_base->get_port(labels.get(i)); 00328 for(j=1; j<=data.size(); j++) 00329 { 00330 index2 = tree_base->get_port(labels.get(j)); 00331 data.S[i][j] = unsorted.S.read(index1, index2); 00332 if(noise) data.C[i][j] = unsorted.C.read(index1, index2); 00333 } 00334 data.B[i] = unsorted.B.read(index1); 00335 } 00336 00337 // now adjust normalizing impedance, if necessary: 00338 data.set_znorm(unsorted.get_znorm()); 00339 data.change_norm(device::Z0); 00340 00341 // Restore device::T 00342 device::T = old_T; 00343 } 00344 00345 00346 //************************************************************** 00347 00348 cascade::cascade() : data_ptr_nport(), Temp(&T), last(0) 00349 { 00350 data.resize(2); 00351 data.S[1][2] = data.S[2][1] = 1.0; // the branch equiv. 00352 data_ptr = &data; 00353 info.source = info.noise = info.active = false; // for the branch equiv. 00354 } 00355 00356 00357 void cascade::recalc() 00358 { 00359 if (last) { 00360 data.resize(last->size()); 00361 c.Temp = Temp; 00362 data_ptr = &c.get_data(); 00363 } 00364 } 00365 00366 00367 void cascade::recalc_S() 00368 { 00369 if (last) { 00370 data.resize(last->size()); 00371 c.Temp = Temp; 00372 data_ptr = &c.get_data_S(); 00373 } 00374 } 00375 00376 00377 const nport::data_info & cascade::get_data_info() 00378 { 00379 if (last) { 00380 c.Temp = Temp; 00381 return c.get_data_info(); 00382 } 00383 else 00384 return info; 00385 } 00386 00387 00388 cascade & cascade::add(nport & n) 00389 { 00390 if (last) { 00391 // not the first device added 00392 if (last->size() == 1) 00393 error::fatal("Can't add to a 1-port cascade."); 00394 00395 switch (n.size()) { 00396 00397 case 1: { 00398 c.pop_port(); 00399 c.connect(*last, 2, n, 1); 00400 last = &n; 00401 break; 00402 } 00403 00404 case 2: { 00405 c.pop_port(); 00406 c.connect(*last, 2, n, 1); 00407 c.add_port(n, 2); 00408 last = &n; 00409 break; 00410 } 00411 00412 default: { 00413 // improper size for n 00414 error::fatal("Device added to cascade must have 1 or 2 ports"); 00415 break; 00416 } 00417 00418 } //switch 00419 00420 } 00421 else { 00422 // first device added 00423 00424 switch (n.size()) { 00425 00426 case 1: { 00427 c.add_port(n, 1); 00428 last = &n; 00429 break; 00430 } 00431 00432 case 2: { 00433 c.add_port(n, 1); 00434 c.add_port(n, 2); 00435 last = &n; 00436 break; 00437 } 00438 00439 default: { 00440 // improper size for n 00441 error::fatal("Device added to cascade must have 1 or 2 ports"); 00442 break; 00443 } 00444 00445 } //switch 00446 00447 } 00448 00449 return *this; 00450 } 00451 00452 00453 00454
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7