You are on page 1of 24

AS-74.

4180 Automatic modelling of industrial


plants using semantic specications
Special assignment common part:
Transient in an electric line
Aram Simonian
9th October 2011
1 Introduction
The aim of this work is to simulate a transient response in an electric line.
The electric line is specied by the following parameters: characteristic
resistance R(/km), characteristic inductance L(H/km), characteristic capacity
C(f/km) and length l(km).
The electric line is then modelled using -equivalent circuit for every line
section. The equivalent circuit for simulation is shown in Figure 1. First of
all, the parameters of the line have to be chosen. I have chosen the following
parameters:
R
char
= 0.2 /km,
L
char
= 3 mH/km,
C
char
= 8 nF/km,
l = 3000 km.
The initial conditions are considered to be all 0 in the simulations, which
means that all voltages and currents are zero. However, it would be quite
easy to add any non-zero initial conditions by simply initialising the state
variables to the values of initial conditions.
Figure 1: -equivalent circuit for one line section.
2 Simulating whole line in one section
In this part, we consider the electric line in one section, which means that
we represent the whole line with just one -circuit. Assuming we have an
ideal voltage source with zero internal resistance connected to the line, we
can leave out the capacitor which is connected parallel to the source. This
1
simplies the -circuit to just two branches: the resistive-inductive branch,
which I will refer to as 2-1 and the capacitive branch, which will be referred
as 2-0 according to the indices of the end nodes of the branches. The
simplied circuit has just one internal node, which is directly the point where
we measure the output voltage.
2.1 Determining equations
Firstly, we have to consider the dierential equations for both of the branches.
We take advantage of the balance between voltage dierence of the end
nodes and voltage losses at the circuit elements along the branches when
determining the integral-dierential equations. Thus we get following equations
for the branch 2-1 and 2-0 respectively (reference node is indexed with 0):
u
2
(t) u
1
(t) Ri
21
(t) L
di
12
dt
= 0, (1)
u
2
(t)
2
C
_
t
i
20
dt = 0, (2)
where R = R
char
l, L = L
char
l and C = C
char
l.
Then we dierentiate (2) to get dierential equation:
du
2
dt

2
C
i
20
(t) = 0 (3)
In the next step we apply the implicit (also backward) Euler temporal discretization,
which means substituting derivatives by dierences:
dx
dt

x(t) x(t t)
t
(4)
Applying (4) to (1) and (3) we get dierence equations:
u
2
(t) u
1
(t) i
21
(t)
_
R
L
t
_
+
L
t
i
21
(t t) = 0, (5)
u
2
(t) u
2
(t t)
t

2
C
i
20
(t) = 0. (6)
As a next task, we are asked to develop a companion model in the form
u
i
g
f

