Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
ACS
Public
Power System Automation and Monitoring
pyVolt
pyVolt
Commits
d01c0b9b
Commit
d01c0b9b
authored
Mar 06, 2019
by
martin.moraga
Browse files
improve nv_state_estimator_cim.py
parent
347be7ee
Changes
3
Expand all
Hide whitespace changes
Inline
Side-by-side
acs/state_estimation/measurement.py
View file @
d01c0b9b
...
@@ -2,17 +2,22 @@ from enum import Enum
...
@@ -2,17 +2,22 @@ from enum import Enum
import
numpy
as
np
import
numpy
as
np
class
ElemType
(
Enum
):
class
ElemType
(
Enum
):
Node
=
1
#Node Voltage
Node
=
1
#Node Voltage
Branch
=
2
#Complex Power
Injection at node
Branch
=
2
#Complex Power
flow at branch
class
MeasType
(
Enum
):
class
MeasType
(
Enum
):
V
=
1
#Node Voltage
V_mag
=
1
#Node Voltage
Sinj
=
2
#Complex Power Injection at node
Sinj_real
=
2
#Complex Power Injection at node
S1
=
4
#Complex Power flow at branch, measured at initial node
Sinj_imag
=
3
#Complex Power Injection at node
S2
=
5
#Complex Power flow at branch, measured at final node
S1_real
=
4
#Active Power flow at branch, measured at initial node (S1.real)
I
=
6
#Branch Current
S1_imag
=
5
#Reactive Power flow at branch, measured at initial node (S1.imag)
Vpmu
=
7
#Node Voltage
I_mag
=
6
#Branch Current
Ipmu
=
9
#Branch Current
Vpmu_mag
=
7
#Node Voltage
Vpmu_phase
=
8
#Node Voltage
Ipmu_mag
=
9
#Branch Current
Ipmu_phase
=
10
#Branch Current
S2_real
=
11
#Active Power flow at branch, measured at final node (S2.real)
S2_imag
=
12
#Reactive Power flow at branch, measured at final node (S2.imag)
class
Measurement
():
class
Measurement
():
def
__init__
(
self
,
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
):
def
__init__
(
self
,
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
):
...
@@ -35,16 +40,18 @@ class Measurement():
...
@@ -35,16 +40,18 @@ class Measurement():
self
.
element_type
=
element_type
self
.
element_type
=
element_type
self
.
meas_type
=
meas_type
self
.
meas_type
=
meas_type
self
.
meas_value
=
meas_value
self
.
meas_value
=
meas_value
self
.
std_dev
=
self
.
meas_value
*
(
std_dev
/
300
)
self
.
std_dev
=
std_dev
if
self
.
std_dev
<
10
**
(
-
6
)
self
.
std_dev
=
std_dev
self
.
std_dev
=
10
**
(
-
6
)
self
.
mval
=
0.0
#measured values (affected by uncertainty)
self
.
mval
=
0.0
#measured values (affected by uncertainty)
class
Measurents_set
():
class
Measurents_set
():
def
__init__
(
self
):
def
__init__
(
self
):
self
.
measurements
=
[]
self
.
measurements
=
[]
#array with all measurements
def
create_measurement
(
self
,
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
):
def
create_measurement
(
self
,
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
):
"""
to add elements to the measurements array
"""
self
.
measurements
.
append
(
Measurement
(
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
))
self
.
measurements
.
append
(
Measurement
(
element
,
element_type
,
meas_type
,
meas_value
,
std_dev
))
def
meas_creation
(
self
):
def
meas_creation
(
self
):
...
@@ -54,79 +61,114 @@ class Measurents_set():
...
@@ -54,79 +61,114 @@ class Measurents_set():
err_pu
=
np
.
random
.
normal
(
0
,
1
,
len
(
self
.
measurements
))
err_pu
=
np
.
random
.
normal
(
0
,
1
,
len
(
self
.
measurements
))
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
measurement
.
mval
=
measurement
.
meas_value
+
self
.
std_dev
*
err_pu
[
index
]
measurement
.
mval
=
measurement
.
meas_value
+
self
.
std_dev
*
err_pu
[
index
]
def
getNumberOfMeasurements
(
self
)
def
meas_creation_test
(
self
,
err_pu
):
"""
"""
return number of measurements of each type in the array Measurents_set.measurements
For test purposes.
"""
It calculates the measured values (affected by uncertainty) at the measurement points.
nvi
,
npi
,
nqi
,
npf
,
nqf
,
nii
,
nvpum
,
nipmu
=
0
This function takes as paramenter the random gaussian distribution.
for
elem
in
self
.
measurements
:
"""
if
elem
.
meas_type
is
MeasType
.
V
:
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
nvi
=
nvi
+
1
measurement
.
mval
=
measurement
.
meas_value
+
measurement
.
std_dev
*
err_pu
[
index
]
elif
elem
.
meas_type
is
MeasType
.
Sinj
:
npi
=
npi
+
1
def
getMeasurements
(
self
,
type
):
nqi
=
nqi
+
1
elif
elem
.
meas_type
is
MeasType
.
S1
or
elem
.
meas_type
is
MeasType
.
S2
:
npf
=
npf
+
1
nqf
=
nqf
+
1
elif
elem
.
meas_type
is
MeasType
.
I
:
nii
=
nii
+
1
elif
elem
.
meas_type
is
MeasType
.
Vpmu
:
nvpum
=
nvpum
+
1
elif
elem
.
meas_type
is
MeasType
.
Ipmu
:
nipmu
=
nipmu
+
1
return
nvi
,
npi
,
nqi
,
npf
,
nqf
,
nii
,
nvpum
,
nipmu
def
getMeasuredActiveInjPowers
(
self
):
"""
"""
return an array with
the
measurements of type
Sinj.real
return an array with
all
measurements of type
"type" in the array Measurents_set.measurements.
"""
"""
Pinj
=
np
.
array
(
[]
)
measurements
=
[]
for
elem
in
self
.
measurements
:
for
measurement
in
self
.
measurements
:
if
elem
.
meas_type
is
MeasType
.
Sinj
:
if
measurement
.
meas_type
is
type
:
Pinj
=
np
.
append
(
Pinj
,
elem
.
real
)
measurements
.
append
(
measurement
)
return
Pinj
return
measurements
def
getNumberOfMeasurements
(
self
,
type
):
"""
return number of measurements of type "type" in the array Measurents_set.measurements
"""
number
=
0
for
measurement
in
self
.
measurements
:
if
measurement
.
meas_type
is
type
:
number
=
number
+
1
return
number
def
get
MeasuredReactiveInjPowers
(
self
):
def
get
IndexOfMeasurements
(
self
,
type
):
"""
"""
return
an array with the
measurements of type
Sinj.imag
return
index of all
measurements of type
"type" in the array Measurents_set.measurements
"""
"""
Qinj
=
np
.
array
([])
idx
=
np
.
zeros
(
self
.
getNumberOfMeasurements
(
type
),
dtype
=
int
)
for
elem
in
self
.
measurements
:
i
=
0
if
elem
.
meas_type
is
MeasType
.
Sinj
:
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
Qinj
=
np
.
append
(
Qinj
,
elem
.
imag
)
if
measurement
.
meas_type
is
type
:
idx
[
i
]
=
index
i
=
i
+
1
return
idx
return
Qinj
def
getWeightsMatrix
(
self
):
"""
return an array the weights (obtained as standard_deviations^-2)
"""
weights
=
np
.
zeros
(
len
(
self
.
measurements
))
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
#the weight is small and can bring instability during matrix inversion, so we "cut" everything below 10^-6
if
measurement
.
std_dev
<
10
**
(
-
6
):
measurement
.
std_dev
=
10
**
(
-
6
)
weights
[
index
]
=
measurement
.
std_dev
**
(
-
2
)
def
getMeasuredActiveBPowers
(
self
):
return
weights
def
getMeasValues
(
self
):
"""
"""
return an array with the measurements of type S1.real or S2.real
for test purposes
returns an array with all measured values
"""
"""
Pbr
=
np
.
array
([]
)
meas_val
=
np
.
zeros
(
len
(
self
.
measurements
)
)
for
elem
in
self
.
measurements
:
for
index
,
measurement
in
enumerate
(
self
.
measurements
)
:
if
elem
.
meas_type
is
MeasType
.
S1
or
elem
.
meas_type
is
MeasType
.
S2
:
meas_val
[
index
]
=
measurement
.
meas_value
Pbr
=
np
.
append
(
Pbr
,
elem
.
real
)
return
Pbr
return
meas_val
def
get
MeasuredReactiveBPowers
(
self
):
def
get
mVal
(
self
):
"""
"""
return an array with
the
measure
ments of type S1.imag or S2.imag
return
s
an array with
all
measure
d values (affected by uncertainty)
"""
"""
Qbr
=
np
.
array
([])
mVal
=
np
.
zeros
(
len
(
self
.
measurements
))
for
elem
in
self
.
measurements
:
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
if
elem
.
meas_type
is
MeasType
.
S1
or
elem
.
meas_type
is
MeasType
.
S2
:
mVal
[
index
]
=
measurement
.
mval
Qbr
=
np
.
append
(
Qbr
,
elem
.
imag
)
return
Qbr
""" Replace in mVal amplitude and phase of Vpmu by real and imaginary part """
#get all measurements of type MeasType.Vpmu_mag
Vpmu_mag_idx
=
self
.
getIndexOfMeasurements
(
type
=
MeasType
.
Vpmu_mag
)
#get all measurements of type MeasType.Vpmu_phase
Vpmu_phase_idx
=
self
.
getIndexOfMeasurements
(
type
=
MeasType
.
Vpmu_phase
)
for
vpmu_mag_index
,
vpmu_phase_index
in
zip
(
Vpmu_mag_idx
,
Vpmu_phase_idx
):
vamp
=
self
.
measurements
[
vpmu_mag_index
].
mval
vtheta
=
self
.
measurements
[
vpmu_phase_index
].
mval
mVal
[
vpmu_mag_index
]
=
vamp
*
np
.
cos
(
vtheta
)
mVal
[
vpmu_phase_index
]
=
vamp
*
np
.
sin
(
vtheta
)
def
getWeightsMatrix
(
self
)
""" Replace in z amplitude and phase of Ipmu by real and imaginary part """
#get all measurements of type MeasType.Ipmu_mag
Ipmu_mag_idx
=
self
.
getIndexOfMeasurements
(
type
=
MeasType
.
Ipmu_mag
)
#get all measurements of type MeasType.Ipmu_phase
Ipmu_phase_idx
=
self
.
getIndexOfMeasurements
(
type
=
MeasType
.
Ipmu_phase
)
for
ipmu_mag_index
,
ipmu_phase_index
in
zip
(
Ipmu_mag_idx
,
Ipmu_phase_idx
):
iamp
=
self
.
measurements
[
ipmu_mag_index
].
mval
itheta
=
self
.
measurements
[
ipmu_phase_index
].
mval
mVal
[
ipmu_mag_index
]
=
iamp
*
np
.
cos
(
itheta
)
mVal
[
ipmu_phase_index
]
=
iamp
*
np
.
sin
(
itheta
)
return
mVal
def
getStd_Dev
(
self
):
"""
"""
creates the weights matrix (obtained as standard_deviations^-2)
for test purposes
returns an array with all standard deviations
"""
"""
weights
=
np
.
zeros
(
len
(
self
.
measurements
))
std_dev
=
np
.
zeros
(
len
(
self
.
measurements
))
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
for
index
,
measurement
in
enumerate
(
self
.
measurements
):
weights
[
index
]
=
measurement
.
std_dev
**
(
-
2
)
std_dev
[
index
]
=
measurement
.
std_dev
return
np
.
diag
(
weights
)
return
std_dev
\ No newline at end of file
\ No newline at end of file
acs/state_estimation/nv_powerflow_cim.py
View file @
d01c0b9b
...
@@ -167,7 +167,7 @@ class PowerflowResults():
...
@@ -167,7 +167,7 @@ class PowerflowResults():
for
branch
in
self
.
branches
:
for
branch
in
self
.
branches
:
S2
=
np
.
append
(
S2
,
branch
.
power2
)
S2
=
np
.
append
(
S2
,
branch
.
power2
)
return
S2
return
S2
def
solve
(
system
):
def
solve
(
system
):
"""It performs Power Flow by using rectangular node voltage state variables."""
"""It performs Power Flow by using rectangular node voltage state variables."""
...
@@ -254,59 +254,4 @@ def solve(system):
...
@@ -254,59 +254,4 @@ def solve(system):
results
.
calculateS1
()
results
.
calculateS1
()
results
.
calculateS2
()
results
.
calculateS2
()
return
results
,
num_iter
return
results
,
num_iter
\ No newline at end of file
def
calculateI
(
system
,
V
):
"""
To calculate the branch currents
"""
Ymatrix
,
Adj
=
Ymatrix_calc
(
system
)
I
=
np
.
zeros
((
len
(
system
.
branches
)),
dtype
=
np
.
complex
)
for
idx
in
range
(
len
(
system
.
branches
)):
fr
=
system
.
branches
[
idx
].
start_node
.
index
to
=
system
.
branches
[
idx
].
end_node
.
index
I
[
idx
]
=
-
(
V
[
fr
]
-
V
[
to
])
*
Ymatrix
[
fr
][
to
]
return
I
def
calculateInj
(
system
,
I
):
"""
To calculate current injections at a node
"""
Iinj
=
np
.
zeros
((
len
(
system
.
nodes
)),
dtype
=
np
.
complex
)
for
k
in
range
(
0
,
(
len
(
system
.
nodes
))):
to
=
[]
fr
=
[]
for
m
in
range
(
len
(
system
.
branches
)):
if
k
==
system
.
branches
[
m
].
start_node
.
index
:
fr
.
append
(
m
)
if
k
==
system
.
branches
[
m
].
end_node
.
index
:
to
.
append
(
m
)
Iinj
[
k
]
=
np
.
sum
(
I
[
to
])
-
np
.
sum
(
I
[
fr
])
return
Iinj
def
calculateS1
(
system
,
V
,
I
):
"""
To calculate powerflow on branches
"""
S1
=
np
.
zeros
((
len
(
system
.
branches
)),
dtype
=
np
.
complex
)
for
i
in
range
(
0
,
len
(
system
.
branches
)):
S1
[
i
]
=
V
[
system
.
branches
[
i
].
start_node
.
index
]
*
(
np
.
conj
(
I
[
i
]))
return
S1
def
calculateS2
(
system
,
V
,
I
):
"""
To calculate powerflow on branches
"""
S2
=
np
.
zeros
((
len
(
system
.
branches
)),
dtype
=
np
.
complex
)
for
i
in
range
(
0
,
len
(
system
.
branches
)):
S2
[
i
]
=
-
V
[
system
.
branches
[
i
].
end_node
.
index
]
*
(
np
.
conj
(
I
[
i
]))
return
S2
def
calculateSinj
(
V
,
Iinj
):
"""
To calculate power injection at a node
"""
Sinj
=
np
.
multiply
(
V
,
np
.
conj
(
Iinj
))
return
Sinj
\ No newline at end of file
acs/state_estimation/nv_state_estimator_cim.py
View file @
d01c0b9b
This diff is collapsed.
Click to expand it.
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment