1 /***************************************************************************
2  *   Copyright (C) 2003-2006 by David Saxton                               *
3  *   david@bluehaze.org                                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10 
11 #ifndef ELEMENT_H
12 #define ELEMENT_H
13 
14 #include "elementset.h"
15 #include "matrix.h"
16 
17 #include <stdint.h>
18 
19 class ElementSet;
20 typedef unsigned int uint;
21 
22 const double T = 300.; ///< Temperature in Kelvin
23 const double K = 1.3806503e-23; ///< Boltzmann's constant
24 const double q = 1.602176462e-19; ///< Charge on an electron
25 const double V_T = K*T/q; ///< Thermal voltage
26 
27 class CNode
28 {
29 public:
CNode()30 	CNode() : v(0.0), isGround(false), m_n(0) {}
CNode(const uint32_t n)31 	CNode(const uint32_t n) : v(0.0), isGround(false), m_n(n) {}
set_n(const uint n)32 	void set_n( const uint n ) { m_n=n; }
n()33 	uint n() const { return m_n; }
34 
35 	/// Voltage on node. This is set from the last calculated voltage.
36 	double v;
37 
38 	/// True for ground nodes. Obviously, you should ignore n and v if this is true
39 	bool isGround;
40 
41 private:
42 
43 	/// CNode number
44 	uint m_n;
45 };
46 
47 class CBranch
48 {
49 public:
CBranch()50 	CBranch() : i(0.0), m_n(0) {}
CBranch(const uint32_t n)51 	CBranch(const uint32_t n) : i(0.0), m_n(n) {}
set_n(const uint n)52 	void set_n( const uint n ) { m_n=n; }
n()53 	uint n() const { return m_n; }
54 
55 	/// Current flowing through branch. This is set from the last calculated current.
56 	double i;
57 
58 private:
59 	/// CBranch number
60 	uint m_n;
61 };
62 
63 const int MAX_CNODES = 4;
64 const int MAX_CBRANCHES = 4;
65 
66 /// Default node number that represents no node (remember that
67 /// Ground node is -1, and the rest are numbered from 0 to n-1
68 const int noCNode = -2;
69 
70 /// Likewise for branch (although there is no "ground" branch;
71 /// it is merely -2 for likeness with noCNode)
72 const int noBranch = -2;
73 
74 /**
75 @short Represents a circuit element (such as resistance)
76 @author David Saxton
77 */
78 class Element
79 {
80 public:
81 	enum Type {
82 		Element_BJT,
83 		Element_Capacitance,
84 		Element_CCCS,
85 		Element_CCVS,
86 		Element_CurrentSignal,
87 		Element_CurrentSource,
88 		Element_Diode,
89 		Element_JFET,
90 		Element_Inductance,
91 		Element_LogicIn,
92 		Element_LogicOut,
93 		Element_MOSFET,
94 		Element_OpAmp,
95 		Element_Resistance,
96 		Element_VCCS,
97 		Element_VCVS,
98 		Element_VoltagePoint,
99 		Element_VoltageSignal,
100 		Element_VoltageSource
101 	};
102 
103 	Element();
104 	virtual ~Element();
105 	/**
106 	 * This must be called when the circuit is changed. The function will get
107 	 * all the required pointers from ElementSet
108 	 */
109 	virtual void setElementSet( ElementSet *c );
110 	/**
111 	 * Returns a pointer to the current element set
112 	 */
elementSet()113 	ElementSet * elementSet() const { return p_eSet; }
114 	/**
115 	 * Tells the element which nodes to use. Remember that -1 is ground. You
116 	 * should refer to the individual elements for which nodes are used for what.
117 	 */
118 	void setCNodes( const int n0 = noCNode, const int n1 = noCNode, const int n2 = noCNode, const int n3 = noCNode );
119 	/**
120 	 * Tells the element it's branch numbers (if it should have one). Not
121 	 * all elements use this.
122 	 */
123 	void setCBranches( const int b0 = noBranch, const int b1 = noBranch, const int b2 = noBranch, const int b3 = noBranch );
124 	/**
125 	 * Returns a pointer to the given CNode
126 	 */
cnode(const uint num)127 	CNode *cnode( const uint num ) { return p_cnode[num]; }
128 	/**
129 	 * Returns a pointer to the given CNode
130 	 */
cbranch(const uint num)131 	CBranch *cbranch( const uint num ) { return p_cbranch[num]; }
132 	/**
133 	 * Returns the number of branches used by the element
134 	 */
numCBranches()135 	int numCBranches() const { return m_numCBranches; }
136 	/**
137 	 * Returns the number of circuit nodes used by the element
138 	 */
numCNodes()139 	int numCNodes() const { return m_numCNodes; }
140 	/**
141 	 * Call this function to tell the element to calculate the
142 	 * current flowing *into* it's cnodes *from* the element. You
143 	 * can get the currents with m_cnodeI. Child class must implement this function.
144 	 */
145 	virtual void updateCurrents() = 0;
146 	/**
147 	 * Returns true for reactive elements that need stepping for numerical-integration
148 	 * (such as capacitors)
149 	 */
isReactive()150 	virtual bool isReactive() const { return false; }
151 	/**
152 	 * Returns true for NonLinear elements that need iteration to converge to a solution
153 	 * as the matrix A is a function of x.
154 	 */
isNonLinear()155 	virtual bool isNonLinear() const { return false; }
156 	/**
157 	 * Returns the type of element
158 	 */
159 	virtual Type type() const = 0;
160 
161 	/**
162 	 * Does the required MNA stuff. This should be called from ElementSet when necessary.
163 	 */
164 	virtual void add_initial_dc() = 0;
165 	/**
166 	 * This is called from the Component destructor. When elementSetDeleted has
167 	 * also been called, this class will delete itself.
168 	 */
169 	 void componentDeleted();
170 	 void elementSetDeleted();
171 
172 	double m_cnodeI[8]; ///< Current flowing into the cnodes from the element
173 	double cbranchCurrent( const int branch );
174 	double cnodeVoltage( const int node );
175 
176 protected:
177 	/**
178 	 * Update the status, returning b_status
179 	 */
180 	virtual bool updateStatus();
181 	/**
182 	 * Resets all calculated currents in the nodes to 0
183 	 */
184 	void resetCurrents();
185 
186 	inline double & A_g( uint i, uint j );
187 	inline double & A_b( uint i, uint j );
188 	inline double & A_c( uint i, uint j );
189 	inline double & A_d( uint i, uint j );
190 
191 	inline double & b_i( uint i );
192 	inline double & b_v( uint i );
193 
194 	ElementSet *p_eSet;
195 
196 	/**
197 	 * Set by child class - the number of circuit nodes that the element uses
198 	 */
199 	int m_numCNodes;
200 	CNode *p_cnode[MAX_CNODES];
201 
202 	/**
203 	 * Set by child class - the number of branches that the element uses
204 	 * Typically, this is 0, but could be 1 (e.g. independent voltage source)
205 	 * or 2 (e.g. cccs)
206 	 */
207 	int m_numCBranches;
208 	CBranch *p_cbranch[MAX_CBRANCHES];
209 
210 	/**
211 	 * True when the element can do add_initial_dc(), i.e. when it has
212 	 * pointers to the circuit, and at least one of its nodes is not ground.
213 	 */
214 	bool b_status;
215 
216 private:
217 	bool b_componentDeleted;
218 	double m_temp;
219 };
220 
221 
A_g(uint i,uint j)222 double &Element::A_g( uint i, uint j )
223 {
224 	if(p_cnode[i]->isGround || p_cnode[j]->isGround) return m_temp;
225 	return p_eSet->matrix()->g( p_cnode[i]->n(), p_cnode[j]->n() );
226 }
227 
A_b(uint i,uint j)228 double &Element::A_b( uint i, uint j )
229 {
230 	if ( p_cnode[i]->isGround ) return m_temp;
231 	return p_eSet->matrix()->b( p_cnode[i]->n(), p_cbranch[j]->n() );
232 }
233 
A_c(uint i,uint j)234 double &Element::A_c( uint i, uint j )
235 {
236 	if ( p_cnode[j]->isGround ) return m_temp;
237 	return p_eSet->matrix()->c( p_cbranch[i]->n(), p_cnode[j]->n() );
238 }
239 
A_d(uint i,uint j)240 double &Element::A_d( uint i, uint j )
241 {
242 	return p_eSet->matrix()->d( p_cbranch[i]->n(), p_cbranch[j]->n() );
243 }
244 
245 
b_i(uint i)246 double &Element::b_i( uint i )
247 {
248 	if ( p_cnode[i]->isGround )
249 		return m_temp;
250 
251 	return (*(p_eSet->b()))[ p_cnode[i]->n() ];
252 }
253 
b_v(uint i)254 double & Element::b_v( uint i )
255 {
256 	return (*(p_eSet->b()))[ p_eSet->cnodeCount() + p_cbranch[i]->n() ];
257 }
258 
259 #endif
260