00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <vector>
00012 #include "circuit.h"
00013 #include "circuitdocument.h"
00014 #include "element.h"
00015 #include "elementset.h"
00016 #include "logic.h"
00017 #include "nonlinear.h"
00018 #include "pin.h"
00019 #include "reactive.h"
00020 #include "wire.h"
00021
00022 #include <kdebug.h>
00023 #include <cassert>
00024 #include <cmath>
00025 #include <map>
00026
00027 typedef std::multimap<int, PinList> PinListMap;
00028
00029
00030 Circuit::Circuit()
00031 {
00032 m_bCanAddChanged = true;
00033 m_pNextChanged[0] = m_pNextChanged[1] = 0;
00034 m_logicOutCount = 0;
00035 m_bCanCache = false;
00036 m_pLogicOut = 0;
00037 m_elementSet = new ElementSet( this, 0, 0 );
00038 m_cnodeCount = m_branchCount = -1;
00039 m_prepNLCount = 0;
00040 m_pLogicCacheBase = new LogicCacheNode;
00041 }
00042
00043 Circuit::~Circuit()
00044 {
00045 delete m_elementSet;
00046 delete m_pLogicCacheBase;
00047 delete[] m_pLogicOut;
00048 }
00049
00050
00051 void Circuit::addPin( Pin *node )
00052 {
00053 if ( m_pinList.contains(node) ) return;
00054 m_pinList.append(node);
00055 }
00056
00057 void Circuit::addElement( Element *element )
00058 {
00059 if ( m_elementList.contains(element) ) return;
00060 m_elementList.append(element);
00061 }
00062
00063 bool Circuit::contains( Pin *node )
00064 {
00065 return m_pinList.contains(node);
00066 }
00067
00068
00069 int Circuit::identifyGround( PinList nodeList, int *highest )
00070 {
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083 int temp_highest;
00084 if (!highest) highest = &temp_highest;
00085
00086
00087 PinListMap eqs;
00088 while ( !nodeList.isEmpty() )
00089 {
00090 PinList associated;
00091 PinList nodes;
00092 Pin *node = *nodeList.begin();
00093 recursivePinAdd( node, &nodeList, &associated, &nodes );
00094 if ( nodes.size() > 0 )
00095 {
00096 eqs.insert( std::make_pair( associated.size(), nodes ) );
00097 }
00098 }
00099
00100
00101
00102
00103 *highest = Pin::gt_never;
00104 int numGround = 0;
00105 const PinListMap::iterator eqsEnd = eqs.end();
00106 for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it )
00107 {
00108 int highPri = Pin::gt_never;
00109 const PinList::iterator send = it->second.end();
00110 for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit )
00111 {
00112 if ( (*sit)->groundType() < highPri )
00113 highPri = (*sit)->groundType();
00114 }
00115
00116 if(highPri == *highest ) numGround++;
00117 else if ( highPri < *highest ) {
00118 numGround = 1;
00119 *highest = highPri;
00120 }
00121 }
00122
00123 if ( *highest == Pin::gt_never ) {
00124 (*highest)--;
00125 numGround=0;
00126 }
00127
00128 else if ( *highest > Pin::gt_always ) numGround = 1;
00129
00130
00131 bool foundGround = false;
00132 for ( PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it )
00133 {
00134 bool ground = false;
00135 const PinList::iterator send = it->second.end();
00136 for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit )
00137 {
00138 ground |= (*sit)->groundType() <= (*highest);
00139 }
00140
00141 if ( ground && (!foundGround || *highest == Pin::gt_always ) )
00142 {
00143 for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit )
00144 {
00145 (*sit)->setEqId(-1);
00146 }
00147 foundGround = true;
00148 } else {
00149 for ( PinList::iterator sit = it->second.begin(); sit != send; ++sit )
00150 {
00151 (*sit)->setEqId(0);
00152 }
00153 }
00154 }
00155
00156 return numGround;
00157 }
00158
00159 void Circuit::init()
00160 {
00161 m_branchCount = 0;
00162
00163 const ElementList::iterator listEnd = m_elementList.end();
00164 for(ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) {
00165 m_branchCount += (*it)->numCBranches();
00166 }
00167
00168
00169 int groundCount = 0;
00170 PinListMap eqs;
00171 PinList unassignedNodes = m_pinList;
00172 while(!unassignedNodes.isEmpty()) {
00173 PinList associated;
00174 PinList nodes;
00175 Pin *node = *unassignedNodes.begin();
00176 if(recursivePinAdd(node, &unassignedNodes, &associated, &nodes)) {
00177 groundCount++;
00178 }
00179
00180 if(nodes.size() > 0) {
00181 eqs.insert( std::make_pair( associated.size(), nodes ) );
00182 }
00183 }
00184
00185 m_cnodeCount = eqs.size() - groundCount;
00186
00187 delete m_pLogicCacheBase;
00188 m_pLogicCacheBase = 0;
00189
00190 delete m_elementSet;
00191 m_elementSet = new ElementSet(this, m_cnodeCount, m_branchCount);
00192
00193
00194 QuickVector *x = m_elementSet->x();
00195 int i=0;
00196 const PinListMap::iterator eqsEnd = eqs.end();
00197 for(PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it) {
00198 bool foundGround = false;
00199
00200 const PinList::iterator sEnd = it->second.end();
00201 for ( PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit )
00202 foundGround |= (*sit)->eqId() == -1;
00203
00204 if(foundGround) continue;
00205
00206 bool foundEnergyStoragePin = false;
00207
00208 for(PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit) {
00209 (*sit)->setEqId(i);
00210 bool energyStorage = false;
00211 const ElementList elements = (*sit)->elements();
00212 ElementList::const_iterator elementsEnd = elements.end();
00213 for ( ElementList::const_iterator it = elements.begin(); it != elementsEnd; ++it ) {
00214 if(!*it) continue;
00215
00216 if(((*it)->type() == Element::Element_Capacitance) ||
00217 ((*it)->type() == Element::Element_Inductance)) {
00218 energyStorage = true;
00219 break;
00220 }
00221 }
00222
00223
00224
00225
00226
00227 if(foundEnergyStoragePin && !energyStorage) continue;
00228
00229 double v = (*sit)->voltage();
00230
00231 if(energyStorage && !foundEnergyStoragePin) {
00232 foundEnergyStoragePin = true;
00233 (*x)[i] = v;
00234 continue;
00235 }
00236
00237 if(std::abs(v) > std::abs((*x)[i])) (*x)[i] = v;
00238 }
00239 i++;
00240 }
00241
00242
00243 for ( ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it )
00244 {
00245
00246
00247 (*it)->setCNodes();
00248 (*it)->setCBranches();
00249 m_elementSet->addElement(*it);
00250 }
00251
00252
00253 i=0;
00254 for(ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) {
00255 switch((*it)->numCBranches()) {
00256 case 0:
00257 break;
00258 case 1:
00259 (*it)->setCBranches(i);
00260 i += 1;
00261 break;
00262 case 2:
00263 (*it)->setCBranches(i, i+1);
00264 i += 2;
00265 break;
00266 case 3:
00267 (*it)->setCBranches(i, i+1, i+2);
00268 i += 3;
00269 break;
00270 default:
00271
00272 break;
00273 }
00274 }
00275 }
00276
00277 void Circuit::initCache()
00278 {
00279 m_elementSet->updateInfo();
00280
00281 m_bCanCache = true;
00282 m_logicOutCount = 0;
00283
00284 delete[] m_pLogicOut;
00285 m_pLogicOut = 0;
00286
00287 delete m_pLogicCacheBase;
00288 m_pLogicCacheBase = 0;
00289
00290 const ElementList::iterator end = m_elementList.end();
00291 for(ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it) {
00292 switch((*it)->type()) {
00293 case Element::Element_BJT:
00294 case Element::Element_CCCS:
00295 case Element::Element_CCVS:
00296 case Element::Element_CurrentSource:
00297 case Element::Element_Diode:
00298 case Element::Element_LogicIn:
00299 case Element::Element_OpAmp:
00300 case Element::Element_Resistance:
00301 case Element::Element_VCCS:
00302 case Element::Element_VCVS:
00303 case Element::Element_VoltagePoint:
00304 case Element::Element_VoltageSource:
00305 break;
00306 case Element::Element_LogicOut:
00307 m_logicOutCount++;
00308 break;
00309 case Element::Element_CurrentSignal:
00310 case Element::Element_VoltageSignal:
00311 case Element::Element_Capacitance:
00312 case Element::Element_Inductance:
00313 m_bCanCache = false;
00314 break;
00315 }
00316 }
00317
00318 if(!m_bCanCache) return;
00319
00320 m_pLogicOut = new LogicOut*[m_logicOutCount];
00321 unsigned i = 0;
00322 for(ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it) {
00323 if((*it)->type() == Element::Element_LogicOut)
00324 m_pLogicOut[i++] = static_cast<LogicOut*>(*it);
00325 }
00326
00327 m_pLogicCacheBase = new LogicCacheNode;
00328 }
00329
00330 void Circuit::setCacheInvalidated()
00331 {
00332 if (m_pLogicCacheBase) {
00333 delete m_pLogicCacheBase->high;
00334 m_pLogicCacheBase->high = 0;
00335
00336 delete m_pLogicCacheBase->low;
00337 m_pLogicCacheBase->low = 0;
00338
00339 delete m_pLogicCacheBase->data;
00340 m_pLogicCacheBase->data = 0;
00341 }
00342 }
00343
00344 void Circuit::cacheAndUpdate()
00345 {
00346 LogicCacheNode *node = m_pLogicCacheBase;
00347 for(unsigned i = 0; i < m_logicOutCount; i++) {
00348 if(m_pLogicOut[i]->outputState()) {
00349 if (!node->high)
00350 node->high = new LogicCacheNode;
00351 node = node->high;
00352 } else {
00353 if (!node->low)
00354 node->low = new LogicCacheNode;
00355 node = node->low;
00356 }
00357 }
00358
00359 if(node->data ) {
00360 m_elementSet->set_x(new QuickVector(node->data));
00361 m_elementSet->updateInfo();
00362 return;
00363 }
00364
00365 if(m_elementSet->containsNonLinear())
00366 m_elementSet->doNonLinear(150, 1e-10, 1e-13);
00367 else m_elementSet->doLinear(true);
00368
00369 node->data = new QuickVector(m_elementSet->x());
00370 }
00371
00372 void Circuit::createMatrixMap()
00373 {
00374 m_elementSet->createMatrixMap();
00375 }
00376
00377 bool Circuit::recursivePinAdd( Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes )
00378 {
00379 if(!unassignedNodes->contains(node)) return false;
00380 unassignedNodes->remove(node);
00381
00382 bool foundGround = node->eqId() == -1;
00383
00384 const PinList circuitDependentPins = node->circuitDependentPins();
00385 const PinList::const_iterator dEnd = circuitDependentPins.end();
00386 for ( PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it ) {
00387 if(!associated->contains(*it))
00388 associated->append(*it);
00389 }
00390
00391 nodes->append(node);
00392
00393 const PinList localConnectedPins = node->localConnectedPins();
00394 const PinList::const_iterator end = localConnectedPins.end();
00395 for ( PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it )
00396 foundGround |= recursivePinAdd( *it, unassignedNodes, associated, nodes );
00397
00398 return foundGround;
00399 }
00400
00401
00402
00403 void Circuit::doNonLogic()
00404 {
00405 if(!m_elementSet || m_cnodeCount+m_branchCount <= 0) return;
00406
00407 if (m_bCanCache) {
00408 if ( !m_elementSet->b()->isChanged() && !m_elementSet->matrix()->isChanged() )
00409 return;
00410 cacheAndUpdate();
00411 updateNodalVoltages();
00412 m_elementSet->b()->setUnchanged();
00413 return;
00414 }
00415
00416 stepReactive();
00417 if ( m_elementSet->containsNonLinear() ) {
00418 m_elementSet->doNonLinear( 10, 1e-9, 1e-12 );
00419 updateNodalVoltages();
00420 } else {
00421 if ( m_elementSet->doLinear(true) )
00422 updateNodalVoltages();
00423 }
00424 }
00425
00426 void Circuit::stepReactive()
00427 {
00428 ElementList::iterator listEnd = m_elementList.end();
00429 for(ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) {
00430 Element *const e = *it;
00431 if ( e && e->isReactive() )
00432 (static_cast<Reactive*>(e))->time_step();
00433 }
00434 }
00435
00436 void Circuit::updateNodalVoltages()
00437 {
00438 const PinList::iterator endIt = m_pinList.end();
00439 for ( PinList::iterator it = m_pinList.begin(); it != endIt; ++it ) {
00440 Pin * const node = *it;
00441 int i = node->eqId();
00442
00443 if ( i == -1 ) node->setVoltage(0.);
00444 else {
00445 const double v = m_elementSet->cnodes(i)->v;
00446 node->setVoltage( std::isfinite(v)?v:0. );
00447 }
00448 }
00449 }
00450
00451 void Circuit::updateCurrents()
00452 {
00453 ElementList::iterator listEnd = m_elementList.end();
00454 double error = 0;
00455 for(ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it ) {
00456 (*it)->updateCurrents();
00457 error += (*it)->checkCurrents();
00458 }
00459
00460 if(error>1e-9) {
00461
00462
00463
00464
00465 kdError() << "currents don't sum, residual = " << error << endl;
00466 }
00467 }
00468
00469 void Circuit::displayEquations()
00470 {
00471 m_elementSet->displayEquations();
00472 }
00473
00474
00475
00476 LogicCacheNode::LogicCacheNode()
00477 {
00478 low = 0;
00479 high = 0;
00480 data = 0;
00481 }
00482
00483 LogicCacheNode::~LogicCacheNode()
00484 {
00485 delete low;
00486 delete high;
00487 delete data;
00488 }
00489
00490