j
g
b
+ s
ij
i
ij
= 0. We determine the parameters g
f
,g
b
and s
ij
simply
by comparing coecients of corresponding variables in equations (5) and (6)
with the equation for companion model. Considering that the voltage of
reference node 0 is 0V we get
i
21
(t) = g
21
(u
2
(t) u
1
(t)) + s
21
, (7)
i
20
(t) = g
20
u
2
(t) + s
20
, (8)
2
where the companion model parameters are
g
21
=
_
R +
L
t
_
1
,
s
21
=
L
t
_
R +
L
t
_
1
i
21
(t t),
g
20
=
C
2t
,
s
20
=
C
2t
u
2
(t t).
The last thing we have to do is to solve the output node voltage for transient
of input from 0V to 100V. I have chosen orientation of both currents i
21
, i
20
going out from node 2. A node cannot accumulate any charge, so we can
write
i
21
(t) + i
20
(t) = 0. (9)
Substituting (7) and (8) to (9), we can determine value of u
2
, because we
know the input voltage u
1
.
0 = u
2
(t)(g
21
+ g
20
) g
21
u
1
(t) + s
21
+ s
20
,
u
2
(t) =
g
21
u
1
t s
21
s
20
g
21
+ g
20
(10)
2.2 Implementation and results
Now we have everything to start the implementation of a simple solver. I have
implemented the solver in C++ programming language. It runs a simulation
according to the given parameters and stores the results in external csv le.
The parameters passed to the solver implemented by SolverWhole include
time step size, simulation length, output le name and parameters of the
electric line. The source code including all supplementary classes is presented
in Appendix A.
To have a rough idea about the systems behaviour I computed transfer
function from u
1
to u
2
and checked the step response in Matlab.
G(s) =
U
1
(s)
U
2
(s)
=
2
LCs
2
+ RCs + 2
This way I found out that the rise time of transient response is t
r
= 0.0144s
and the peak amplitude is u
2
= 1.31V at t = 0.0346s. (In our task we dont
3
have unit step at the input, but a 100V step, so the peak amplitude will be
100 higher.)
Before running the simulation, we have to think about the sampling
period (time step) t. According to Nyquist theorem, we should choose such
sampling frequency, that it is at least twice higher than highest frequency
in the spectrum of the signal that we want to capture. However, this is
only a lower bound. The sampling frequency is usually set higher. The
choice depends on requirements for the simulation. Higher sampling rates
slow down the simulation, whereas lower sampling rates bring lower accuracy.
Therefore we have to nd some compromise. There is an empirical rule in
control theory that we should get 10 samples within the rise time. Following
this rule I have chosen t = 1ms.
After running the simulation I imported the csv le in Matlab and plotted
the results. Figure 2 shows input and both theoretical and simulated output
voltages. The theoretical output voltage has been computed using Matlab
Control System Toolbox.
0 0.05 0.1 0.15 0.2
0
20
40
60
80
100
120
140
Time (s)
u
2
(
t
)

(
V
)
Output voltage


Input
Simulated output
theoretical output
Figure 2: Input, simulated output and theoretical output voltage.
4
To demonstrate the importance of choice of the sampling rate, I have run
the simulation with dierent time steps. Comparison of results is shown in
Figure 3. It is evident that with decreasing time step the simulation results
t the theoretical output better and better. However, we could not decrease
the time step innitesimally because we would reach the limits of numerical
precision (meaning the way how the numbers are represented in the physical
memory of the computer).
0 0.05 0.1 0.15 0.2
0
20
40
60
80
100
120
140
Time (s)
u
2
(
t
)

(
V
)
Output voltage


t=0.01s
t=0.005s
t=0.001s
t=0.0001s
Theoretical output
Figure 3: Comparison of simulation results with dierent time steps
3 Spatial discretization
In previous section we have considered the whole line in one section represented
by one equivalent -circuit. In this section we will divide the line into N
subsections that will be interconnected. To determine the node (state) and
branch (ow) variables we will have to solve a system of equations in a form
Au = d in every simulation step, where A is a matrix given by structure
of interconnections between the nodes, u is vector of node voltages and d is
vector of right side.
5
R
L
R
L
C
Ua
Ub Uc
R
L
R
L
C
R
L
C/2
Uy
Uz = Uout
U0
Figure 4: Equivalent circuit diagram for spatial discretization of electrical
line, orientation of branches marked with arrows.
3.1 Determining equations
Like in Section 2 we have two kinds of branches resistive-inductive and
capacitive. We can furthermore simplify the structure by merging neighbouring
parallel capacitive branches into one with capacity C. As we will do equidistant
spatial discretization, we will get the same type of equations for every internal
node. The only dierence will be in indices of variables. By merging the
neighbouring parallel capacitors we in fact introduce a series of identical
ipped -equivalent circuits with the last unit having half capacity. Scheme
depicting this approach is shown in Figure 4.
3.1.1 Equations for internal nodes
Even if we didnt use equidistant discretization, the equations for internal
nodes would dier only in static parameters R, L, C, but their form would
be the same. Here we show the equations for node which is marked as
U
b
in Figure 4. The three branches connected to this node are described
by dierential equations similar to the ones in Section 2.1 with the only
dierence that we have three branches connected to the node instead of two.
u
b
(t) u
a
(t) Ri
ba
(t) L
di
ba
dt
= 0, (11)
u
b
(t)
1
C
_
t
i
b0
dt = 0, (12)
u
c
(t) u
b
(t) Ri
cb
(t) L
di
cb
dt
= 0. (13)
The constants R, L and C are parameters of one control volume and can be
found by simply dividing resistance/inductance/capacity of the whole line
by number of control volumes. Similarly to Section 2.1 we dierentiate (12)
and subsequently apply the implicit Euler discretization. Then we get the
equations with companion model parameters.
6
i
ba
(t) = g
ba
(u
b
(t) u
a
(t)) + s
ba
, (14)
i
b0
(t) = g
b0
u
b
(t) + s
b0
, (15)
i
cb
(t) = g
cb
(u
c
(t) u
b
(t)) + c
cb
, (16)
where
g
ba
=
_
R +
L
t
_
1
= g
RL
,
s
ba
=
L
t
g
RL
i
ba
(t t) ,
g
b0
=
C
t
= g
C
,
s
b0
= g
C
u
b
(t t) ,
g
cb
= g
RL
,
s
cb
=
L
t
g
RL
i
cb
(t t) .
Being aware of the chosen orientation of branches we can write
i
ba
(t) + i
b0
(t) i
cb
(t) = 0, (17)
which gives us one equation from the set of equations that will describe the
whole network of nodes
g
RL
u
a
(t) + (2g
RL
+ g
C
)u
b
(t) g
RL
u
c
(t) = s
cb
s
ba
s
b0
. (18)
3.1.2 Equations for output node
The output node is in fact also an internal node, but it diers from all the
other internal nodes by its capacity, which is only C/2, and also by the
number of branches connected. Therefore we get
i
zy
(t) = g
zy
(u
z
(t) u
y
(t)) + s
zy
, (19)
i
z0
(t) = g
z0
u
z
(t) + s
z0
, (20)
where
g
zy
= g
RL
,
s
zy
=
L
t
g
RL
i
zy
(t t) ,
g
z0
= g
C
/2,
s
z0
= g
C
/2u
z
(t t) .
7
From the balance of currents i
zy
+ i
z0
= 0 we get
g
RL
u
y
(t) + (g
RL
+ g
C
/2)u
z
(t) = s
z0
+ s
zy
(21)
3.2 Constructing the matrix
We have already determined all the equations, so the only thing we have to
do is to write the set of equations as a matrix equation. We have to realise
that the voltage u
a
in case of the rst internal node is directly the voltage of
the source, so we just transfer it to the vector of right side. The system of
equations gives us a tri-diagonal matrix equation in form
_

_
b
1
c
1
0 0
a
2
b
2
c
2
.
.
.
0 a
3
b
3
c
3
.
.
.
.
.
. a
4
b
4
c
4
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
0
.
.
. a
n1
b
n1
c
n1
0 a
n
b
n
_

_
u
1
u
2
.
.
.
.
.
.
.
.
.
u
n1
u
n
_

_
=
_

_
d
1
d
2
.
.
.
.
.
.
.
.
.
d
n1
d
n
_

_
(22)
where
a
k
= g
RL
for k = 2, 3, , n
b
k
=
_
(2g
RL
+ g
C
) for k = 1, 2, , (n 1)
(g
RL
+ g
C
/2) for k = n
c
k
= g
RL
for k = 1, 2, , (n 1)
d
k
=
_

_
g
RL
u
a
+
L
t
g
RL
_
i
(k+1)k
(t t) i
k(k1)
(t t)
_
+ g
C
u
k
(t t) for k = 1
L
t
g
RL
_
i
(k+1)k
(t t) i
k(k1)
(t t)
_
+ g
C
u
k
(t t) for k = 2, 3, , (n 1)

