Observability Analysis

In this example, we analyze a 6-bus power system, shown in Figure 1. The initial objective is to conduct an observability analysis to identify observable islands and restore observability. Later, we examine optimal PMU placement to ensure system observability using only phasor measurements.

Figure 1: The 6-bus power system.

 
Info

Users can download a Julia script containing the scenarios from this section using the following link.

We define the power system and add buses and branches:

system = powerSystem()

addBus!(system; label = "Bus 1", type = 3)
addBus!(system; label = "Bus 2")
addBus!(system; label = "Bus 3")
addBus!(system; label = "Bus 4")
addBus!(system; label = "Bus 5")
addBus!(system; label = "Bus 6")

@branch(reactance = 0.22)
addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2")
addBranch!(system; label = "Branch 2", from = "Bus 2", to = "Bus 3")
addBranch!(system; label = "Branch 3", from = "Bus 2", to = "Bus 4")
addBranch!(system; label = "Branch 4", from = "Bus 3", to = "Bus 5")
addBranch!(system; label = "Branch 5", from = "Bus 3", to = "Bus 4")
addBranch!(system; label = "Branch 6", from = "Bus 4", to = "Bus 6")

Observability analysis and optimal PMU placement are independent of branch parameters, measurement values, and variances.


Identification of Observable Islands

Next, we define the measurement model. JuliaGrid uses standard observability analysis based on the linear decoupled measurement model. Wattmeter active power measurements estimate bus voltage angles, while varmeter reactive power measurements estimate bus voltage magnitudes. In this example, four meters monitor the 6-bus power system, as shown in Figure 2.

Figure 2: The 6-bus power system monitoring with four power meters.

 

The island detection step relies only on wattmeters, so defining wattmeters alone is sufficient when the goal is to identify observable islands. For observability restoration followed by state estimation, varmeters are also needed. Therefore, the four meters represent both wattmeters and varmeters:

monitoring = measurement(system)

addWattmeter!(monitoring; label = "Meter 1", from = "Branch 1", active = 1.1)
addVarmeter!(monitoring; label = "Meter 1", from = "Branch 1", reactive = -0.5)

addWattmeter!(monitoring; label = "Meter 2", bus = "Bus 2", active = -0.1)
addVarmeter!(monitoring; label = "Meter 2", bus = "Bus 2", reactive = -0.1)

addWattmeter!(monitoring; label = "Meter 3", bus = "Bus 4", active = -0.3)
addVarmeter!(monitoring; label = "Meter 3", bus = "Bus 4", reactive = 0.6)

addWattmeter!(monitoring; label = "Meter 4", to = "Branch 6", active = 0.2)
addVarmeter!(monitoring; label = "Meter 4", to = "Branch 6", reactive = 0.3)

AC state estimation cannot be solved with these measurements because the gain matrix would be singular. The same issue occurs with DC state estimation. To address this, observability analysis adds non-redundant measurements to ensure a nonsingular gain matrix and a unique state estimator.

Observability analysis begins by identifying observable islands. JuliaGrid can identify both flow-observable and maximal-observable islands, either of which can serve as the foundation for restoration. Here, we explore both types.

First, we determine the flow-observable islands:

islands = islandTopologicalFlow(monitoring)

The result identifies four flow-observable islands:

julia> islands.island4-element Vector{Vector{Int64}}:
 [1, 2]
 [3]
 [4, 6]
 [5]

The first observable island consists of Bus 1 and Bus 2, the second contains Bus 3, the third includes Bus 4 and Bus 6, and Bus 5 forms the fourth island, as shown in Figure 3.

Figure 3: Flow-observable islands in the 6-bus power system.

 

We can also identify maximal-observable islands:

islands = islandTopological(monitoring)

The result identifies two maximal-observable islands:

julia> islands.island2-element Vector{Vector{Int64}}:
 [1, 2, 3, 4, 6]
 [5]

The measurements from Meter 2 and Meter 3 merge the first, second, and third flow-observable islands into one, as shown in Figure 4.

Figure 4: Maximal-observable islands in the 6-bus power system.

 

For island identification, detecting flow-observable islands requires less computational effort than identifying maximal-observable islands. For observability restoration, however, using flow islands tends to be more computationally demanding than using maximal islands.


Observability Restoration

Observability restoration requires a new set of measurements, called pseudo-measurements. These typically hold historical data about electrical quantities. We define this set:

