Skip to content
Snippets Groups Projects
Commit 32bcec09 authored by Marc Moritz's avatar Marc Moritz
Browse files

Dummy change for testing of JupyterHub Execution

parent a03be3fb
No related branches found
No related tags found
No related merge requests found
%% Cell type:markdown id:cfe34583 tags:
<style>
/* Set the font for the entire notebook to Times New Roman */
* {
font-family: "Times New Roman", Times, serif;
}
</style>
<div>
<img src="figures/slew_logo.png" style="float: right;height: 15em;">
</div>
# SLEW Case 2 - Electromechanical Dynamics: Small-signal Stability
## Theoretical background
### The Linearized Swing Equation
The swing equation is the fundamental equation that determines the rotor dynamics of a synchronous machine.
$$M\frac{d^{2}\delta}{dt^{2}} = P_{m} - P_{e}(\delta) - D\frac{d\delta}{dt}$$
For small signal stability analysis, the swing equation can be linearized in the vicinity of the operating point $\delta = \delta_{0}$:
$$M\frac{d^{2}\Delta\delta}{dt^{2}} + D\frac{d\Delta\delta}{dt} + K_{e^{'}}\Delta\delta = 0 $$
where $K_{e^{'}}$ is the transient synchronizing power coefficient at $\delta = \delta_{0}$:
$$K_{e^{'}} = \frac{\partial P_{e^{'}}}{\partial \delta^{'}}\mid_{\delta = \delta_{0}}$$
The characteristic equation and the roots of the linearized swing equation are as follows:
$$\lambda^{2} + \frac{D}{M}\lambda + \frac{K_{e^{'}}}{M} = 0 $$
$$\lambda_{1,2} = -\frac{D}{2M} \pm \sqrt{\left(\frac{D}{2M}\right)^{2} - \frac{K_{e^{'}}}{M}} $$
%% Cell type:markdown id:eb59e0e7 tags:
***
## Case description
%% Cell type:markdown id:58c9e2a2 tags:
This is a test change (05.06.2025)
A $200$ MVA round-rotor generator is connected to an infinite bus system of nominal frequency of $50 Hz$ through a step-up transformer with reactance of $0.13 p.u.$ and a transmission line with reactance of $0.17 p.u.$ . The generator’s transient reactance is $x'_{d} = 0.23 p.u.$ and the inertia constant is $H = 4 s$. The synchronous generator mechanical power is set to $0.6 p.u.$ and the steady-state emf $E = 1.1 p.u.$
%% Cell type:markdown id:a6940104 tags:
***
## Case tasks
%% Cell type:markdown id:f3323e4f tags:
#### Task 1
If at the given operating point the system eigen-values are as follows:
$$\lambda_{1,2} = -0.06254 \pm 8.8318j $$
&nbsp;&nbsp;&nbsp;&nbsp;a) Determine whether the system response following a small disturbance is overdamped, critically damped or underdamped.
&nbsp;&nbsp;&nbsp;&nbsp;b) Verify your findings by calculating the damping coefficient *D* (not to be confused with the damping ratio ζ ) of the synchronous generator and then applying the damping value *"D"* in SLEW and generating the corresponding power and angle plots.
#### Task 2
If the system response following a small disturbance is critically damped.
&nbsp;&nbsp;&nbsp;&nbsp;a) Determine the synchronous generator damping coefficient (not to be confused with the damping ratio ζ ).
&nbsp;&nbsp;&nbsp;&nbsp;b) Apply the calculated damping value in SLEW and generate the corresponding power and angle plots.
&nbsp;&nbsp;&nbsp;&nbsp;c) Increase the damping coefficient (not to be confused with the damping ratio ζ ) value further and observe the impact of such increase.
%% Cell type:markdown id:1fc3c700 tags:
**You can process the results from SLEW (as required in 1 and 2) using the prepared notebook cells below.**
%% Cell type:markdown id:9da09483 tags:
***
## Case solutions
%% Cell type:markdown id:d1a0ab6c tags:
#### First Setup your Python for post-processing
%% Cell type:markdown id:8432a231 tags:
Import relevant Python packages by executing the following cell:
%% Cell type:code id:5bb649a9 tags:
``` python
from IPython.display import display
from villas.web.result import Result
from pprint import pprint
import tempfile
import os
from villas.dataprocessing.readtools import *
from villas.dataprocessing.timeseries import *
import matplotlib.pyplot as plt
import scipy.io as sio
outputs = sio.loadmat('outputs/case2_output.mat', simplify_cells=True)
#matplotlib widget
%matplotlib widget
```
%% Cell type:markdown id:290ba8ba tags:
### Task 1
%% Cell type:markdown id:3564b4be tags:
If at the given operating point the system eigen-values are as follows:
$$\lambda_{1,2} = -0.06254 \pm 8.8318j $$
%% Cell type:markdown id:29d31393 tags:
#### a)
Determine whether the system response following a small disturbance is overdamped, critically damped or underdamped.
%% Cell type:code id:e1620ea2 tags:
``` python
import scipy.io
import ipywidgets as widgets
from IPython.display import display, clear_output
# Load the solution from the .mat file
mat_data = scipy.io.loadmat('outputs/case2_output.mat')
correct_answer = mat_data['correct_answer'][0]
# Create a radio button widget for the damping question
radio_btn = widgets.RadioButtons(
options=['Overdamped', 'Critically Damped', 'Underdamped'],
description='Select the correct answer:',
disabled=False
)
# Create an output widget to display the result
output = widgets.Output()
# Function to check the student's answer, display the result, and disable further attempts
def check_answer(b):
with output:
clear_output() # Clear previous output
selected = radio_btn.value
if selected == correct_answer:
print("Your answer is correct! The Eigenvalues are complex conjugate pair with an imaginary part \ineq 0, therefore the system is underdamped.")
else:
print("Incorrect. Try again!")
# Disable the radio buttons and the submit button after the first attempt
#radio_btn.disabled = True
#submit_btn.disabled = True
# Create a button to submit the answer
submit_btn = widgets.Button(description="Submit Answer")
# Link the submit button to the check_answer function
submit_btn.on_click(check_answer)
# Display the radio button, submit button, and output widget
display(radio_btn, submit_btn, output)
```
%% Cell type:markdown id:b08ba784 tags:
#### b)
Verify your findings by calculating the damping coefficient (not to be confused with the damping ratio ζ ) of the synchronous generator and then applying the damping value in SLEW and generating the corresponding power and angle plots.
To check your results, enter your solution for *"D"* rounded to 4 digits after the decimal point:
%% Cell type:code id:4d8c545c tags:
``` python
D=input('D in Subtask 1.b:')
print('Your result is', 'correct!' if round(float(D),4)==round(outputs['D_T1b'],4) else 'incorrect. You should double-check your calculations.')
```
%% Cell type:markdown id:5592eeac tags:
Download simulation results from SLEW
%% Cell type:markdown id:192ea4fa tags:
Enter SLEW under [https://slew.k8s.eonerc.rwth-aachen.de](https://slew.k8s.eonerc.rwth-aachen.de).
Adjust the parameter *"D"* and run a corresponding simulation.
Then, enter your code snippet for result download in the following cell:
%% Cell type:code id:3a922965 tags:
``` python
# Access result using token
r = Result(1, 'xyz', endpoint='https://slew.k8s.eonerc.rwth-aachen.de')
```
%% Cell type:markdown id:7d391ebd tags:
#### Plot the results
%% Cell type:code id:609cbf87 tags:
``` python
results_file_name='SP_SynGenTrStab_SMIB_Fault_SlewCase2_JsonSyngenParams_SP.csv'
# Get file by name
f = r.get_file_by_name(results_file_name)
# Create temp dir
tmpdir = tempfile.mkdtemp()
results_file_path = os.path.join(tmpdir,results_file_name)
# Load files as bytes
f = f.download(dest=results_file_path)
# Get time series object from csv
ts_res1 = read_timeseries_csv(results_file_path, print_status=True)
# Plot the currents
plt.figure(figsize=(8,12))
name_list = ['Rotor Angle','Output Power']
plt.subplot(2,1,1)
plt.ylabel("Angle (degree)")
plt.xlabel("time (s)")
plt.plot(ts_res1['delta_r_gen'].time, ts_res1['delta_r_gen'].values, label='Rotor Angle task 1.b', color='C0')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.subplot(2,1,2)
plt.ylabel("Power (MW)")
plt.xlabel("time (s)")
plt.plot(ts_res1['P_elec'].time, ts_res1['P_elec'].values/1e6, label='Output Power task 1.b', color='C1')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.show()
```
%% Cell type:markdown id:8ef9b8b2 tags:
### Task 2
%% Cell type:markdown id:00d2e239 tags:
If the system response following a small disturbance is critically damped.
%% Cell type:markdown id:b1a6d35b tags:
#### a)
Determine the synchronous generator damping coefficient (not to be confused with the damping ratio ζ ).
To check your results, enter your solution for *"D"* rounded to 4 digits behind the comma:
%% Cell type:code id:e70ae849 tags:
``` python
D=input('D in Subtask 2.a:')
print('Your result is', 'correct!' if round(float(D),4)==round(outputs['D_T2a'],4) else 'incorrect. You should double-check your calculations.')
```
%% Cell type:markdown id:6ab41b23 tags:
#### b)
Apply the calculated damping value in SLEW and generate the corresponding power and angle plots.
Download simulation results from SLEW
%% Cell type:markdown id:5f52f99d tags:
Enter SLEW under [https://slew.k8s.eonerc.rwth-aachen.de](https://slew.k8s.eonerc.rwth-aachen.de).
Adjust the parameter *"D"* and run a corresponding simulation.
Then, enter your code snippet for result download in the following cell:
%% Cell type:code id:921256f6 tags:
``` python
# Access result using token
r = Result(1, 'xyz', endpoint='https://slew.k8s.eonerc.rwth-aachen.de')
```
%% Cell type:markdown id:4d20385b tags:
#### Plot the results
%% Cell type:code id:ba064129 tags:
``` python
results_file_name='SP_SynGenTrStab_SMIB_Fault_SlewCase2_JsonSyngenParams_SP.csv'
# Get file by name
f = r.get_file_by_name(results_file_name)
# Create temp dir
tmpdir = tempfile.mkdtemp()
results_file_path = os.path.join(tmpdir,results_file_name)
# Load files as bytes
f = f.download(dest=results_file_path)
# Get time series object from csv
ts_res2 = read_timeseries_csv(results_file_path, print_status=False)
# Plot the currents
plt.figure(figsize=(8,12))
name_list = ['Rotor Angle','Output Power']
plt.subplot(2,1,1)
plt.ylabel("Angle (degree)")
plt.xlabel("time (s)")
plt.plot(ts_res2['delta_r_gen'].time, ts_res2['delta_r_gen'].values, label='Rotor Angle task 2.b', color='C0')
plt.plot(ts_res1['delta_r_gen'].time, ts_res1['delta_r_gen'].values, label='Rotor Angle task 1.b', color='black', linestyle=':')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.subplot(2,1,2)
plt.ylabel("Power (MW)")
plt.xlabel("time (s)")
plt.plot(ts_res2['P_elec'].time, ts_res2['P_elec'].values/1e6, label='Output Power task 2.b', color='C1')
plt.plot(ts_res1['P_elec'].time, ts_res1['P_elec'].values/1e6, label='Output Power task 1.b', color='black', linestyle=':')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.show()
```
%% Cell type:markdown id:18f20b09 tags:
#### c)
Increase the damping coefficient (not to be confused with the damping ratio ζ ) value (for example by a factor of 2) further and observe the impact of such increase.
Download simulation results from SLEW
%% Cell type:markdown id:4f967ccb tags:
Enter SLEW under [https://slew.k8s.eonerc.rwth-aachen.de](https://slew.k8s.eonerc.rwth-aachen.de).
Adjust the parameter *"D"* and run a corresponding simulation.
Then, enter your code snippet for result download in the following cell:
%% Cell type:code id:79b309eb tags:
``` python
# Access result using token
r = Result(1, 'xyz', endpoint='hhttps://slew.k8s.eonerc.rwth-aachen.de')
```
%% Cell type:markdown id:a4dbb836 tags:
#### Plot the results
%% Cell type:code id:ba53ba36 tags:
``` python
results_file_name='SP_SynGenTrStab_SMIB_Fault_SlewCase2_JsonSyngenParams_SP.csv'
# Get file by name
f = r.get_file_by_name(results_file_name)
# Create temp dir
tmpdir = tempfile.mkdtemp()
results_file_path = os.path.join(tmpdir,results_file_name)
# Load files as bytes
f = f.download(dest=results_file_path)
# Get time series object from csv
ts_res3 = read_timeseries_csv(results_file_path, print_status=False)
# Plot the currents
plt.figure(figsize=(8,12))
name_list = ['Rotor Angle','Output Power']
plt.subplot(2,1,1)
plt.ylabel("Angle (degree)")
plt.xlabel("time (s)")
plt.plot(ts_res3['delta_r_gen'].time, ts_res3['delta_r_gen'].values, label='Rotor Angle task 2.c', color='C0')
plt.plot(ts_res2['delta_r_gen'].time, ts_res2['delta_r_gen'].values, label='Rotor Angle task 2.b', color='black', linestyle=':')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.subplot(2,1,2)
plt.ylabel("Power (MW)")
plt.xlabel("time (s)")
plt.plot(ts_res3['P_elec'].time, ts_res3['P_elec'].values/1e6, label='Output Power task 2.c', color='C1')
plt.plot(ts_res2['P_elec'].time, ts_res2['P_elec'].values/1e6, label='Output Power task 2.b', color='black', linestyle=':')
plt.xlim([1, 30])
plt.legend(loc='upper right')
plt.show()
```
%% Cell type:code id:d74fe01a tags:
``` python
```
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment