Non-linear power flow#
The non-linear power flow n.pf()
works for AC networks andby extension for DC networks too.
The non-linear power flow n.pf()
can be called for aparticular snapshot
as n.pf(snapshot)
or on an iterableof snapshots
as n.pf(snapshots)
to calculate thenon-linear power flow on a selection of snapshots at once (which ismore performant than calling n.pf
on each snapshotseparately). If no argument is passed, it will be called on alln.snapshots
, see pypsa.Network.pf() for details.
AC networks (single slack)#
The power flow ensures for given inputs (load and power plantdispatch) that the following equation is satisfied for each bus\(i\):
\[S_i = P_i + j Q_i = V_i I_i^* = V_i \left(\sum_j Y_{ij} V_j\right)^*\]
where \(V_i = |V_i|e^{j\theta_i}\) is the complex voltage, whoserotating angle is taken relative to the slack bus.
\(Y_{ij}\) is the bus admittance matrix, based on the branchimpedances and any shunt admittances attached to the buses.
For the slack bus \(i=0\) it is assumed \(|V_0|\) is given and that \(\theta_0 = 0\); P and Q are to be found.
For the PV buses, P and \(|V|\) are given; Q and \(\theta\) are to be found.
For the PQ buses, P and Q are given; \(|V|\) and \(\theta\) are to be found.
If PV and PQ are the sets of buses, then there are \(|PV| + 2|PQ|\) real equations to solve:
\[\begin{split}\textrm{Re}\left[ V_i \left(\sum_j Y_{ij} V_j\right)^* \right] - P_i & = 0 \hspace{.7cm}\forall\hspace{.1cm} i \in PV \cup PQ \\\textrm{Im}\left[ V_i \left(\sum_j Y_{ij} V_j\right)^* \right] - Q_i & = 0 \hspace{.7cm}\forall\hspace{.1cm} i \in PQ\end{split}\]
To be found: \(\theta_i \forall i \in PV \cup PQ\) and \(|V_i| \forall i \in PQ\).
These equations \(f(x) = 0\) are solved using the Newton-Raphson method, with the Jacobian:
\[\begin{split}\frac{\partial f}{\partial x} = \left( \begin{array}{cc} \frac{\partial P}{\partial \theta} & \frac{\partial P}{\partial |V|} \\ \frac{\partial Q}{\partial \theta} & \frac{\partial Q}{\partial |V|} \end{array} \right)\end{split}\]
and the initial “flat” guess of \(\theta_i = 0\) and \(|V_i| = 1\) for unknown quantities.
AC networks (distributed slack)#
If the slack is to be distributed to all generators in proportionto their dispatch (distribute_slack=True
), instead of beingallocated fully to the slack bus, the active power balance is altered to
\[\textrm{Re}\left[ V_i \left(\sum_j Y_{ij} V_j\right)^* \right] - P_i - P_{slack}\gamma_i = 0 \hspace{.7cm}\forall\hspace{.1cm} i \in PV \cup PQ \cup slack\]
where \(P_{slack}\) is the total slack power and \(\gamma_{i}\)is the share of bus \(i\) of the total generation that is used todistribute the slack power. Note that also an additional active powerbalance is included for the slack bus since it is now part of thedistribution scheme.
This adds an additional row to the Jacobian for the derivativesof the slack bus active power balance and an additional columnfor the partial derivatives with respect to \(\gamma_i\).
DC networks#
For meshed DC networks the equations are a special case of those forAC networks, with the difference that all quantities are real.
To solve the non-linear equations for a DC network, ensure that theseries reactance \(x\) and shunt susceptance \(b\) are zerofor all branches, pick a Slack bus (where \(V_0 = 1\)) and set allother buses to be ‘PQ’ buses. Then execute n.pf()
.
The voltage magnitudes then satisfy at each bus \(i\):
\[P_i = V_i I_i = V_i \sum_j G_{ij} V_j\]
where all quantities are real.
\(G_{ij}\) is based only on the branch resistances and any shuntconductances attached to the buses.
Line model#
Lines are modelled with the standard equivalent PI model.
If the series impedance is given by
\[z = r+jx\]
and the shunt admittance is given by
\[y = g + jb\]
then the currents and voltages at buses 0 and 1 for a line:
are related by
\[\begin{split}\left( \begin{array}{c} i_0 \\ i_1\end{array}\right) = \left( \begin{array}{cc} \frac{1}{z} + \frac{y}{2} & -\frac{1}{z} \\ -\frac{1}{z} & \frac{1}{z} + \frac{y}{2} \end{array} \right) \left( \begin{array}{c} v_0 \\ v_1\end{array} \right)\end{split}\]
Transformer model#
The transformer models here are largely based on the implementation inpandapower, which isloosely based on DIgSILENT PowerFactory.
Transformers are modelled either with the equivalent T model (thedefault, since this represents the physics better) or with theequivalent PI model. The can be controlled by setting transformerattribute model
to either t
or pi
.
The tap changer can either be modelled on the primary, high voltageside 0 (the default) or on the secondary, low voltage side 1. This is set with attribute tap_side
.
If the transformer type
is not given, then tap_ratio
isdefined by the user, defaulting to 1.
. If the type
is given,then the user can specify the tap_position
which results in atap ratio
\(\tau\) given by:
\[\tau = 1 + (\textrm{tap_position} - \textrm{tap_neutral})\cdot \frac{\textrm{tap_step}}{100}\]
For a transformer with tap ratio \(\tau\) on the primary sidetap_side = 0
and phase shift \(\theta_{\textrm{shift}}\), theequivalent T model is given by:
For a transformer with tap ratio \(\tau\) on the secondary sidetap_side = 1
and phase shift \(\theta_{\textrm{shift}}\), theequivalent T model is given by:
For the admittance matrix, the T model is transformed into a PI modelwith the wye-delta transformation.
For a transformer with tap ratio \(\tau\) on the primary sidetap_side = 0
and phase shift \(\theta_{\textrm{shift}}\), theequivalent PI model is given by:
for which the currents and voltages are related by:
\[\begin{split}\left( \begin{array}{c} i_0 \\ i_1\end{array}\right) = \left( \begin{array}{cc} \frac{1}{z} + \frac{y}{2} & -\frac{1}{z}\frac{1}{\tau e^{-j\theta}} \\ -\frac{1}{z}\frac{1}{\tau e^{j\theta}} & \left(\frac{1}{z} + \frac{y}{2} \right) \frac{1}{\tau^2} \end{array} \right) \left( \begin{array}{c} v_0 \\ v_1\end{array} \right)\end{split}\]
For a transformer with tap ratio \(\tau\) on the secondary sidetap_side = 1
and phase shift \(\theta_{\textrm{shift}}\), theequivalent PI model is given by:
for which the currents and voltages are related by:
\[\begin{split}\left( \begin{array}{c} i_0 \\ i_1\end{array}\right) = \left( \begin{array}{cc} \left(\frac{1}{z} + \frac{y}{2} \right) \frac{1}{\tau^2} & -\frac{1}{z}\frac{1}{\tau e^{-j\theta}} \\ -\frac{1}{z}\frac{1}{\tau e^{j\theta}} & \frac{1}{z} + \frac{y}{2} \end{array} \right) \left( \begin{array}{c} v_0 \\ v_1\end{array} \right)\end{split}\]
Inputs#
For the non-linear power flow, the following data for each componentare used. For almost all values, defaults are assumed if notexplicitly set. For the defaults and units, see Components.
n.buses.{v_nom, v_mag_pu_set}
n.loads.{p_set, q_set}
n.generators.{control, p_set, q_set}
n.storage_units.{control, p_set, q_set}
n.stores.{p_set, q_set}
n.shunt_impedances.{b, g}
n.lines.{x, r, b, g}
n.transformers.{x, r, b, g}
n.links.{p_set}
Note
Note that the control strategy for active and reactive power PQ/PV/Slack is set on the generators not on the buses. Buses then inherit the control strategy from the generators attached at the bus (defaulting to PQ if there is no generator attached). Any PV generator will make the whole bus a PV bus. For PV buses, the voltage magnitude set point is set on the bus, not the generator, with bus.v_mag_pu_set since it is a bus property.
Note
Note that for lines and transformers you MUST make sure that \(r+jx\) is non-zero, otherwise the bus admittance matrix will be singular.
Outputs#
n.buses.{v_mag_pu, v_ang, p, q}
n.loads.{p, q}
n.generators.{p, q}
n.storage_units.{p, q}
n.stores.{p, q}
n.shunt_impedances.{p, q}
n.lines.{p0, q0, p1, q1}
n.transformers.{p0, q0, p1, q1}
n.links.{p0, p1}
Linear power flow#
The linear power flow n.lpf()
can be called for aparticular snapshot
as n.lpf(snapshot)
or on an iterableof snapshots
as n.lpf(snapshots)
to calculate thelinear power flow on a selection of snapshots at once (which ismore performant than calling n.lpf
on each snapshotseparately). If no argument is passed, it will be called on alln.snapshots
, , see pypsa.Network.lpf() for details.
AC networks#
For AC networks, it is assumed for the linear power flow that reactivepower decouples, there are no voltage magnitude variations, voltageangles differences across branches are small and branch resistancesare much smaller than branch reactances (i.e. it is good for overheadtransmission lines).
For AC networks, the linear load flow is calculated using small voltageangle differences and the series reactances alone.
It is assumed that the active powers \(P_i\) are given for all buses except the slack bus and the task is to find the voltage angles \(\theta_i\) at all buses except the slack bus, where it is assumed \(\theta_0 = 0\).
To find the voltage angles, the following linear set of equations are solved
\[P_i = \sum_j (KBK^T)_{ij} \theta_j - \sum_l K_{il} b_l \theta_l^{\textrm{shift}}\]
where \(K\) is the incidence matrix of the network, \(B\) isthe diagonal matrix of inverse branch series reactances \(x_l\)multiplied by the tap ratio \(\tau_l\), i.e. \(B_{ll} = b_l =\frac{1}{x_l\tau_l}\) and \(\theta_l^{\textrm{shift}}\) is thephase shift for a transformer. The matrix \(KBK^T\) is singularwith a single zero eigenvalue for a connected network, therefore therow and column corresponding to the slack bus is deleted beforeinverting.
The flows p0
in the network branches at bus0
can then be found by multiplying by the transpose incidence matrix and inverse series reactances:
\[F_l = \sum_i (BK^T)_{li} \theta_i - b_l \theta_l^{\textrm{shift}}\]
DC networks#
For DC networks, it is assumed for the linear power flow that voltagemagnitude differences across branches are all small.
For DC networks, the linear load flow is calculated using small voltagemagnitude differences and series resistances alone.
The linear load flow for DC networks follows the same calculation as for AC networks, but replacing the voltage angles by the difference in voltage magnitude \(\delta V_{n,t}\) and the series reactance by the series resistance \(r_l\).
Inputs#
For the linear power flow, the following data for each componentare used. For almost all values, defaults are assumed if notexplicitly set. For the defaults and units, see Components.
n.buses.{v_nom}
n.loads.{p_set}
n.generators.{p_set}
n.storage_units.{p_set}
n.stores.{p_set}
n.shunt_impedances.{g}
n.lines.{x}
n.transformers.{x}
n.links.{p_set}
Note
Note that for lines and transformers you must make sure that \(x\) is non-zero, otherwise the bus admittance matrix will be singular.
Outputs#
n.buses.{v_mag_pu, v_ang, p}
n.loads.{p}
n.generators.{p}
n.storage_units.{p}
n.stores.{p}
n.shunt_impedances.{p}
n.lines.{p0, p1}
n.transformers.{p0, p1}
n.links.{p0, p1}