summaryrefslogtreecommitdiffstats
path: root/src/electronics/simulation/elementset.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/electronics/simulation/elementset.cpp')
-rw-r--r--src/electronics/simulation/elementset.cpp253
1 files changed, 253 insertions, 0 deletions
diff --git a/src/electronics/simulation/elementset.cpp b/src/electronics/simulation/elementset.cpp
new file mode 100644
index 0000000..25057c2
--- /dev/null
+++ b/src/electronics/simulation/elementset.cpp
@@ -0,0 +1,253 @@
+/***************************************************************************
+ * Copyright (C) 2003-2004 by David Saxton *
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ ***************************************************************************/
+
+#include "bjt.h"
+#include "circuit.h"
+#include "elementset.h"
+#include "element.h"
+#include "logic.h"
+#include "matrix.h"
+#include "nonlinear.h"
+#include "vec.h"
+
+#include <kdebug.h>
+
+#include <cmath>
+#include <iostream>
+#include <assert.h>
+
+ElementSet::ElementSet( Circuit * circuit, const int n, const int m )
+{
+ m_pCircuit = circuit;
+ m_cn = n;
+ m_cb = m;
+ p_logicIn = 0l;
+ p_A = new Matrix( m_cn, m_cb );
+ p_b = new Vector(m_cn+m_cb);
+ p_x = new Vector(m_cn+m_cb);
+ p_x_prev = new Vector(m_cn+m_cb);
+ m_cbranches = new CBranch*[m_cb];
+ m_cnodes = new CNode*[m_cn];
+ for ( uint i=0; i<m_cn; i++ )
+ {
+ m_cnodes[i] = new CNode();
+ m_cnodes[i]->set_n(i);
+ }
+ for ( uint i=0; i<m_cb; i++ )
+ {
+ m_cbranches[i] = new CBranch();
+ m_cbranches[i]->set_n(i);
+ }
+ m_ground = new CNode();
+ m_ground->isGround = true;
+ b_containsNonLinear = false;
+}
+
+ElementSet::~ElementSet()
+{
+ const ElementList::iterator end = m_elementList.end();
+ for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it )
+ {
+ // Note: By calling setElementSet(0l), we might have deleted it (the Element will commit
+ // suicide when both the the ElementSet and Component to which it belongs have deleted
+ // themselves). So be very careful it you plan to do anything with the (*it) pointer
+ if (*it) (*it)->elementSetDeleted();
+ }
+ for ( uint i=0; i<m_cn; i++ )
+ {
+ delete m_cnodes[i];
+ }
+ for ( uint i=0; i<m_cb; i++ )
+ {
+ delete m_cbranches[i];
+ }
+ delete[] m_cbranches;
+ delete[] m_cnodes;
+ delete[] p_logicIn;
+ delete m_ground;
+ delete p_A;
+ delete p_b;
+ delete p_x;
+ delete p_x_prev;
+}
+
+
+void ElementSet::setCacheInvalidated()
+{
+ m_pCircuit->setCacheInvalidated();
+}
+
+
+void ElementSet::addElement( Element *e )
+{
+ if ( !e || m_elementList.contains(e) ) return;
+ e->setElementSet(this);
+ m_elementList.append(e);
+ if ( e->isNonLinear() )
+ {
+ b_containsNonLinear = true;
+ m_cnonLinearList.append( static_cast<NonLinear*>(e) );
+ }
+}
+
+
+void ElementSet::createMatrixMap()
+{
+ p_A->createMap();
+
+
+ // And do our logic as well...
+
+ m_clogic = 0;
+ ElementList::iterator end = m_elementList.end();
+ for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it )
+ {
+ if ( dynamic_cast<LogicIn*>(*it) )
+ m_clogic++;
+ }
+
+ p_logicIn = new LogicIn*[m_clogic];
+ int i=0;
+ for ( ElementList::iterator it = m_elementList.begin(); it != end; ++it )
+ {
+ if ( LogicIn * in = dynamic_cast<LogicIn*>(*it) )
+ p_logicIn[i++] = in;
+ }
+}
+
+
+void ElementSet::doNonLinear( int maxIterations, double maxErrorV, double maxErrorI )
+{
+// p_x_prev->reset();
+
+ // And now tell the cnodes and cbranches about their new voltages & currents
+ updateInfo();
+
+ const NonLinearList::iterator end = m_cnonLinearList.end();
+
+ int k = 0;
+ do
+ {
+ // Tell the nonlinear elements to update its J, A and b from the newly calculated x
+ for ( NonLinearList::iterator it = m_cnonLinearList.begin(); it != end; ++it )
+ (*it)->update_dc();
+
+ *p_x = *p_b;
+ p_A->performLU();
+ p_A->fbSub(p_x);
+ updateInfo();
+
+ // Now, check for convergence
+ bool converged = true;
+ for ( unsigned i = 0; i < m_cn; ++i )
+ {
+ double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] );
+ if ( diff > maxErrorI )
+ {
+ converged = false;
+ break;
+ }
+ }
+ if ( converged )
+ {
+ for ( unsigned i = m_cn; i < m_cn+m_cb; ++i )
+ {
+ double diff = std::abs( (*p_x_prev)[i] - (*p_x)[i] );
+ if ( diff > maxErrorV )
+ {
+ converged = false;
+ break;
+ }
+ }
+ }
+
+ *p_x_prev = *p_x;
+
+ if ( converged )
+ break;
+ }
+ while ( ++k < maxIterations );
+}
+
+
+bool ElementSet::doLinear( bool performLU )
+{
+ if ( b_containsNonLinear || (!p_b->isChanged() && ((performLU && !p_A->isChanged()) || !performLU)) )
+ return false;
+
+ if (performLU)
+ p_A->performLU();
+
+ *p_x = *p_b;
+ p_A->fbSub(p_x);
+ updateInfo();
+ p_b->setUnchanged();
+
+ return true;
+}
+
+
+void ElementSet::updateInfo()
+{
+ for ( uint i=0; i<m_cn; i++ )
+ {
+ const double v = (*p_x)[i];
+ if (std::isfinite(v)) {
+ m_cnodes[i]->v = v;
+ } else {
+ (*p_x)[i] = 0.;
+ m_cnodes[i]->v = 0.;
+ }
+ }
+ for ( uint i=0; i<m_cb; i++ )
+ {
+ // NOTE: I've used lowercase and uppercase "I" here, so be careful!
+ const double I = (*p_x)[i+m_cn];
+ if (std::isfinite(I)) {
+ m_cbranches[i]->i = I;
+ } else {
+ (*p_x)[i+m_cn] = 0.;
+ m_cbranches[i]->i = 0.;
+ }
+ }
+
+ // Tell logic to check themselves
+ for ( uint i=0; i<m_clogic; ++i )
+ {
+ p_logicIn[i]->check();
+ }
+}
+
+
+void ElementSet::displayEquations()
+{
+ std::cout.setf(std::ios_base::fixed);
+ std::cout.precision(5);
+ std::cout.setf(std::ios_base::showpoint);
+ std::cout << "A x = b :"<<std::endl;
+ for ( uint i=0; i<m_cn+m_cb; i++ )
+ {
+ std::cout << "( ";
+ for ( uint j=0; j<m_cn+m_cb; j++ )
+ {
+ const double value = p_A->g(i,j);
+// if ( value > 0 ) cout <<"+";
+// else if ( value == 0 ) cout <<" ";
+ std::cout.width(10);
+ std::cout << value<<" ";
+ }
+ std::cout << ") ( "<<(*p_x)[i]<<" ) = ( ";
+ std::cout<<(*p_b)[i]<<" )"<<std::endl;
+ }
+ std::cout << "A_LU:"<<std::endl;
+ p_A->displayLU();
+}
+
+