AC State Estimation

To perform nonlinear or AC state estimation, the initial requirement is to have the PowerSystem type configured with the AC model, along with the Measurement type storing measurement data. Next, develop either the weighted least-squares (WLS) model, using the Gauss-Newton method, or the least absolute value (LAV) model. These models are encapsulated within the AcStateEstimation type:


To obtain bus voltages and solve the state estimation problem, users need to implement the Gauss-Newton iterative process for the WLS model using:

Alternatively, to obtain the LAV estimator, simply execute the second function.

After solving the AC state estimation, JuliaGrid provides functions for computing powers and currents:

Alternatively, users can call the wrapper function to solve the WLS or LAV model and, optionally, compute powers and currents:

Users can also access specialized functions for computing specific types of powers or currents for individual buses, branches, or generators within the power system.


Setup Initial Voltages

Create the PowerSystem and Measurement type:

system, monitoring = ems()

addBus!(system; label = "Bus 1", type = 3, magnitude = 1.1, angle = 0.0)
addBus!(system; label = "Bus 2", type = 1, magnitude = 1.2, angle = -0.1, active = 0.6)

addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.2)

addGenerator!(system; label = "Generator 1", bus = "Bus 1", active = 1.2)

addVoltmeter!(monitoring; bus = "Bus 1", magnitude = 1.0)
addVoltmeter!(monitoring; bus = "Bus 2", magnitude = 0.9)

addWattmeter!(monitoring; from = "Branch 1", active = 0.6)

Next, instantiate the weighted least-squares or least absolute value state estimation models. This example uses the weighted least-squares model:

analysis = gaussNewton(monitoring)

The initial voltage values for each model are derived from the voltage magnitudes and angles defined in the PowerSystem type:

julia> print(system.bus.label, system.bus.voltage.magnitude, system.bus.voltage.angle)Bus 1: 1.1, 0.0
Bus 2: 1.2, -0.1

These values are passed to the AcStateEstimation object during the execution of the gaussNewton or acLavStateEstimation function. Thus, the initial voltages are:

julia> print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)Bus 1: 1.1, 0.0
Bus 2: 1.2, -0.1

Custom Initial Voltages

Users may adjust the initial voltages according to their needs. One practical approach is to perform an AC power flow analysis and then apply the resulting solution as the starting point for state estimation:

pf = newtonRaphson(system)
powerFlow!(pf)

setInitialPoint!(analysis, pf)

This approach enables the state estimation process to start from a realistic operating condition, based on the power flow solution.


Weighted Least-Squares Estimator

To begin, define the PowerSystem and Measurement types:

system, monitoring = ems()

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

@branch(resistance = 0.14, conductance = 1e-4, susceptance = 0.04)
addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.25)
addBranch!(system; label = "Branch 2", from = "Bus 1", to = "Bus 3", reactance = 0.35)
addBranch!(system; label = "Branch 3", from = "Bus 2", to = "Bus 3", reactance = 0.16)

@voltmeter(label = "Voltmeter ? (!)")
addVoltmeter!(monitoring; bus = "Bus 1", magnitude = 1.0, variance = 1e-5)

@ammeter(label = "Ammeter ? (!)")
addAmmeter!(monitoring; from = "Branch 3", magnitude = 0.0356, variance = 1e-3)
addAmmeter!(monitoring; to = "Branch 2", magnitude = 0.5892, variance = 1e-3)

@wattmeter(label = "Wattmeter ? (!)")
addWattmeter!(monitoring; from = "Branch 1", active = 0.7067, variance = 1e-4)
addWattmeter!(monitoring; bus = "Bus 2", active = -0.6, variance = 2e-4)

@varmeter(label = "Varmeter ? (!)")
addVarmeter!(monitoring; from = "Branch 1", reactive = 0.2125, variance = 1e-4)
addVarmeter!(monitoring; bus = "Bus 2", reactive = -0.1, variance = 1e-5)

