-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
384 bug voltage drop should be considered when selecting cable to connect new components #411
Changes from 9 commits
f9972bc
3dc762b
9d0411a
b8a8baa
bab29bc
f31886a
8adc372
a37c4d5
1b2301a
a0f01fb
3a23e5e
6e3cd06
8404748
f1a02e2
9c9f456
bd9c87e
803d796
2115254
e68b601
93e3592
59f12c8
ace46a9
aa49064
0d1683d
095e3d0
2875aa7
ec36c0b
a49d907
4552729
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -193,7 +193,109 @@ def drop_duplicated_columns(df, keep="last"): | |
return df.loc[:, ~df.columns.duplicated(keep=keep)] | ||
|
||
|
||
def select_cable(edisgo_obj, level, apparent_power): | ||
def calculate_voltage_diff_per_line( | ||
s_max: float | np.ndarray, | ||
r_total: float | np.ndarray, | ||
x_total: float | np.ndarray, | ||
v_nom: float | np.ndarray, | ||
sign: int = -1, | ||
cos_phi: float = 0.95, | ||
) -> float | np.ndarray: | ||
""" | ||
Calculate the voltage difference across a line in kV. | ||
|
||
Parameters | ||
---------- | ||
s_max : float or array-like | ||
Apparent power the cable must carry in MVA. | ||
r_total : float or array-like | ||
Total resistance in Ohms. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add "of the line" here, as well as for x_total and v_nom. |
||
x_total : float or array-like | ||
Total reactance in Ohms. | ||
v_nom : float or array-like | ||
Nominal voltage in kV. | ||
sign : int, optional | ||
Sign of the reactance. -1 for inductive and +1 for capacitive. Default is -1. | ||
cos_phi : float, optional | ||
Power factor (cosine of the phase angle) of the load or generator. | ||
Default is 0.95. | ||
|
||
Returns | ||
------- | ||
float or array-like | ||
Voltage difference in kV. | ||
""" | ||
sin_phi = np.sqrt(1 - cos_phi**2) | ||
# Calculate the voltage difference using the formula from VDE-AR-N 4105 | ||
voltage_diff = np.abs( | ||
(s_max * 1e6 / (v_nom * 1e3)) * (r_total * cos_phi + sign * x_total * sin_phi) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please avoid multiplying and dividing unnecessarily due to rounding errors. 1e6/1e3/1e3 all cancels out, so it is not necessary here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, please don't return the absolute value here because it would be better to test, whether the voltage rises or drops. |
||
) # in V | ||
return voltage_diff / 1e3 # Convert to kV | ||
|
||
|
||
def voltage_diff_pu( | ||
R_per_km: float | np.ndarray, | ||
L_per_km: float | np.ndarray, | ||
length: float, | ||
num_parallel: int, | ||
v_nom: float | np.ndarray, | ||
s_max: float | np.ndarray, | ||
cos_phi: float = 0.95, | ||
sign: int = -1, | ||
) -> float | np.ndarray: | ||
""" | ||
Calculate the voltage difference per unit of nominal voltage. | ||
|
||
Parameters | ||
---------- | ||
R_per_km : float or array-like | ||
Resistance per kilometer of the cable in ohm/km. | ||
L_per_km : float or array-like | ||
Inductance per kilometer of the cable in mH/km. | ||
length : float | ||
Length of the cable in km. | ||
num_parallel : int | ||
Number of parallel cables. | ||
v_nom : int | ||
Nominal voltage in kV. | ||
s_max : float | ||
Apparent power the cable must carry in MVA. | ||
cos_phi : float, optional | ||
Cosine phi of the load or generator. Default: 0.95. | ||
sign : int, optional | ||
Sign of the reactance. -1 for inductive and +1 for capacitive. Default is -1. | ||
|
||
Returns | ||
------- | ||
float | ||
Voltage difference in per unit of nominal voltage. | ||
""" | ||
# Calculate total resistance and reactance for the given length and | ||
# number of parallel cables | ||
r_total = calculate_line_resistance(R_per_km, length, num_parallel) | ||
x_total = calculate_line_reactance(L_per_km, length, num_parallel) | ||
|
||
# Calculate the voltage drop or increase | ||
delta_v = calculate_voltage_diff_per_line( | ||
s_max, r_total, x_total, v_nom, sign=sign, cos_phi=cos_phi | ||
) | ||
|
||
# Convert voltage difference to per unit of nominal voltage | ||
voltage_difference_pu = delta_v / v_nom | ||
|
||
return voltage_difference_pu | ||
|
||
|
||
def select_cable( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please adapt the docstring of this function. The cable is not only selected based on the apparent power anymore but also considering the voltage deviation over the cable. The docstring should always start with a short one line description and then in the next paragraph it can be elaborated if needed. |
||
edisgo_obj: EDisGo, | ||
level: str, | ||
apparent_power: float, | ||
length: float = 0, | ||
max_voltage_diff: float | None = None, | ||
max_cables: int = 7, | ||
cos_phi: float | None = 0.95, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please rename this parameter to power_factor to have it consistent with the rest of the code base. Also, I would prefer that there is no default value but that the default value is obtained from the configs. For this, the type of the component to be connected needs to be specified as input parameter. |
||
inductive_reactance: bool = True, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please use "reactive_power_mode" instead of "inductive_reactance" to have it consistent with the rest of the code base, e.g. here). Also, whether the reactive power is positive or negative in case of inductive behavior depends on the sign convention used. In eDisGo we use the generator sign convention for generators and storage units and the load sign convention for loads. This also needs to be fixed in the other functions. |
||
) -> tuple[pd.Series, int]: | ||
""" | ||
Selects suitable cable type and quantity using given apparent power. | ||
|
||
|
@@ -209,6 +311,17 @@ def select_cable(edisgo_obj, level, apparent_power): | |
'lv'. | ||
apparent_power : float | ||
Apparent power the cable must carry in MVA. | ||
length : float | ||
Length of the cable in km. Default: 0. | ||
max_voltage_diff : float | ||
Maximum voltage difference in pu. Default: None. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please elaborate this a bit more. It is the maximum allowed voltage difference over the line that connects the new component to the grid. If it is not specified, it is taken from the config files (section grid_connection, parameters lv_max_voltage_deviation and mv_max_voltage_deviation). |
||
max_cables : int | ||
Maximum number of parallel cables to consider. Default is 7. | ||
cos_phi : float | ||
Cosine phi of the load or generator. Default: 0.95. | ||
inductive_reactance : bool | ||
If True, inductive reactance is considered. Default | ||
is True. If False, capacitive reactance is considered. | ||
|
||
Returns | ||
------- | ||
|
@@ -219,39 +332,76 @@ def select_cable(edisgo_obj, level, apparent_power): | |
Number of necessary parallel cables. | ||
|
||
""" | ||
|
||
cable_count = 1 | ||
|
||
if not cos_phi: | ||
cos_phi = 0.95 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not necessary because 0.95 is already the default value in the function head. |
||
if inductive_reactance: | ||
sign = -1 | ||
else: | ||
sign = 1 | ||
if level == "mv": | ||
cable_data = edisgo_obj.topology.equipment_data["mv_cables"] | ||
available_cables = cable_data[ | ||
cable_data["U_n"] == edisgo_obj.topology.mv_grid.nominal_voltage | ||
] | ||
if not max_voltage_diff: | ||
max_voltage_diff = edisgo_obj.config["grid_connection"][ | ||
"mv_max_voltage_deviation" | ||
] | ||
elif level == "lv": | ||
available_cables = edisgo_obj.topology.equipment_data["lv_cables"] | ||
if not max_voltage_diff: | ||
max_voltage_diff = edisgo_obj.config["grid_connection"][ | ||
"lv_max_voltage_deviation" | ||
] | ||
else: | ||
raise ValueError( | ||
"Specified voltage level is not valid. Must either be 'mv' or 'lv'." | ||
) | ||
|
||
cable_count = 1 | ||
suitable_cables = available_cables[ | ||
calculate_apparent_power( | ||
available_cables["U_n"], available_cables["I_max_th"], cable_count | ||
) | ||
> apparent_power | ||
] | ||
if length != 0: | ||
suitable_cables = suitable_cables[ | ||
voltage_diff_pu( | ||
R_per_km=available_cables["R_per_km"], | ||
L_per_km=available_cables["L_per_km"], | ||
length=length, | ||
num_parallel=cable_count, | ||
v_nom=available_cables["U_n"], | ||
s_max=apparent_power, | ||
cos_phi=cos_phi, | ||
sign=sign, | ||
) | ||
< max_voltage_diff | ||
] | ||
|
||
# increase cable count until appropriate cable type is found | ||
while suitable_cables.empty and cable_count < 7: | ||
while suitable_cables.empty and cable_count < max_cables: # parameter | ||
cable_count += 1 | ||
suitable_cables = available_cables[ | ||
calculate_apparent_power( | ||
available_cables["U_n"], | ||
available_cables["I_max_th"], | ||
cable_count, | ||
available_cables["U_n"], available_cables["I_max_th"], cable_count | ||
) | ||
> apparent_power | ||
] | ||
if length != 0: | ||
suitable_cables = suitable_cables[ | ||
voltage_diff_pu( | ||
R_per_km=available_cables["R_per_km"], | ||
L_per_km=available_cables["L_per_km"], | ||
length=length, | ||
num_parallel=cable_count, | ||
v_nom=available_cables["U_n"], | ||
s_max=apparent_power, | ||
cos_phi=cos_phi, | ||
sign=sign, | ||
) | ||
< max_voltage_diff | ||
] | ||
if suitable_cables.empty: | ||
raise exceptions.MaximumIterationError( | ||
"Could not find a suitable cable for apparent power of " | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please add the comment above the value it applies to?