L
t
g
RL
i
k(k1)
(t t) + g
C
/2u
k
(t t) for k = n
3.3 Implementation and results
Solver with both spatial and temporal discretization is implemented by SolverSpDiscr.
This solver takes the same parameters as SolverWhole, compared to which
it has one additional parameter, which is the number of control volumes the
line should be divided to. The source code is enclosed in the Appendix A.
8
The matrix A is strictly tri-diagonal, so we do not need to use any
sparse matrix techniques and we can eciently represent the matrix as three
vectors (sub-, sup-diagonal and main diagonal). The tri-diagonal matrix
equation system also enables us to use a more eective solver with asymptotic
complexity O(n) instead of traditional Gaussian elimination which has asymptotic
complexity O(n
3
). It would be possible to make even more noticeable optimisation
in our case, because the matrix A doesnt change during the simulation, so
the elimination steps are exactly the same in every iteration
1
. However, such
optimisation would make the implementation less generic.
The simulation performs following steps in every iteration:
1. write current state to external le (optional)
2. store current state as previous state (voltages and currents)
3. update companion model parameters (update A and d)
4. solve matrix equation for node voltages (determine vector u)
5. calculate the currents (branch ow variables)
For the space discrete simulation we used the same line parameters as
in Section 2, so the results should be comparable. The spreading velocity
of the signal is quite important for spatial discretization. The signal should
not travel a longer distance during one simulation step than the distance
of centres of two neighbouring control volumes. The velocity of alternating
electric signal along the line depends on the parameters of the line and the
frequency of signal. We have a voltage step at the input, which theoretically
contains all frequencies including the direct component. As the direct signal
spreads along the line at the speed of light, we have to consider the speed
of light as the spreading speed. To capture the transient response more
properly we also had to change the simulation time step. When we diminish
the time step, it enables us to capture higher frequencies from the spectrum
of sampled/simulated signal. (This means that even after setting smaller
time step we miss a part of the signal spectrum, but not that big part as
before diminishing the time step.) With respect to very quick transients we
have set the time step t = 100ns. Thanks to the spatial discretisation
we are able to see how the signal spreads along the line, in other words to
1
This would enable us to eliminate the matrix just once and then only update the
vector d in every iteration
9
0 0.05 0.1 0.15 0.2
0
20
40
60
80
100
120
140
160
simulation with 30 discrete control volumes
Time (s)
V
o
l
t
a
g
e

(
V
)


1
st
internal node voltage
middle node voltage
output node voltage
Figure 5: Transient response at the beginning, in the middle and at the end
of the electric line.
visualise the time delays and signal reections at the ends of the line. For
this purpose we divide the line into 30 control volumes.
Simulation results are shown in Figure 5. We got typical results with
the reections of the signal at the ends of the line. The output of the line
behaves as an open circuit with respect to direct signal, so the coecient of
reection at the end of the line is 0 < c
re
< 1. The value is smaller than 1
because of nonzero characteristic resistance of the line. If the resistance was
0, the coecient of reection at the end of the line would be exactly c
ro
= 1.
Ideal voltage source that is connected to the input of the line behaves as a
short circuit with respect to the direct signal, so the coecient of reection
at the beginning of the line is 1 < c
ri
< 0.
After the voltage step occurs, the signal starts to spread along the line.
The voltage of the rst input node rises, but, temporary steady value is lower
due to the resistance of the line. The rest of line is being charged, so there is
an electric current which causes voltage loss. After 5ms the signal arrives to
the middle of the line. Here, the temporary steady value is lower. 10ms after
the step the signal arrives to the output node. The time delay of signal along
10
0 2 4 6 8 10 12 14
x 10
3
0
5
10
15
20
25
30
35
40
45
50
simulation with 30 discrete control volumes
Time (s)
V
o
l
t
a
g
e

(
V
)


1
st
internal node voltage
middle node voltage
output node voltage
Figure 6: Time delay of the signal along the line caused by nite spreading
velocity.
the line is shown in Figure 6. The temporary steady value at the end of the
line seems to be even higher than input voltage. It is caused by the reection
of the signal at the end of the line. The reected (backward) signal (with the
same polarity as the forward one) is added to the forward signal according to
the principle of superposition. Then the backward signal is travelling to the
beginning of the line, which causes increase of voltage in the middle of the line
and another oscillation at the beginning. At the beginning the signal reects
again, but with opposite polarity and spreads again towards the end. Thanks
to the resistance of the line the amplitude of reected signal is getting lower
with the distance travelled along the line, so nally there is a steady state
voltage equal to the input voltage in all parts of the line. We have preserved
the same line parameters in Sections 2 and 3, so we can compare the results.
The comparison is presented in Figure 7. Apparently the model without
spatial discretisation cannot simulate the transport delays and reections
very well. As a result, neither amplitudes neither the frequency of oscillation
correspond with the results of the spatially discretized model, which is much
closer to real transient.
11
0 0.05 0.1 0.15 0.2
0
20
40
60
80
100
120
140
160
simulation with 30 discrete control volumes
Time (s)
V
o
l
t
a
g
e