Next, to establish the AC state estimation model, use the gaussNewton function:

analysis = gaussNewton(monitoring)
Tip

Here, the user triggers LU factorization as the default method for solving the system of linear equations within each iteration of the Gauss-Newton method. The available factorization methods are LL, LDLt, LU, KLU, and QR:

analysis = gaussNewton(monitoring, LDLt)

To conduct an iterative process using the Gauss-Newton method, it is essential to include the increment! and solve! functions inside the iteration loop. For example:

for iteration = 1:20
    increment!(analysis)
    solve!(analysis)
end

Once the state estimator is obtained, users can access the bus voltage magnitudes and angles using:

julia> print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)Bus 1: 0.9999999893867697, 0.0
Bus 2: 0.8551739067243623, -0.16932686045421685
Bus 3: 0.8460326304864767, -0.17123533032549174

Breaking the Iterative Process

The iterative process can be terminated using the increment! function. The following code demonstrates how to use this function to break out of the iteration loop:

analysis = gaussNewton(monitoring)
for iteration = 1:20
    stopping = increment!(analysis)
    if stopping < 1e-8
        println("Solution found in $(analysis.method.iteration) iterations.")
        break
    end
    solve!(analysis)
end
Solution found in 4 iterations.

The increment! function returns the maximum absolute value of the state variable increment, which is commonly used as a convergence criterion in the iterative Gauss-Newton algorithm.

Info

Readers can refer to the AC State Estimation tutorial for implementation insights.


Wrapper Function

JuliaGrid provides the stateEstimation! wrapper function for AC state estimation. It manages the WLS iteration process or solves the LAV model, and it can optionally compute powers and currents:

analysis = gaussNewton(monitoring)
stateEstimation!(analysis; verbose = 3)
Number of wattmeters: 2   Number of varmeters: 2   Number of voltmeters: 1
  In-service:         2     In-service:        2     In-service:         1
  Out-of-service:     0     Out-of-service:    0     Out-of-service:     0

Number of ammeters:   2   Number of PMUs:      0   Number of devices:    7
  In-service:         2     In-service:        0     In-service:         7
  Out-of-service:     0     Out-of-service:    0     Out-of-service:     0

Number of entries in the Jacobian: 29
Number of measurement functions:    7
Number of state variables:          5
Number of buses:                    3
Number of branches:                 3

-----------------------------------------------
Iteration   Objective Value   Maximum Increment
-----------------------------------------------
        0    8.01893670e+03      2.03582921e-01
        1    2.97107558e+02      4.82737240e-02
        2    2.16194897e-01      1.87147684e-03
        3    4.71061964e-06      2.58855233e-06
        4    3.54147541e-07      1.58003988e-10

                    Measurement   Maximum Value
Absolute Residual:            2      1.2391e-05
Objective Value:              2      1.5352e-07

EXIT: The solution was found using the Gauss-Newton method in 4 iterations.
Info

Users can choose any approach in this section to obtain the WLS estimator based on their needs. Additionally, users can review the Gauss-Newton Algorithm used in the wrapper function within the tutorial section.


Inclusion of PMUs in Rectangular Coordinates

In the example above, the focus is solely on solving the AC state estimation using SCADA measurements. However, users can also integrate PMUs into the AC state estimation, either in the rectangular or polar coordinate system.

The default approach is to include PMUs in the rectangular coordinate system:

@pmu(label = "PMU ? (!)")
addPmu!(monitoring; to = "Branch 1", magnitude = 0.7466, angle = 2.8011)

Including PMU measurements in the rectangular system resolves ill-conditioned problems arising in polar coordinates due to small current magnitudes. However, this approach's main disadvantage is related to measurement errors, as measurement errors correspond to polar coordinates. Therefore, the covariance matrix must be transformed from polar to rectangular coordinates [4]. As a result, measurement errors of a single PMU are correlated, and the covariance matrix does not have a diagonal form. Despite that, the measurement error covariance matrix is usually considered as a diagonal matrix, affecting the accuracy of the state estimation.

