Skip to content

Commit 841e389

Browse files
committed
fix: fix stability limit and mark user susceptance
1 parent 40462e2 commit 841e389

File tree

1 file changed

+52
-36
lines changed

1 file changed

+52
-36
lines changed

src/pownet/core/data_processor.py

Lines changed: 52 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -86,40 +86,46 @@ def calc_stability_limit(
8686
source_kv: int,
8787
sink_kv: int,
8888
distance: float,
89-
wavelength: int,
9089
n_circuits: int,
9190
) -> float:
92-
"""This function calculates the steady-state stability limit of a transmission line.
93-
From Chapter 5 of Power System Analysis and Design 5th (EQ 5.4.30)
91+
"""Calculates the theoretical steady-state stability limit of a transmission line.
92+
93+
This function uses the fundamental power transfer formula based on total line
94+
reactance, as shown in "Power System Analysis and Design" (Eq. 5.4.27):
9495
95-
The stability limit per circuit is given by:
96-
97-
P = V1 * V2 / X * sin(2 * pi * d / lambda)
96+
P_max = (V_S * V_R) / X'
9897
9998
where:
100-
P is the stability limit in MW
101-
V1 and V2 are the voltages at the two ends of the line
102-
X is the reactance of the line in ohms per km
103-
d is the distance between the two ends of the line in km
104-
lambda is the wavelength of the system in km
99+
P_max is the stability limit in MW.
100+
V_S and V_R are the sending and receiving end voltages in kV.
101+
X' is the total line reactance in ohms.
105102
106103
Args:
107-
source_kv (int): Voltage level of the source bus
108-
sink_kv (int): Voltage level of the sink bus
109-
distance (float): Distance between the two buses in km
110-
wavelength (int): Wavelength of the system in km
111-
n_circuits (int): Number of circuits in the transmission line
104+
source_kv (int): Voltage level of the source bus in kV.
105+
sink_kv (int): Voltage level of the sink bus in kV.
106+
distance (float): Distance between the two buses in km.
107+
n_circuits (int): Number of circuits in the transmission line.
112108
113109
Returns:
114-
float: The stability limit of the transmission line in MW
110+
float: The stability limit of the transmission line in MW.
115111
"""
116-
# The reactance of the line is a function of the maximum voltage level
117-
# of the two buses.
112+
# Get the reactance per kilometer for the line's voltage level.
118113
max_kv = max(source_kv, sink_kv)
119114
reactance_per_km = self.transmission_params["reactance_ohms_per_km"][max_kv]
120-
# Calculate the Surge Impedance Limit (SIL)
121-
sil = source_kv * sink_kv / reactance_per_km / 1000 # Divide by 1000 to get MW
122-
stability_limit_per_circuit = sil / np.sin(2 * np.pi * distance / wavelength)
115+
116+
# 1. Calculate the TOTAL line reactance.
117+
total_reactance = reactance_per_km * distance
118+
119+
# Avoid division by zero for co-located buses (distance = 0).
120+
if total_reactance == 0:
121+
return float('inf')
122+
123+
# 2. Calculate the stability limit per circuit.
124+
# The result is in MW because (kV * kV) / ohms = MVA. We assume a
125+
# power factor of 1 (MW = MVA).
126+
stability_limit_per_circuit = (source_kv * sink_kv) / total_reactance
127+
128+
# 3. Return the total limit for all circuits.
123129
return int(n_circuits * stability_limit_per_circuit)
124130

125131
def calc_thermal_limit(
@@ -162,7 +168,6 @@ def calc_line_capacity(self) -> None:
162168
x["source_kv"],
163169
x["sink_kv"],
164170
x["distance"],
165-
self.wavelength,
166171
x["n_circuits"],
167172
),
168173
axis=1,
@@ -196,6 +201,10 @@ def calc_line_capacity(self) -> None:
196201

197202
def calc_line_susceptance(self) -> None:
198203
"""Calculate the susceptance of line segments. The unit is in Siemens (S)."""
204+
205+
# TODO: This is a misnomer as we are calculating the maximum power that
206+
# can be transferred over the line, not the susceptance.
207+
199208
# Assume reactance based on the maximum voltage level of the two buses
200209
self.transmission_data["max_kv"] = self.user_transmission.apply(
201210
lambda x: max(x["source_kv"], x["sink_kv"]), axis=1
@@ -216,19 +225,26 @@ def calc_line_susceptance(self) -> None:
216225
axis=1,
217226
)
218227

219-
# Replace with user-specified values
220-
excluded_values = [-1, None]
221-
user_specified_susceptance = self.user_transmission.loc[
222-
~self.user_transmission["user_susceptance"].isin(excluded_values),
223-
["source", "sink", "user_susceptance"],
224-
]
225-
user_specified_susceptance = user_specified_susceptance.set_index(
226-
["source", "sink"]
227-
)
228-
# Change from float to int
229-
user_specified_susceptance = user_specified_susceptance.astype(
230-
{"user_susceptance": int}
231-
)
228+
# Raise an error if there are other values other than -1 or None
229+
if not self.user_transmission["user_susceptance"].isin([-1, None]).all():
230+
raise ValueError(
231+
"Currently does not support user specified susceptance values."
232+
)
233+
234+
# TODO: Revise the following code
235+
# # Replace with user-specified values
236+
# excluded_values = [-1, None]
237+
# user_specified_susceptance = self.user_transmission.loc[
238+
# ~self.user_transmission["user_susceptance"].isin(excluded_values),
239+
# ["source", "sink", "user_susceptance"],
240+
# ]
241+
# user_specified_susceptance = user_specified_susceptance.set_index(
242+
# ["source", "sink"]
243+
# )
244+
# # Change from float to int
245+
# user_specified_susceptance = user_specified_susceptance.astype(
246+
# {"user_susceptance": int}
247+
# )
232248

233249
self.transmission_data = self.transmission_data.set_index(["source", "sink"])
234250
self.transmission_data.update(user_specified_susceptance)

0 commit comments

Comments
 (0)