File indexing completed on 2024-04-28 05:43:15
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 by David Saxton * 0003 * david@bluehaze.org * 0004 * * 0005 * This program is free software; you can redistribute it and/or modify * 0006 * it under the terms of the GNU General Public License as published by * 0007 * the Free Software Foundation; either version 2 of the License, or * 0008 * (at your option) any later version. * 0009 ***************************************************************************/ 0010 0011 #include "circuit.h" 0012 #include "circuitdocument.h" 0013 #include "element.h" 0014 #include "elementset.h" 0015 #include "logic.h" 0016 #include "nonlinear.h" 0017 #include "pin.h" 0018 #include "reactive.h" 0019 #include "wire.h" 0020 0021 //#include <vector> 0022 #include <cmath> 0023 #include <map> 0024 0025 typedef std::multimap<int, PinList> PinListMap; 0026 0027 // BEGIN class Circuit 0028 Circuit::Circuit() 0029 { 0030 m_bCanAddChanged = true; 0031 m_pNextChanged[0] = m_pNextChanged[1] = nullptr; 0032 m_logicOutCount = 0; 0033 m_bCanCache = false; 0034 m_pLogicOut = nullptr; 0035 m_elementSet = new ElementSet(this, 0, 0); // why do we do this? 0036 m_cnodeCount = m_branchCount = -1; 0037 m_prepNLCount = 0; 0038 m_pLogicCacheBase = new LogicCacheNode; 0039 } 0040 0041 Circuit::~Circuit() 0042 { 0043 delete m_elementSet; 0044 delete m_pLogicCacheBase; 0045 delete[] m_pLogicOut; 0046 } 0047 0048 void Circuit::addPin(Pin *node) 0049 { 0050 if (m_pinList.contains(node)) 0051 return; 0052 m_pinList.append(node); 0053 } 0054 0055 void Circuit::addElement(Element *element) 0056 { 0057 if (m_elementList.contains(element)) 0058 return; 0059 m_elementList.append(element); 0060 } 0061 0062 bool Circuit::contains(Pin *node) 0063 { 0064 return m_pinList.contains(node); 0065 } 0066 0067 // static function 0068 int Circuit::identifyGround(PinList nodeList, int *highest) 0069 { 0070 // What this function does: 0071 // We are given a list of pins. First, we divide them into groups of pins 0072 // that are directly connected to each other (e.g. through wires or 0073 // switches). Then, each group of connected pins is looked at to find the 0074 // pin with the highest "ground priority", and this is taken to be 0075 // the priority of the group. The highest ground priority from all the 0076 // groups is recorded. If the highest ground priority found is the maximum, 0077 // then all the pins in groups with this priority are marked as ground 0078 // (their eq-id is set to -1). Otherwise, the first group of pins with the 0079 // highest ground priority found is marked as ground, and all others are 0080 // marked as non ground (their eq-id is set to 0). 0081 0082 int temp_highest; 0083 if (!highest) 0084 highest = &temp_highest; 0085 0086 // Now to give all the Pins ids 0087 PinListMap eqs; 0088 while (!nodeList.isEmpty()) { 0089 PinList associated; 0090 PinList nodes; 0091 Pin *node = *nodeList.begin(); 0092 recursivePinAdd(node, &nodeList, &associated, &nodes); 0093 if (nodes.size() > 0) { 0094 eqs.insert(std::make_pair(associated.size(), nodes)); 0095 } 0096 } 0097 0098 // Now, we want to look through the associated Pins, 0099 // to find the ones with the highest "Ground Priority". Anything with a lower 0100 // priority than Pin::gt_never will not be considered 0101 *highest = Pin::gt_never; // The highest priority found so far 0102 int numGround = 0; // The number of node groups found with that priority 0103 const PinListMap::iterator eqsEnd = eqs.end(); 0104 for (PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it) { 0105 int highPri = Pin::gt_never; // The highest priority found in these group of nodes 0106 const PinList::iterator send = it->second.end(); 0107 for (PinList::iterator sit = it->second.begin(); sit != send; ++sit) { 0108 if ((*sit)->groundType() < highPri) 0109 highPri = (*sit)->groundType(); 0110 } 0111 0112 if (highPri == *highest) 0113 numGround++; 0114 0115 else if (highPri < *highest) { 0116 numGround = 1; 0117 *highest = highPri; 0118 } 0119 } 0120 0121 if (*highest == Pin::gt_never) { 0122 (*highest)--; 0123 numGround = 0; 0124 } 0125 // If there are no Always Ground nodes, then we only want to set one of the nodes as ground 0126 else if (*highest > Pin::gt_always) 0127 numGround = 1; 0128 0129 // Now, we can give the nodes their cnode ids, or tell them they are ground 0130 bool foundGround = false; // This is only used when we don't have a Always ground node 0131 for (PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it) { 0132 bool ground = false; 0133 const PinList::iterator send = it->second.end(); 0134 for (PinList::iterator sit = it->second.begin(); sit != send; ++sit) { 0135 ground |= (*sit)->groundType() <= (*highest); 0136 } 0137 if (ground && (!foundGround || *highest == Pin::gt_always)) { 0138 for (PinList::iterator sit = it->second.begin(); sit != send; ++sit) { 0139 (*sit)->setEqId(-1); 0140 } 0141 foundGround = true; 0142 } else { 0143 for (PinList::iterator sit = it->second.begin(); sit != send; ++sit) { 0144 (*sit)->setEqId(0); 0145 } 0146 } 0147 } 0148 0149 return numGround; 0150 } 0151 0152 void Circuit::init() 0153 { 0154 m_branchCount = 0; 0155 0156 const ElementList::iterator listEnd = m_elementList.end(); 0157 for (ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) { 0158 m_branchCount += (*it)->numCBranches(); 0159 } 0160 0161 // Now to give all the Pins ids 0162 int groundCount = 0; 0163 PinListMap eqs; 0164 PinList unassignedNodes = m_pinList; 0165 while (!unassignedNodes.isEmpty()) { 0166 PinList associated; 0167 PinList nodes; 0168 Pin *node = *unassignedNodes.begin(); 0169 if (recursivePinAdd(node, &unassignedNodes, &associated, &nodes)) { 0170 groundCount++; 0171 } 0172 if (nodes.size() > 0) { 0173 eqs.insert(std::make_pair(associated.size(), nodes)); 0174 } 0175 } 0176 0177 m_cnodeCount = eqs.size() - groundCount; 0178 0179 delete m_pLogicCacheBase; 0180 m_pLogicCacheBase = nullptr; 0181 0182 delete m_elementSet; 0183 m_elementSet = new ElementSet(this, m_cnodeCount, m_branchCount); 0184 0185 // Now, we can give the nodes their cnode ids, or tell them they are ground 0186 QuickVector *x = m_elementSet->x(); 0187 int i = 0; 0188 const PinListMap::iterator eqsEnd = eqs.end(); 0189 for (PinListMap::iterator it = eqs.begin(); it != eqsEnd; ++it) { 0190 bool foundGround = false; 0191 0192 const PinList::iterator sEnd = it->second.end(); 0193 for (PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit) 0194 foundGround |= (*sit)->eqId() == -1; 0195 0196 if (foundGround) 0197 continue; 0198 0199 bool foundEnergyStoragePin = false; 0200 0201 for (PinList::iterator sit = it->second.begin(); sit != sEnd; ++sit) { 0202 (*sit)->setEqId(i); 0203 0204 bool energyStorage = false; 0205 const ElementList elements = (*sit)->elements(); 0206 ElementList::const_iterator elementsEnd = elements.end(); 0207 for (ElementList::const_iterator it = elements.begin(); it != elementsEnd; ++it) { 0208 if (!*it) 0209 continue; 0210 0211 if (((*it)->type() == Element::Element_Capacitance) || ((*it)->type() == Element::Element_Inductance)) { 0212 energyStorage = true; 0213 break; 0214 } 0215 } 0216 0217 // A pin attached to an energy storage pin overrides one that doesn't. 0218 // If the two pins have equal status with in this regard, we pick the 0219 // one with the highest absolute voltage on it. 0220 0221 if (foundEnergyStoragePin && !energyStorage) 0222 continue; 0223 0224 double v = (*sit)->voltage(); 0225 0226 if (energyStorage && !foundEnergyStoragePin) { 0227 foundEnergyStoragePin = true; 0228 (*x)[i] = v; 0229 continue; 0230 } 0231 0232 if (std::abs(v) > std::abs((*x)[i])) 0233 (*x)[i] = v; 0234 } 0235 i++; 0236 } 0237 0238 // And add the elements to the elementSet 0239 for (ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) { 0240 // We don't want the element to prematurely try to do anything, 0241 // as it doesn't know its actual cnode ids yet 0242 (*it)->setCNodes(); 0243 (*it)->setCBranches(); 0244 m_elementSet->addElement(*it); 0245 } 0246 // And give the branch ids to the elements 0247 i = 0; 0248 for (ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) { 0249 switch ((*it)->numCBranches()) { 0250 case 0: 0251 break; 0252 case 1: 0253 (*it)->setCBranches(i); 0254 i += 1; 0255 break; 0256 case 2: 0257 (*it)->setCBranches(i, i + 1); 0258 i += 2; 0259 break; 0260 case 3: 0261 (*it)->setCBranches(i, i + 1, i + 2); 0262 i += 3; 0263 break; 0264 default: 0265 // What the?! 0266 break; 0267 } 0268 } 0269 } 0270 0271 void Circuit::initCache() 0272 { 0273 m_elementSet->updateInfo(); 0274 0275 m_bCanCache = true; 0276 m_logicOutCount = 0; 0277 0278 delete[] m_pLogicOut; 0279 m_pLogicOut = nullptr; 0280 0281 delete m_pLogicCacheBase; 0282 m_pLogicCacheBase = nullptr; 0283 0284 const ElementList::iterator end = m_elementList.end(); 0285 for (ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it) { 0286 switch ((*it)->type()) { 0287 case Element::Element_BJT: 0288 case Element::Element_CCCS: 0289 case Element::Element_CCVS: 0290 case Element::Element_CurrentSource: 0291 case Element::Element_Diode: 0292 case Element::Element_JFET: 0293 case Element::Element_LogicIn: 0294 case Element::Element_MOSFET: 0295 case Element::Element_OpAmp: 0296 case Element::Element_Resistance: 0297 case Element::Element_VCCS: 0298 case Element::Element_VCVS: 0299 case Element::Element_VoltagePoint: 0300 case Element::Element_VoltageSource: { 0301 break; 0302 } 0303 0304 case Element::Element_LogicOut: { 0305 m_logicOutCount++; 0306 break; 0307 } 0308 0309 case Element::Element_CurrentSignal: 0310 case Element::Element_VoltageSignal: 0311 case Element::Element_Capacitance: 0312 case Element::Element_Inductance: { 0313 m_bCanCache = false; 0314 break; 0315 } 0316 } 0317 } 0318 0319 if (!m_bCanCache) 0320 return; 0321 0322 m_pLogicOut = new LogicOut *[m_logicOutCount]; 0323 unsigned i = 0; 0324 for (ElementList::iterator it = m_elementList.begin(); it != end && m_bCanCache; ++it) { 0325 if ((*it)->type() == Element::Element_LogicOut) 0326 m_pLogicOut[i++] = static_cast<LogicOut *>(*it); 0327 } 0328 0329 m_pLogicCacheBase = new LogicCacheNode; 0330 } 0331 0332 void Circuit::setCacheInvalidated() 0333 { 0334 if (m_pLogicCacheBase) { 0335 delete m_pLogicCacheBase->high; 0336 m_pLogicCacheBase->high = nullptr; 0337 0338 delete m_pLogicCacheBase->low; 0339 m_pLogicCacheBase->low = nullptr; 0340 0341 delete m_pLogicCacheBase->data; 0342 m_pLogicCacheBase->data = nullptr; 0343 } 0344 } 0345 0346 void Circuit::cacheAndUpdate() 0347 { 0348 LogicCacheNode *node = m_pLogicCacheBase; 0349 for (unsigned i = 0; i < m_logicOutCount; i++) { 0350 if (m_pLogicOut[i]->outputState()) { 0351 if (!node->high) 0352 node->high = new LogicCacheNode; 0353 0354 node = node->high; 0355 } else { 0356 if (!node->low) 0357 node->low = new LogicCacheNode; 0358 0359 node = node->low; 0360 } 0361 } 0362 0363 if (node->data) { 0364 (*m_elementSet->x()) = *node->data; 0365 m_elementSet->updateInfo(); 0366 return; 0367 } 0368 0369 if (m_elementSet->containsNonLinear()) 0370 m_elementSet->doNonLinear(150, 1e-10, 1e-13); 0371 else 0372 m_elementSet->doLinear(true); 0373 0374 if (node->data) { 0375 node->data = m_elementSet->x(); 0376 } else { 0377 node->data = new QuickVector(m_elementSet->x()); 0378 } 0379 0380 // node->data = new Vector( m_elementSet->x()->size() ); 0381 // *node->data = *m_elementSet->x(); 0382 } 0383 0384 void Circuit::createMatrixMap() 0385 { 0386 m_elementSet->createMatrixMap(); 0387 } 0388 0389 bool Circuit::recursivePinAdd(Pin *node, PinList *unassignedNodes, PinList *associated, PinList *nodes) 0390 { 0391 if (!unassignedNodes->contains(node)) 0392 return false; 0393 unassignedNodes->removeAll(node); 0394 0395 bool foundGround = node->eqId() == -1; 0396 0397 const PinList circuitDependentPins = node->circuitDependentPins(); 0398 const PinList::const_iterator dEnd = circuitDependentPins.end(); 0399 for (PinList::const_iterator it = circuitDependentPins.begin(); it != dEnd; ++it) { 0400 if (!associated->contains(*it)) 0401 associated->append(*it); 0402 } 0403 0404 nodes->append(node); 0405 0406 const PinList localConnectedPins = node->localConnectedPins(); 0407 const PinList::const_iterator end = localConnectedPins.end(); 0408 for (PinList::const_iterator it = localConnectedPins.begin(); it != end; ++it) 0409 foundGround |= recursivePinAdd(*it, unassignedNodes, associated, nodes); 0410 0411 return foundGround; 0412 } 0413 0414 void Circuit::doNonLogic() 0415 { 0416 if (!m_elementSet || m_cnodeCount + m_branchCount <= 0) 0417 return; 0418 0419 if (m_bCanCache) { 0420 if (!m_elementSet->b()->isChanged() && !m_elementSet->matrix()->isChanged()) 0421 return; 0422 cacheAndUpdate(); 0423 updateNodalVoltages(); 0424 m_elementSet->b()->setUnchanged(); 0425 return; 0426 } 0427 0428 stepReactive(); 0429 if (m_elementSet->containsNonLinear()) { 0430 m_elementSet->doNonLinear(10, 1e-9, 1e-12); 0431 updateNodalVoltages(); 0432 } else { 0433 if (m_elementSet->doLinear(true)) 0434 updateNodalVoltages(); 0435 } 0436 } 0437 0438 void Circuit::stepReactive() 0439 { 0440 ElementList::iterator listEnd = m_elementList.end(); 0441 for (ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) { 0442 Element *const e = *it; 0443 if (e && e->isReactive()) 0444 (static_cast<Reactive *>(e))->time_step(); 0445 } 0446 } 0447 0448 void Circuit::updateNodalVoltages() 0449 { 0450 CNode **_cnodes = m_elementSet->cnodes(); 0451 0452 const PinList::iterator endIt = m_pinList.end(); 0453 for (PinList::iterator it = m_pinList.begin(); it != endIt; ++it) { 0454 Pin *const node = *it; 0455 int i = node->eqId(); 0456 if (i == -1) 0457 node->setVoltage(0.); 0458 else { 0459 const double v = _cnodes[i]->v; 0460 node->setVoltage(std::isfinite(v) ? v : 0.); 0461 } 0462 } 0463 } 0464 0465 void Circuit::updateCurrents() 0466 { 0467 ElementList::iterator listEnd = m_elementList.end(); 0468 for (ElementList::iterator it = m_elementList.begin(); it != listEnd; ++it) { 0469 (*it)->updateCurrents(); 0470 } 0471 } 0472 0473 void Circuit::displayEquations() 0474 { 0475 m_elementSet->displayEquations(); 0476 } 0477 // END class Circuit 0478 0479 // BEGIN class LogicCacheNode 0480 0481 LogicCacheNode::LogicCacheNode() 0482 { 0483 low = nullptr; 0484 high = nullptr; 0485 data = nullptr; 0486 } 0487 0488 LogicCacheNode::~LogicCacheNode() 0489 { 0490 delete low; 0491 delete high; 0492 if (data) 0493 delete data; 0494 } 0495 // END class LogicCacheNode