The example above specifically includes PMUs where measurement error correlations are disregarded. This is evident through the precision matrix, which remains diagonal:

julia> analysis = gaussNewton(monitoring);
julia> analysis.method.precision9×9 SparseArrays.SparseMatrixCSC{Float64, Int64} with 9 stored entries: 100000.0 ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ 1000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 10000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 5000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 100000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1.05192e8 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1.64807e8

Lastly, correlation is incorporated into the model by adding a new PMU with the desired error correlation:

addPmu!(monitoring; bus = "Bus 3", magnitude = 0.846, angle = -0.1712, correlated = true)

The precision matrix is now no longer diagonal:

julia> analysis = gaussNewton(monitoring);
julia> analysis.method.precision11×11 SparseArrays.SparseMatrixCSC{Float64, Int64} with 13 stored entries: 100000.0 ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ 1000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 10000.0 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ … ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1.64807e8 ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ ⋅ 1.01153e8 6.66801e6 ⋅ ⋅ ⋅ ⋅ … ⋅ 6.66801e6 1.38567e8

Inclusion of PMUs in Polar Coordinates

The second approach involves incorporating these measurements into the polar coordinate system. For instance:

addPmu!(monitoring; from = "Branch 1", magnitude = 0.7379, angle = -0.2921, polar = true)

Including PMU measurements in the polar system provides more accurate state estimates compared to rectangular inclusion, but demands longer computing time. PMUs are handled in the same manner as SCADA measurements. However, this approach is susceptible to ill-conditioned problems arising in polar coordinates due to small values of current magnitudes [4, 5].

Tip

It is important to note that with each individual phasor measurement, the coordinate system can be set independently, allowing some measurements to use polar coordinates and others to use rectangular coordinates. This flexibility is particularly valuable because bus voltage phasor measurements are preferably included in a polar coordinate system, while current phasor measurements are best suited to a rectangular coordinate system.


Users can print the results in the REPL using any units that have been configured, such as:

@voltage(pu, deg)
printBusData(analysis)
|----------------------------|
| Bus Data                   |
|----------------------------|
| Label |      Voltage       |
|       |                    |
|   Bus | Magnitude |  Angle |
|       |      [pu] |  [deg] |
|-------|-----------|--------|
| Bus 1 |    1.0000 | 0.0000 |
| Bus 2 |    1.0000 | 0.0000 |
| Bus 3 |    1.0000 | 0.0000 |
|----------------------------|

Next, users can customize the print results for specific buses, for example:

printBusData(analysis; label = "Bus 1", header = true)
printBusData(analysis; label = "Bus 2")
printBusData(analysis; label = "Bus 3", footer = true)

Save Results to a File

Users can also redirect print output to a file. For example, data can be saved in a text file:

open("bus.txt", "w") do file
    printBusData(analysis, file)
end
Tip

JuliaGrid also provides functions to print or save state estimation results, such as estimated values and residuals. For more details, users can consult the Power and Current Analysis section of this manual.


Alternative Formulations

The resolution of the WLS state estimation problem using the conventional method typically progresses smoothly. However, it is widely acknowledged that in certain situations common to real-world systems, this method can be vulnerable to numerical instabilities. Such conditions might impede the algorithm from finding a satisfactory solution. In such scenarios, users may choose to apply an alternative formulation of the WLS estimator.

These alternative methods are applicable when measurement errors are uncorrelated and the precision matrix is diagonal. Therefore, as a preliminary step, the correlation must be eliminated, as shown previously:

updatePmu!(monitoring; label = "PMU 2 (Bus 3)", correlated = false)
Info

Readers can refer to the Alternative Formulation tutorial for implementation insights.


Orthogonal Method

