@@ -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