pseudo = measurement(system)

addWattmeter!(pseudo; label = "Pseudo 1", from = "Branch 5", active = 0.3)
addVarmeter!(pseudo; label = "Pseudo 1", from = "Branch 5", reactive = 0.1)

addWattmeter!(pseudo; label = "Pseudo 2", bus = "Bus 5", active = 0.3)
addVarmeter!(pseudo; label = "Pseudo 2", bus = "Bus 5", reactive = -0.2)

Next, we invoke the observability restoration function:

restorationGram!(monitoring, pseudo, islands)

This function identifies the minimal set of pseudo-measurements needed to make the system observable. In this case, it selects Pseudo 2 and transfers it to the measurement model.

The final wattmeter set used to measure active power is:

printWattmeterData(monitoring)
|--------------------------------------------|
| Wattmeter Data                             |
|--------------------------------------------|
|  Label   |          Active Power           |
|          |                                 |
|          | Measurement | Variance | Status |
|          |        [pu] |     [pu] |        |
|----------|-------------|----------|--------|
| Meter 1  |      1.1000 | 1.00e-04 |      1 |
| Meter 2  |     -0.1000 | 1.00e-04 |      1 |
| Meter 3  |     -0.3000 | 1.00e-04 |      1 |
| Meter 4  |      0.2000 | 1.00e-04 |      1 |
| Pseudo 2 |      0.3000 | 1.00e-04 |      1 |
|--------------------------------------------|

Likewise, the final varmeter set used to measure reactive power is:

printVarmeterData(monitoring)
|--------------------------------------------|
| Varmeter Data                              |
|--------------------------------------------|
|  Label   |         Reactive Power          |
|          |                                 |
|          | Measurement | Variance | Status |
|          |        [pu] |     [pu] |        |
|----------|-------------|----------|--------|
| Meter 1  |     -0.5000 | 1.00e-04 |      1 |
| Meter 2  |     -0.1000 | 1.00e-04 |      1 |
| Meter 3  |      0.6000 | 1.00e-04 |      1 |
| Meter 4  |      0.3000 | 1.00e-04 |      1 |
| Pseudo 2 |     -0.2000 | 1.00e-04 |      1 |
|--------------------------------------------|

Adding the Pseudo 2 measurement makes the system observable, which we confirm by identifying a single observable island:

islands = islandTopological(monitoring)
julia> islands.island1-element Vector{Vector{Int64}}:
 [1, 2, 4, 6, 5, 3]

To proceed with AC state estimation, one additional step is needed. The system must include at least one bus voltage magnitude measurement because observable islands are identified using wattmeters, which estimate voltage angles. Since the slack bus voltage angle is already known, an analogous reference is needed for bus voltage magnitudes. To satisfy this condition, we add the following measurement:

addVoltmeter!(monitoring; label = "Pseudo 3", bus = "Bus 1", magnitude = 1.0)

Figure 5 shows the measurement configuration that makes the 6-bus power system observable and ensures a unique state estimator.

Figure 5: Measurement configuration that makes the 6-bus power system observable.


Optimal PMU Placement

The PMU placement algorithm determines the minimum number of PMUs required to make the system observable. Here, we analyze a 6-bus power system without power meters and identify the smallest PMU set needed for full observability and a unique state estimator:

pmu = measurement(system)
placement = pmuPlacement(pmu, HiGHS.Optimizer)

We retrieve the optimal PMU locations with:

julia> keys(placement.bus)KeySet for a OrderedCollections.OrderedDict{String, Int64} with 3 entries. Keys:
  "Bus 2"
  "Bus 3"
  "Bus 4"

Figure 6 shows the PMU configuration that ensures observability and guarantees a unique state estimator. Each installed PMU measures the bus voltage phasor and the current phasors of all connected branches.

Figure 6: PMU configuration that makes the 6-bus power system observable.

 

The phasor measurement configuration includes voltage phasor measurements at Bus 2, Bus 3, and Bus 4, along with current phasor measurements at the from-bus ends of the branches:

julia> keys(placement.from)KeySet for a OrderedCollections.OrderedDict{String, Int64} with 5 entries. Keys:
  "Branch 2"
  "Branch 3"
  "Branch 4"
  "Branch 5"
  "Branch 6"

To complete the measurement setup, the set also includes current phasor measurements at the to-bus ends of the branches:

julia> keys(placement.to)KeySet for a OrderedCollections.OrderedDict{String, Int64} with 4 entries. Keys:
  "Branch 1"
  "Branch 2"
  "Branch 3"
  "Branch 5"

These variables provide a convenient way to define phasor measurement values, whether based on AC power flow or AC optimal power flow analyses, as shown in the PMU state estimation example.

Users can also specify phasor measurement values manually:

addPmu!(pmu; label = "PMU 1-1", bus = "Bus 2", magnitude = 1.1, angle = -0.2)
addPmu!(pmu; label = "PMU 1-2", to = "Branch 1", magnitude = 1.2, angle = -2.7)
addPmu!(pmu; label = "PMU 1-3", from = "Branch 2", magnitude = 0.6, angle = 0.3)
addPmu!(pmu; label = "PMU 1-4", from = "Branch 3", magnitude = 0.6, angle = 0.7)

addPmu!(pmu; label = "PMU 2-1", bus = "Bus 3", magnitude = 1.2, angle = -0.3)
addPmu!(pmu; label = "PMU 2-2", to = "Branch 2", magnitude = 0.6, angle = -2.8)
addPmu!(pmu; label = "PMU 2-3", from = "Branch 4", magnitude = 0.3, angle = -2.8)

addPmu!(pmu; label = "PMU 3-1", bus = "Bus 4", magnitude = 1.2, angle = -0.3)
addPmu!(pmu; label = "PMU 3-2", to = "Branch 3", magnitude = 0.6, angle = -2.3)
addPmu!(pmu; label = "PMU 3-3", to = "Branch 4", magnitude = 0.3, angle = 0.3)
addPmu!(pmu; label = "PMU 3-4", from = "Branch 6", magnitude = 0.2, angle = 1.9)

This phasor measurement set ensures system observability and guarantees a unique state estimator. Display the defined phasor measurements with:

printPmuData(pmu)
|-----------------------------------------------------------------------------|
| PMU Data                                                                    |
|-----------------------------------------------------------------------------|
|  Label  |        Voltage Magnitude        |          Voltage Angle          |
|         |                                 |                                 |
|         | Measurement | Variance | Status | Measurement | Variance | Status |
|         |        [pu] |     [pu] |        |       [rad] |    [rad] |        |
|---------|-------------|----------|--------|-------------|----------|--------|
| PMU 1-1 |      1.1000 | 1.00e-08 |      1 |     -0.2000 | 1.00e-08 |      1 |
| PMU 2-1 |      1.2000 | 1.00e-08 |      1 |     -0.3000 | 1.00e-08 |      1 |
| PMU 3-1 |      1.2000 | 1.00e-08 |      1 |     -0.3000 | 1.00e-08 |      1 |
|-----------------------------------------------------------------------------|
|-----------------------------------------------------------------------------|
| PMU Data                                                                    |
|-----------------------------------------------------------------------------|
|  Label  |        Current Magnitude        |          Current Angle          |
|         |                                 |                                 |
|         | Measurement | Variance | Status | Measurement | Variance | Status |
|         |        [pu] |     [pu] |        |       [rad] |    [rad] |        |
|---------|-------------|----------|--------|-------------|----------|--------|
| PMU 1-2 |      1.2000 | 1.00e-08 |      1 |     -2.7000 | 1.00e-08 |      1 |
| PMU 1-3 |      0.6000 | 1.00e-08 |      1 |      0.3000 | 1.00e-08 |      1 |
| PMU 1-4 |      0.6000 | 1.00e-08 |      1 |      0.7000 | 1.00e-08 |      1 |
| PMU 2-2 |      0.6000 | 1.00e-08 |      1 |     -2.8000 | 1.00e-08 |      1 |
| PMU 2-3 |      0.3000 | 1.00e-08 |      1 |     -2.8000 | 1.00e-08 |      1 |
| PMU 3-2 |      0.6000 | 1.00e-08 |      1 |     -2.3000 | 1.00e-08 |      1 |
| PMU 3-3 |      0.3000 | 1.00e-08 |      1 |      0.3000 | 1.00e-08 |      1 |
| PMU 3-4 |      0.2000 | 1.00e-08 |      1 |      1.9000 | 1.00e-08 |      1 |
|-----------------------------------------------------------------------------|