One alternative is the orthogonal method [6, Sec. 3.2], which provides increased numerical robustness, especially with widely varying measurement variances. It solves the WLS problem using QR factorization on a rectangular matrix formed by multiplying the square root of the precision matrix with the Jacobian in each Gauss-Newton iteration. Enable it by passing the Orthogonal argument to the gaussNewton function:

analysis = gaussNewton(monitoring, Orthogonal)
stateEstimation!(analysis)

Peters and Wilkinson Method

Another option is the Peters and Wilkinson method [6, Sec. 3.4], which uses LU factorization on the same rectangular matrix built from the square root of the precision matrix and the Jacobian in each Gauss-Newton iteration. It can be selected by passing the PetersWilkinson argument to the gaussNewton function:

analysis = gaussNewton(monitoring, PetersWilkinson)
stateEstimation!(analysis)

Least Absolute Value Estimator

The LAV method presents an alternative estimation technique known for its increased robustness compared to WLS. While the WLS method relies on specific assumptions regarding measurement errors, robust estimators like LAV are designed to maintain unbiasedness even in the presence of various types of measurement errors and outliers. This characteristic often eliminates the need for extensive bad data analysis procedures [6, Ch. 6]. However, it is important to note that achieving robustness typically involves increased computational complexity.

To obtain an LAV estimator, users need to use one of the solvers listed in the JuMP documentation. In many common scenarios, the Ipopt solver proves sufficient to obtain a solution:

using Ipopt

analysis = acLavStateEstimation(monitoring, Ipopt.Optimizer)

To solve the formulated LAV state estimation model, simply execute the following function:

stateEstimation!(analysis)

Upon obtaining the solution, access the bus voltage magnitudes and angles using:

julia> print(system.bus.label, analysis.voltage.magnitude, analysis.voltage.angle)Bus 1: 0.9999955853355601, 0.0
Bus 2: 0.8551679167452755, -0.16932742195979208
Bus 3: 0.8460243712345896, -0.17123747254085778
Info

Readers can refer to the Least Absolute Value Estimation tutorial for implementation insights.


Measurement Set Update

Begin by creating the PowerSystem and Measurement types with the ems function. The AC model is then configured using the acModel! function. After that, initialize the AcStateEstimation type through the gaussNewton function and solve the resulting state estimation problem:

system, monitoring = ems()

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

@branch(resistance = 0.1, susceptance = 0.02)
addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.25)

acModel!(system)

addWattmeter!(monitoring; label = "Wattmeter 1", from = "Branch 1", active = 0.6)
addWattmeter!(monitoring; label = "Wattmeter 2", bus = "Bus 2", active = -0.6)

addVarmeter!(monitoring; label = "Varmeter 1", from = "Branch 1", reactive = 0.2)
addVarmeter!(monitoring; label = "Varmeter 2", bus = "Bus 2", reactive = -0.1)

analysis = gaussNewton(monitoring)
stateEstimation!(analysis)

Next, modify the existing Measurement type using add and update functions. Then, create the new AcStateEstimation type based on the modified system and solve the state estimation problem:

addWattmeter!(monitoring; label = "Wattmeter 3", to = "Branch 1", active = -0.7)
updateWattmeter!(monitoring; label = "Wattmeter 2", status = 0)

addVarmeter!(monitoring; label = "Varmeter 3", to = "Branch 1", reactive = -0.1)
updateVarmeter!(monitoring; label = "Varmeter 2", variance = 1e-2)

analysis = gaussNewton(monitoring)
stateEstimation!(analysis)
Info

This concept removes the need to restart and recreate the Measurement type from the beginning when implementing changes to the existing measurement set.


State Estimation Update

For advanced workflows, users can create the AcStateEstimation type once using gaussNewton or acLavStateEstimation. They can then modify existing measurement devices without recreating the AcStateEstimation type.

This approach extends the previous workflow by also avoiding recreation of the AcStateEstimation object.

Tip