(
V
)


Input
Output without spatial discr.
Output after spatial discr.
Figure 7: Comparison of simulation results with- and without spatial
discretization.
4 Conclusion
I have described the equivalent circuit of electric line with dierential equations.
After temporal discretization of these equations I have developed the companion
model and implemented solver that simulates the whole line in one section.
As the very next step, I have performed the spatial discretization and
implemented solver for both time- and space-discrete simulation based on
tri-diagonal matrix algorithm.
Simulations have brought expected results. Both solvers were implemented
in C++ and the source code is enclosed in Appendix A.
12
A Implementation
The implementation consists of several classes. Class FileWriter provides
an encapsulated interface for writing simulation results to external csv les.
Class Solver serves just as the parent class for solvers. Class SolverWhole
simulates the line as one unit. In fact this class implements the rst task
of the common part of the assignment. Class SolverSpDiscr represents
implementation of the spatially discretized model, which was the second part
of the common assignment.
The source code is presented at the following pages.
13
Class FileWriter interface for storing simulation results to external file
FileWriter.h
#pragmaonce
#include<iostream>
#include<fstream>
usingnamespace std;

class FileWriter
{
private:
fstream fs;
char* fn;
public:
FileWriter(void);
FileWriter(constchar* filename);
int insertLine(double* values, int length, double time);
int setOutput(constchar *filename);
int wrtColNames(constchar **colnames,int length);
int ready(void);
~FileWriter(void);
};

FileWriter.cpp
#include"FileWriter.h"

FileWriter::FileWriter(void)
{
}

FileWriter::FileWriter(constchar* filename)
{
fn = newchar[40];
setOutput(filename);
}

FileWriter::~FileWriter(void)
{
fs.close();
delete fn;
}

int FileWriter::insertLine(double* values, int length, double time)
{
fs << time <<";";
for(int i = 0; i<length; i++)
{
fs << values[i] <<";";
}
fs <<"\n";
if(fs.fail())
{
cout <<"Error writing file.\n";
fs.clear();
return 1;
}
else
{
return 0;
}
}

int FileWriter::setOutput(constchar *filename)
{
if(fs.is_open())
{
fs.close();
}
strcpy(fn,filename);
fs.open(fn, std::ios_base::trunc|std::ios_base::out);
if(!fs.is_open())
{
printf("Error opening/creating file '%s'...", fn);
return 1;
}
return 0;
}

int FileWriter::wrtColNames(constchar **colnames, int length)
{
if(!fs.is_open())
{
return 1;
}
for(int i=0; i<length; i++)
{
fs.write(colnames[i],strlen(colnames[i]));
fs <<";";
}
fs <<"\n";
return 0;
}

int FileWriter::ready(void)
{
return fs.is_open();
}

Class Solver parent class for other solvers
Solver.h
class Solver
{
protected:
double dt, simLen, L, R, C, lineLen;
long steps;
char outputFile [40];
FileWriter *fw;
public:
Solver(void);
~Solver(void);
void setTimeStep(constdouble timeStep);
void setSimLength(constdouble simulationLength);
int setOutput(constchar *outputFileName);
};


Solver.cpp
#include"Solver.h"
Solver::Solver(void)
{
}

Solver::~Solver(void)
{
}

