File indexing completed on 2024-04-28 05:43:15
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2004 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 "elementset.h" 0012 #include "bjt.h" 0013 #include "circuit.h" 0014 #include "element.h" 0015 #include "logic.h" 0016 #include "matrix.h" 0017 #include "nonlinear.h" 0018 0019 #include <QDebug> 0020 0021 #include <cassert> 0022 #include <cmath> 0023 #include <iostream> 0024 0025 ElementSet::ElementSet(Circuit *circuit, const int n, const int m) 0026 : m_cb(m) 0027 , m_cn(n) 0028 , m_pCircuit(circuit) 0029 { 0030 int tmp = m_cn + m_cb; 0031 0032 p_logicIn = nullptr; 0033 0034 if (tmp) { 0035 p_A = new Matrix(m_cn, m_cb); 0036 p_b = new QuickVector(tmp); 0037 p_x = new QuickVector(tmp); 0038 } else { 0039 p_A = nullptr; 0040 p_x = p_b = nullptr; 0041 } 0042 0043 m_cnodes = new CNode *[m_cn]; 0044 for (uint i = 0; i < m_cn; i++) { 0045 m_cnodes[i] = new CNode(i); 0046 } 0047 0048 m_cbranches = new CBranch *[m_cb]; 0049 for (uint i = 0; i < m_cb; i++) { 0050 m_cbranches[i] = new CBranch(i); 0051 } 0052 0053 m_ground = new CNode(); 0054 m_ground->isGround = true; 0055 b_containsNonLinear = false; 0056 } 0057 0058 ElementSet::~ElementSet() 0059 { 0060 const ElementList::iterator end = m_elementList.end(); 0061 for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) { 0062 // Note: By calling setElementSet(nullptr), we might have deleted it (the Element will commit 0063 // suicide when both the ElementSet and Component to which it belongs have deleted 0064 // themselves). So be very careful it you plan to do anything with the (*it) pointer 0065 if (*it) 0066 (*it)->elementSetDeleted(); 0067 } 0068 0069 for (uint i = 0; i < m_cn; i++) 0070 delete m_cnodes[i]; 0071 for (uint i = 0; i < m_cb; i++) 0072 delete m_cbranches[i]; 0073 0074 delete[] m_cbranches; 0075 delete[] m_cnodes; 0076 delete[] p_logicIn; 0077 delete m_ground; 0078 if (p_A) 0079 delete p_A; 0080 if (p_b) 0081 delete p_b; 0082 if (p_x) 0083 delete p_x; 0084 } 0085 0086 void ElementSet::setCacheInvalidated() 0087 { 0088 m_pCircuit->setCacheInvalidated(); 0089 } 0090 0091 void ElementSet::addElement(Element *e) 0092 { 0093 if (!e || m_elementList.contains(e)) 0094 return; 0095 e->setElementSet(this); 0096 m_elementList.append(e); 0097 if (e->isNonLinear()) { 0098 b_containsNonLinear = true; 0099 m_cnonLinearList.append(static_cast<NonLinear *>(e)); 0100 } 0101 } 0102 0103 void ElementSet::createMatrixMap() 0104 { 0105 // mapping nolonger done, overly ambitious optimization... 0106 0107 // And do our logic as well... 0108 0109 m_clogic = 0; 0110 ElementList::iterator end = m_elementList.end(); 0111 for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) { 0112 if (dynamic_cast<LogicIn *>(*it)) 0113 m_clogic++; 0114 } 0115 0116 p_logicIn = new LogicIn *[m_clogic]; 0117 int i = 0; 0118 for (ElementList::iterator it = m_elementList.begin(); it != end; ++it) { 0119 if (LogicIn *in = dynamic_cast<LogicIn *>(*it)) 0120 p_logicIn[i++] = in; 0121 } 0122 } 0123 0124 void ElementSet::doNonLinear(int maxIterations, double maxErrorV, double maxErrorI) 0125 { 0126 QuickVector *p_x_prev = new QuickVector(p_x); 0127 0128 // And now tell the cnodes and cbranches about their new voltages & currents 0129 updateInfo(); 0130 0131 const NonLinearList::iterator end = m_cnonLinearList.end(); 0132 0133 int k = 0; 0134 do { 0135 // Tell the nonlinear elements to update its J, A and b from the newly calculated x 0136 for (NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it) 0137 (*it)->update_dc(); 0138 0139 *p_x = *p_b; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 0140 0141 p_A->performLU(); 0142 p_A->fbSub(p_x); 0143 updateInfo(); 0144 0145 // Now, check for convergence 0146 bool converged = true; 0147 for (unsigned i = 0; i < m_cn; ++i) { 0148 double diff = std::abs((*p_x_prev)[i] - (*p_x)[i]); 0149 if (diff > maxErrorI) { 0150 converged = false; 0151 break; 0152 } 0153 } 0154 if (converged) { 0155 for (unsigned i = m_cn; i < m_cn + m_cb; ++i) { 0156 double diff = std::abs((*p_x_prev)[i] - (*p_x)[i]); 0157 if (diff > maxErrorV) { 0158 converged = false; 0159 break; 0160 } 0161 } 0162 } 0163 0164 *p_x_prev = *p_x; // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 0165 0166 if (converged) 0167 break; 0168 } while (++k < maxIterations); 0169 0170 delete p_x_prev; 0171 } 0172 0173 bool ElementSet::doLinear(bool performLU) 0174 { 0175 if (b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU))) 0176 return false; 0177 0178 if (performLU) 0179 p_A->performLU(); 0180 0181 *p_x = *p_b; // <<< why does this code work, when I try it, I always get the default shallow copy. 0182 0183 p_A->fbSub(p_x); 0184 updateInfo(); 0185 p_b->setUnchanged(); 0186 0187 return true; 0188 } 0189 0190 void ElementSet::updateInfo() 0191 { 0192 for (uint i = 0; i < m_cn; i++) { 0193 const double v = (*p_x)[i]; 0194 if (std::isfinite(v)) { 0195 m_cnodes[i]->v = v; 0196 } else { 0197 (*p_x)[i] = 0.; 0198 m_cnodes[i]->v = 0.; 0199 } 0200 } 0201 0202 for (uint i = 0; i < m_cb; i++) { 0203 // NOTE: I've used lowercase and uppercase "I" here, so be careful! 0204 const double I = (*p_x)[i + m_cn]; 0205 if (std::isfinite(I)) { 0206 m_cbranches[i]->i = I; 0207 } else { 0208 (*p_x)[i + m_cn] = 0.; 0209 m_cbranches[i]->i = 0.; 0210 } 0211 } 0212 0213 // Tell logic to check themselves 0214 for (uint i = 0; i < m_clogic; ++i) { 0215 p_logicIn[i]->check(); 0216 } 0217 } 0218 0219 void ElementSet::displayEquations() 0220 { 0221 std::cout.setf(std::ios_base::fixed); 0222 std::cout.precision(5); 0223 std::cout.setf(std::ios_base::showpoint); 0224 std::cout << "A x = b :" << std::endl; 0225 for (uint i = 0; i < m_cn + m_cb; i++) { 0226 std::cout << "( "; 0227 for (uint j = 0; j < m_cn + m_cb; j++) { 0228 const double value = p_A->g(i, j); 0229 // if ( value > 0 ) cout <<"+"; 0230 // else if ( value == 0 ) cout <<" "; 0231 std::cout.width(10); 0232 std::cout << value << " "; 0233 } 0234 std::cout << ") ( " << (*p_x)[i] << " ) = ( "; 0235 std::cout << (*p_b)[i] << " )" << std::endl; 0236 } 0237 std::cout << "A_LU:" << std::endl; 0238 p_A->displayLU(); 0239 }