The addition of new measurements after the creation of AcStateEstimation is not practical in terms of reusing this type. Instead, users should create a final set of measurements and then use update functions to manage devices, either setting them in-service or out-of-service throughout the process.

Now revisit the defined PowerSystem, Measurement and AcStateEstimation types:

system, monitoring = ems()

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

@branch(resistance = 0.1, susceptance = 0.02)
addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.25)

acModel!(system)

addWattmeter!(monitoring; label = "Wattmeter 1", from = "Branch 1", active = 0.6)
addWattmeter!(monitoring; label = "Wattmeter 2", bus = "Bus 2", active = -0.6)
addWattmeter!(monitoring; label = "Wattmeter 3", to = "Branch 1", active = -0.7, status = 0)

addVarmeter!(monitoring; label = "Varmeter 1", from = "Branch 1", reactive = 0.2)
addVarmeter!(monitoring; label = "Varmeter 2", bus = "Bus 2", reactive = -0.1)
addVarmeter!(monitoring; label = "Varmeter 3", to = "Branch 1", reactive = -0.1, status = 0)

analysis = gaussNewton(monitoring)
stateEstimation!(analysis)

Next, modify the existing Measurement type as well as the AcStateEstimation type using add and update functions. Then, immediately solve the state estimation problem:

updateWattmeter!(analysis; label = "Wattmeter 3", status = 1)
updateWattmeter!(analysis; label = "Wattmeter 2", status = 0)

updateVarmeter!(analysis; label = "Varmeter 3", status = 0)
updateVarmeter!(analysis; label = "Varmeter 2", variance = 1e-2)

stateEstimation!(analysis)
Info

This concept removes the need to rebuild both the Measurement and the AcStateEstimation from the beginning when implementing changes to the existing measurement set. In the scenario of using the WLS model, JuliaGrid can reuse symbolic factorizations of LL, LDLt, LU, and KLU, provided that the nonzero pattern of the gain matrix remains unchanged.


Power and Current Analysis

After obtaining the solution from the AC state estimation, calculate various electrical quantities related to buses and branches using the power! and current! functions. For instance, consider the model used to obtain the AC state estimation solution:

system, monitoring = ems()

addBus!(system; label = "Bus 1", type = 3, susceptance = 0.002)
addBus!(system; label = "Bus 2")
addBus!(system; label = "Bus 3")

@branch(resistance = 0.02, conductance = 1e-4, susceptance = 0.04)
addBranch!(system; label = "Branch 1", from = "Bus 1", to = "Bus 2", reactance = 0.05)
addBranch!(system; label = "Branch 2", from = "Bus 1", to = "Bus 3", reactance = 0.05)
addBranch!(system; label = "Branch 3", from = "Bus 2", to = "Bus 3", reactance = 0.03)

addWattmeter!(monitoring; from = "Branch 1", active = 1.046, variance = 1e-2)
addWattmeter!(monitoring; bus = "Bus 2", active = -0.1, variance = 1e-3)
addWattmeter!(monitoring; from = "Branch 3", active = 0.924, variance = 1e-3)

addVarmeter!(monitoring; from = "Branch 1", reactive = 0.059, variance = 1e-3)
addVarmeter!(monitoring; bus = "Bus 2", reactive = -0.01, variance = 1e-2)
addVarmeter!(monitoring; to = "Branch 3", reactive = -0.044, variance = 1e-3)

analysis = gaussNewton(monitoring)
stateEstimation!(analysis)

Now use the provided functions to compute powers and currents:

power!(analysis)
current!(analysis)

For instance, to show the active power injections and the from-bus current angles, use the following code:

julia> print(system.bus.label, analysis.power.injection.active)Bus 1: 2.6951392544228376
Bus 2: -0.09999730840050709
Bus 3: -2.49928780049058
julia> print(system.branch.label, analysis.current.from.angle)Branch 1: -0.05634389539194549 Branch 2: -0.15413096831549453 Branch 3: -0.08788060834432761
Info

To better understand the powers and currents associated with buses and branches that are calculated by the power! and current! functions, see the tutorials on AC State Estimation.


Users can use any of the print functions outlined in the Print API. For example, to print state estimation data related to wattmeters, use:

@power(MW, pu)
printWattmeterData(analysis)
|---------------------------------------------------------------|
| Wattmeter Data                                                |
|---------------------------------------------------------------|
| Label |                     Active Power                      |
|       |                                                       |
|       | Measurement | Variance | Estimate | Residual | Status |
|       |        [MW] |     [MW] |     [MW] |     [MW] |        |
|-------|-------------|----------|----------|----------|--------|
| 1     |    104.6000 | 1.00e+00 | 104.6026 |  -0.0026 |      1 |
| 2     |    -10.0000 | 1.00e-01 |  -9.9997 |  -0.0003 |      1 |
| 3     |     92.4000 | 1.00e-01 |  92.3997 |   0.0003 |      1 |
|---------------------------------------------------------------|

Save Results to a CSV File

For CSV output, users should first generate a simple table with style = false, and then save it to a CSV file:

using CSV

io = IOBuffer()
printWattmeterData(analysis, io; style = false)
CSV.write("wattmeter.csv", CSV.File(take!(io); delim = "|"))

Active and Reactive Power Injection

To calculate the active and reactive power injection associated with a specific bus, use:

julia> active, reactive = injectionPower(analysis; label = "Bus 1")(2.6951392544228376, 0.3132044972069036)

Active and Reactive Power Injection from Generators

To calculate the active and reactive power supply associated with a specific bus, use:

julia> active, reactive = supplyPower(analysis; label = "Bus 1")(2.6951392544228376, 0.3132044972069036)

Active and Reactive Power at Shunt Element

To calculate the active and reactive power associated with the shunt element at a specific bus, use:

julia> active, reactive = shuntPower(analysis; label = "Bus 1")(0.0, -0.0020066379178126643)

Active and Reactive Power Flow

Similarly, to compute the active and reactive power flow at both the from-bus and to-bus ends of a specific branch, use:

julia> active, reactive = fromPower(analysis; label = "Branch 2")(1.6491130619728922, 0.25621149744636723)
julia> active, reactive = toPower(analysis; label = "Branch 2")(-1.5932872124412005, -0.15530958335762404)

Active and Reactive Power at Charging Admittances

To calculate the active and reactive power associated with the branch charging admittances of a particular branch, use:

julia> active, reactive = chargingPower(analysis; label = "Branch 1")(9.800363198441312e-5, -0.039201452793765246)

Active powers indicate active losses within the branch's charging admittances. Moreover, charging admittances inject reactive power into the power system due to their capacitive nature, as denoted by a negative sign.


Active and Reactive Power at Series Impedance

To calculate the active and reactive power across the series impedance of the branch, use:

julia> active, reactive = seriesPower(analysis; label = "Branch 2")(0.055729793109976056, 0.1393244827749401)

The active power also considers active losses originating from the series resistance of the branch, while the reactive power represents reactive losses resulting from the impedance's inductive characteristics.


Current Injection

To calculate the current injection associated with a specific bus, use:

julia> magnitude, angle = injectionCurrent(analysis; label = "Bus 1")(2.7087856562191854, -0.11569193444689857)

Current Flow

To compute the current flow at both the from-bus and to-bus ends of a specific branch, use:

julia> magnitude, angle = fromCurrent(analysis; label = "Branch 2")(1.666134681475446, -0.15413096831549453)
julia> magnitude, angle = toCurrent(analysis; label = "Branch 2")(1.6709804259856476, 2.9641707923859992)

Current Through Series Impedance

To calculate the current passing through the series impedance of the branch in the direction from the from-bus end to the to-bus end, use the following function:

julia> magnitude, angle = seriesCurrent(analysis; label = "Branch 2")(1.6692781839761766, -0.16599467616843305)