void Solver::setTimeStep(constdouble timeStep)
{
steps = (long)ceil(steps*dt/timeStep);
dt = timeStep;
printf("Setting time step to %f s, %d simulation steps in
total.\n\n",timeStep,steps);
}

void Solver::setSimLength(constdouble simulationLength)
{
steps = (long)ceil(simulationLength/dt);
simLen = simulationLength;
printf("Setting simulation length to %f s, %d simulation steps in total.\n\n",
simLen,steps);
}

int Solver::setOutput(constchar *outputFileName)
{
if(fw->setOutput(outputFileName))
{
printf("Error opening/creating file %s\n\n",outputFileName);
return 1;
}
printf("Output file set to %s\n\n");
return 0;
}

Class SolverWhole simulate whole line as one unit
SolverWhole.h
#pragmaonce
#include"FileWriter.h"
#include"Solver.h"
#include<math.h>
#include<time.h>

class SolverWhole : public Solver
{
protected:
double u1,u2,i,io,u1o,u2o,i21,i21o,i20;
double g20,s20,s21,g21;
public:
SolverWhole(constdouble timeStep, constdouble simulationLength,
constchar *outputFileName, double l, double r, double c, double len);
~SolverWhole(void);
int solve(void);
void setL(constdouble l);
void setR(constdouble r);
void setC(constdouble c);
void setLineLength(constdouble length);
int writeState(double time);
};

SolverWhole.cpp
#include"SolverWhole.h"

SolverWhole::SolverWhole(constdouble timeStep, constdouble simulationLength,
constchar *outputFileName, double l, double r, double c, double len)
{
dt = timeStep; //time step for simulation [s]
simLen = simulationLength; //length of simulation [s]
strcpy_s(outputFile, outputFileName);
fw = new FileWriter(outputFile); //fstream for output
//init line parameters
L=l*len,R=r*len,C=c*len,lineLen=len;
//init variables for simulation
u1=100,u2=0,u2o=0,i21=0,i21o=0;
//init static companion model parameters
g21=1/(R+L/dt);
g20=C/2/dt;
//print info
steps = (long)ceil(simulationLength/timeStep);
printf("ELECTRIC LINE SIMULATION, WHOLE LINE IN ONE SECTION\n");
printf("Line parameters: L=%1.3f(H/km), R=%1.3f(Ohm/km), C=%1.3f(F/km),
l=1(km)\n",L,R,C);
printf("Time step for simulation: %f(s)\n", timeStep);
printf("Simulation length: %f(s), %d simulation steps in total.\n\n",
simulationLength,steps);
}

SolverWhole::~SolverWhole(void)
{
delete fw;
}

int SolverWhole::solve(void)
{
clock_t start,finish;
printf("Solving...\n");
start = clock();
//write initial conditions
writeState(0);
for(int n=0; n<steps; n++)
{
//save previous iteration results
i21o = i21;
u2o = u2;
//determine companion model parameters
s21 = L*i21o/dt*g21;
s20 = -C*u2o/2/dt;
//determine values of state and flow variables
u2 = (g21*u1-s21-s20)/(g21+g20);
i21 = g21*(u2-u1)+s21;
i20 = g20*u2+s20;
//write results to the output file
writeState((n+1)*dt);
}
finish = clock();
printf("%d ms elapsed...\n\n",(finish-start));
return 0;
}

void SolverWhole::setL(constdouble l)
{
L = l*lineLen;
printf("Setting characteristic inductance to %f H/km.\n\n",l);
}

void SolverWhole::setR(constdouble r)
{
R = r*lineLen;
printf("Setting characteristic resistance to %f Ohm/km.\n\n",r);
}

void SolverWhole::setC(constdouble c)
{
C = c*lineLen;
printf("Setting characteristic capacitance to %f F/km.\n\n",c);
}

void SolverWhole::setLineLength(constdouble length)
{
L*=(length/lineLen);
R*=(length/lineLen);
C*=(length/lineLen);
lineLen = length;
printf("Setting line length to %f km.\n\n",length);
}

int SolverWhole::writeState(double time)
{
if(!fw->ready())
{
printf("FileWriter not ready, cannto write...\n");
return 1;
}
else
{
fw->insertLine(&u2,1,time);
return 0;
}
}


SolverSpDiscr.h simulate spatially discretized line
#pragmaonce
#include"FileWriter.h"
#include<math.h>
#include<time.h>
#include"Solver.h"

class SolverSpDiscr : public Solver
{
protected:
int ctrlVolCount; //number of discrete control volumes
double dL,dR,dC; //parameters of one control volume
double *a,*b,*c,*d; //tri-diagonal matrix equation storage
double *u,*uo,**i,**io; //state and flow variables
double uin; //input voltage [V]
double gRL, gC; //conductances of the two types of branches
double sRLcoeff; //coefficient for source computation in RL branch
double *init1DArray(double *toInit, int size, double value=0);
double **init2DArray(double **toInit, int cols, int rows=2, double value=0);
double *updateDVector(double *d, double **io, double *uo);
void free2DArray(double **toFree, int rows);
void storeStatesAsPrev(void);
double* setArrayValue(double *arr, int length, double value);
double* updateBVector(double *b);
double** updateCurrents(double **i, double *u, double *uo, double **io);
void printArray(double *arr, int length, char *name);
public:
SolverSpDiscr(constdouble timeStep, constdouble simulationLength,
constchar *outputFileName, double _l, double _r, double _c, double len,
int controlVolumes);
~SolverSpDiscr(void);
int solve(int ithToSave);
double* tdmSolve(double *a, double *b, double *c, double *d, double *u, int
ctrlVolCount);
void setL(constdouble l);
void setR(constdouble r);
void setC(constdouble c);
void setLineLength(constdouble length);
int writeState(double time, double *u);
};


SolverSpDiscr.cpp
#include"SolverSpDicr.h"

SolverSpDiscr::SolverSpDiscr(constdouble timeStep, constdouble simulationLength,
constchar *outputFileName, double _l, double _r, double _c, double len, int
controlVolumes)
{
if(controlVolumes<2)
{
printf("controlVolumes must be >= 2...\n");
exit(1);
}
dt = timeStep; //time step for simulation [s]
simLen = simulationLength; //length of simulation [s]
strcpy_s(outputFile, outputFileName);
fw = new FileWriter(outputFile); //fstream for output
//init line parameters
L=_l*len,R=_r*len,C=_c*len,lineLen=len;
dL=L/(double)controlVolumes;
dR=R/(double)controlVolumes;
dC=C/(double)controlVolumes;
//init static companion model parameters
gRL=1/(dR+dL/dt);
gC=dC/dt;
sRLcoeff=gRL*dL/dt;
uin = 100;
//init the arrays
a = init1DArray(a,controlVolumes-1);
b = init1DArray(b,controlVolumes);
c = init1DArray(c,controlVolumes-1);
d = init1DArray(d,controlVolumes);
u = init1DArray(u,controlVolumes);
uo = init1DArray(uo,controlVolumes);
i = init2DArray(i,controlVolumes);
io = init2DArray(io,controlVolumes);
//print info
steps = (long)ceil(simulationLength/timeStep);
ctrlVolCount = controlVolumes;
printf("ELECTRIC LINE SIMULATION, TIME AND SPATIAL DISCRETIZATION\n");
printf("Line parameters: L=%1.3f(H/km), R=%1.3f(Ohm/km), C=%1.3f(F/km),
l=1(km)\n",L,R,C);
printf("Time step for simulation: %f(s)\n", timeStep);
printf("Simulation length: %f(s), %d simulation steps in total.\n",
simulationLength,steps);
printf("%d discrete control volumes.\n\n", ctrlVolCount);
d = updateDVector(d,io,uo);
}

SolverSpDiscr::~SolverSpDiscr(void)
{
//free all dynamically allocated memory
delete[] a;
delete[] b;
delete[] c;
delete[] d;
delete[] u;
delete[] uo;
free2DArray(i,2);
free2DArray(io,2);
delete fw;
}

int SolverSpDiscr::solve(int ithToSave)
{
for(int k=0; k<steps+1; k++)
{
if(k % ithToSave == 0)
writeState((double)k*dt, u);
storeStatesAsPrev();
a = setArrayValue(a, ctrlVolCount-1, -gRL);
b = updateBVector(b);
c = setArrayValue(c, ctrlVolCount-1, -gRL);
d = updateDVector(d,io,uo);
u = tdmSolve(a,b,c,d,u,ctrlVolCount);
i = updateCurrents(i,u,uo,io);
}
return 0;
}

void SolverSpDiscr::setL(constdouble l)
{
L = l*lineLen;
dL = L/ctrlVolCount;
printf("Setting characteristic inductance to %f H/km.\n\n");
}

void SolverSpDiscr::setR(constdouble r)
{
R = r*lineLen;
dR = R/ctrlVolCount;
printf("Setting characteristic resistance to %f Ohm/km.\n\n",r);
}

void SolverSpDiscr::setC(constdouble c)
{
C = c*lineLen;
dC = C/ctrlVolCount;
printf("Setting characteristic capacitance to %f F/km.\n\n",c);
}

void SolverSpDiscr::setLineLength(constdouble length)
{
L*=(length/lineLen);
R*=(length/lineLen);
C*=(length/lineLen);
dL*=(length/lineLen);
dR*=(length/lineLen);
dC*=(length/lineLen);
lineLen = length;
printf("Setting line length to %f km.\n\n",length);
}

int SolverSpDiscr::writeState(double time, double *u)
{
fw->insertLine(u,ctrlVolCount,time);
return 0;
}

double* SolverSpDiscr::init1DArray(double *toInit, int size, double value)
{
toInit = newdouble [size];
for(int i=0;i<size;i++)
{
toInit[i] = value;
}
return toInit;
}

double** SolverSpDiscr::init2DArray(double **toInit, int cols, int rows , double
value)
{
toInit = newdouble*[rows];
for(int i=0;i<rows;i++){
toInit[i] = newdouble[cols];
for(int j=0;j<cols;j++){
toInit[i][j] = value;
}
}
return toInit;
}

double* SolverSpDiscr::updateDVector(double *d, double **io, double *uo)
{
int n=0;
for(n; n<ctrlVolCount-1; n++)
{
d[n] = sRLcoeff*(io[0][n+1]-io[0][n])+gC*uo[n];
}
d[0] += gRL*uin;
d[n] = gC/2*uo[n] - sRLcoeff*io[0][n];
return d;
}

void SolverSpDiscr::free2DArray(double **toFree, int rows)
{
for(int i=0;i<rows;i++)
{
delete[] toFree[i];
}
}

void SolverSpDiscr::storeStatesAsPrev(void)
{
double *oneDbuffer;
double **twoDbuffer;

//store current voltages as previous
oneDbuffer = u;
u = uo; //values will be rewritten
uo = oneDbuffer;

//store current currents as previous
twoDbuffer = i;
i = io; //values will be rewritten
io = twoDbuffer;
}

double* SolverSpDiscr::tdmSolve(double *a, double *b, double *c, double *d, double *u,
int ctrlVolCount)
{
double m;
for (int i = 0; i < ctrlVolCount-1; i++)
{
m = a[i]/b[i];
b[i+1] = b[i+1] - m*c[i];
d[i+1] = d[i+1] - m*d[i];;
}
u[ctrlVolCount-1] = d[ctrlVolCount-1]/b[ctrlVolCount-1];
for (int i = ctrlVolCount - 2; i >= 0; i--)
{
u[i]=(d[i]-c[i]*u[i+1])/b[i];
}
return u;
}

double* SolverSpDiscr::setArrayValue(double *arr, int length, double value)
{
for(int i = 0;i<length;i++)
{
arr[i] = value;
}
return arr;
}

double* SolverSpDiscr::updateBVector(double *b)
{
for(int i=0; i<ctrlVolCount-1; i++)
{
b[i]=gC+2*gRL;
}
b[ctrlVolCount-1] = gC/2+gRL;
return b;
}

double** SolverSpDiscr::updateCurrents(double **i, double *u, double *uo, double **io)
{
//node connected to the voltage source has to be computed separately
i[0][0] = gRL*(u[0] - uin) + sRLcoeff*io[0][0];
i[1][0] = gC*(u[0] - uo[0]);
//internal nodes
for(int k=1; k<ctrlVolCount-1; k++)
{
i[0][k] = gRL*(u[k] - u[k-1]) + sRLcoeff*io[0][k];
i[1][k] = gC*(u[k] - uo[k]);
}
//last node - beware of capacitance only C/2
i[0][ctrlVolCount-1] = gRL*(u[ctrlVolCount-1] - u[ctrlVolCount-2]) +
sRLcoeff*io[0][ctrlVolCount-1];
i[1][ctrlVolCount-1] = gC*(u[ctrlVolCount-1] - uo[ctrlVolCount-1])/2;
return i;
}

void SolverSpDiscr::printArray(double *arr, int length, char *name)
{
printf("%s = ",name);
for(int i=0;i<length;i++)
{
printf("%f\t", arr[i]);
}
printf("\n");
}

You might also like