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