diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/buses.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/buses.csv new file mode 100644 index 0000000..3817d3d --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/buses.csv @@ -0,0 +1,3 @@ +name,base_power_MVA,base_voltage_kV,base_frequency_Hz,minimum_voltage_pu,maximum_voltage_pu +lima,1.00E+02,2.30E+02,60,0.95,1.05 +santiago,1.00E+02,2.30E+02,60,0.95,1.05 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/gfli_e.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/gfli_e.csv new file mode 100755 index 0000000..8bdc652 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/gfli_e.csv @@ -0,0 +1,2 @@ +name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,rf1_pu,lf1_pu,rsh_pu,csh_pu,txr_power_MVA,txr_voltage1_kV,txr_voltage2_kV,txr_r1_pu,txr_l1_pu,txr_r2_pu,txr_l2_pu,beta,kp_pll_pu,ki_pll_puHz,kp_cc_pu,ki_cc_puHz,v_dc_ref,c_dc,kp_oc_pu,ki_oc_puHz,Tload,r_dc +solar,santiago,50,50,-10,10,1.00E+02,4.80E-01,60,0,0.02,0.1,10,1,1.00E+02,4.80E-01,2.30E+02,0.01,0.1,0.02,0.1,0,1,5,1,5,1,20,0.01,0,0.01,10 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/infinite_sources.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/infinite_sources.csv new file mode 100644 index 0000000..fed2eb7 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/infinite_sources.csv @@ -0,0 +1,2 @@ +name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,r_pu,x_pu +gen1,lima,-200,200,-500,500,1.00E+02,2.30E+02,60,0,0.01,0.04 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/lines.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/lines.csv new file mode 100644 index 0000000..b74276c --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/lines.csv @@ -0,0 +1,2 @@ +name,from_bus,to_bus,base_power_MVA,base_voltage_kV,base_frequency_Hz,r_pu,x_pu,g_pu,b_pu +tx_1,lima,santiago,1.00E+02,2.30E+02,60,0.01,0.2,0.05,0.066666667 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/loads.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/loads.csv new file mode 100644 index 0000000..79d806e --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/loads.csv @@ -0,0 +1,3 @@ +bus,timepoint,load_MW,load_MVAR +lima,t_1,0,0 +chile,t_1,0,0 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/timepoints.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/timepoints.csv new file mode 100644 index 0000000..ad319a5 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/inputs/timepoints.csv @@ -0,0 +1,2 @@ +name +timepoint_1 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/active_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/active_power_balance_by_bus.csv new file mode 100644 index 0000000..6c7977c --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/active_power_balance_by_bus.csv @@ -0,0 +1,3 @@ +bus,timepoint,generator_dispatch_MW,load_shedding_MW,load_MW,net_line_leaving_flow_MW +lima,timepoint_1,-39.80828383129473,-9.974940963696508e-9,0.0,-39.808283840763764 +santiago,timepoint_1,50.0,-9.97494096379835e-9,0.0,49.999999989909305 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/bus_voltage.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/bus_voltage.csv new file mode 100644 index 0000000..66021f4 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/bus_voltage.csv @@ -0,0 +1,3 @@ +id,bus,timepoint,voltage_magnitude_pu,voltage_angle_deg +0,lima,timepoint_1,0.9943823157326167,0.0 +1,santiago,timepoint_1,1.0045025151823652,5.136441290604731 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/costs_summary.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/costs_summary.csv new file mode 100644 index 0000000..6ef2ea8 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/costs_summary.csv @@ -0,0 +1,2 @@ +component,cost +total_cost_USD,-0.00003989976385267742 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/generator_dispatch.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/generator_dispatch.csv new file mode 100644 index 0000000..9a20949 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/generator_dispatch.csv @@ -0,0 +1,3 @@ +id,type,generator,timepoint,active_power_MW,reactive_power_MVAR +0,infinite_sources,gen1,timepoint_1,-39.80828383129473,-7.380487609970588 +0,gfli_e,solar,timepoint_1,50.0,-1.8861486979909645 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/line_flows.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/line_flows.csv new file mode 100644 index 0000000..8f4a02e --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/line_flows.csv @@ -0,0 +1,2 @@ +line,from_bus,to_bus,existing_capacity_MW,active_power_from_bus_MW,reactive_power_from_bus_MVAR,active_power_to_bus_MW,reactive_power_to_bus_MVAR,active_power_loss_MW,reactive_power_loss_MVAR +tx_1,lima,santiago,inf,-39.80828384076382,-7.380487617787122,49.9999999899092,-1.8861487031750395,10.191716149145378,-9.266636320962162 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/load_shedding.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/load_shedding.csv new file mode 100644 index 0000000..ffef917 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/load_shedding.csv @@ -0,0 +1,3 @@ +bus,timepoint,active_load_shedding_MW,reactive_load_shedding_MVAR +lima,timepoint_1,-9.974940963696508e-9,-9.974940964376057e-9 +santiago,timepoint_1,-9.97494096379835e-9,-9.974940960806504e-9 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv new file mode 100644 index 0000000..fb89795 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv @@ -0,0 +1,3 @@ +bus,timepoint,generator_dispatch_MVAR,load_shedding_MVAR,load_MVAR,net_line_leaving_flow_MVAR +lima,timepoint_1,-7.380487609970588,-9.974940964376057e-9,0.0,-7.380487617787122 +santiago,timepoint_1,-1.8861486979909645,-9.974940960806504e-9,0.0,-1.8861487031749502 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/solver_status.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/solver_status.csv new file mode 100644 index 0000000..61ad3cd --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/ac_power_flow/solver_status.csv @@ -0,0 +1,5 @@ +attribute,value +solver_name,ipopt +solver_status,ok +termination_condition,optimal +time_spent_seconds,0.06075906753540039 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/F.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/F.csv new file mode 100644 index 0000000..25ec4a0 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/F.csv @@ -0,0 +1,18 @@ +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfli_e_0', 'i_bus_D')","('gfli_e_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'v_ref_d')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_ref_q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'v_dc_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_load_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_bus_q_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('gfli_e_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/G.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/G.csv new file mode 100644 index 0000000..c46e286 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/G.csv @@ -0,0 +1,18 @@ +Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","('gfli_e_0', 'v_dc_ref')","('gfli_e_0', 'i_load_ref')","('gfli_e_0', 'i_bus_q_ref')" +"('infinite_sources_0', 'v_ref_d')",1.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_ref_q')",0.0,1.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'v_dc_ref')",0.0,0.0,1.0,0.0,0.0 +"('gfli_e_0', 'i_load_ref')",0.0,0.0,0.0,1.0,0.0 +"('gfli_e_0', 'i_bus_q_ref')",0.0,0.0,0.0,0.0,1.0 +"('gfli_e_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/H.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/H.csv new file mode 100644 index 0000000..d2f1694 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/H.csv @@ -0,0 +1,11 @@ +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfli_e_0', 'i_bus_D')","('gfli_e_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/L.csv b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/L.csv new file mode 100644 index 0000000..95c81c6 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/outputs/component_connection_matrices/L.csv @@ -0,0 +1,11 @@ +Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","('gfli_e_0', 'v_dc_ref')","('gfli_e_0', 'i_load_ref')","('gfli_e_0', 'i_bus_q_ref')" +"('infinite_sources_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('gfli_e_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfli_e/run.py b/examples/small_signal_and_emt/2-bus-src-gfli_e/run.py new file mode 100644 index 0000000..9bb1cf4 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfli_e/run.py @@ -0,0 +1,62 @@ + +# Import Python standard and third-party packages +from pathlib import Path +from scipy.linalg import eig, inv +import matplotlib.pyplot as plt +import sys +import seaborn as sns +import pandas as pd +import numpy as np +import os +from plotly.subplots import make_subplots +import plotly.graph_objects as go + +sys.path.append("/Users/ruthkravis/Documents/STING") +# Import sting package +from sting import main +from sting.system.core import System +from scipy import signal + + + +# Step-change input to applied to the system +def step1(t): + return 0.2 if t >= 0.2 else 0.0 + +def step2(t): + return 0.0 + +def step3(t): + return 0.1 if t >= 1.0 else 0.0 + + +def sin_oscillation(t): + return 0.05*np.sin(2*np.pi*20*t) if t < 1 else 0 #1 Hz oscillation + +def square_oscillation(t): + osc = 0.05*signal.square(2 * np.pi * 14 * t) + return osc + +inputs = { + 'infinite_sources_0': { + 'v_ref_d': step1 + }, + 'gfli_e_0': { + 'i_load_ref': step2 + } + } + +t_max = 1.0 # Simulation length (in seconds) + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model +sys = System.from_csv(case_directory=case_dir) + +# Construct system and small-signal model +_, ssm = main.run_ssm(case_directory=case_dir) +ssm.simulate_ssm(t_max=t_max, inputs=inputs) +main.run_emt(case_directory=case_dir, inputs=inputs, t_max=t_max) + +print('\nok') \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_analysis.py b/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_analysis.py new file mode 100644 index 0000000..d7b8887 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_analysis.py @@ -0,0 +1,202 @@ +""" + +Analysis of EMT response of GFMI_E v INF bus system to a grid disturbance under different P/Q and different Pref/Pload relationships + +In progress - April 3 (Ruth) + +""" + +# Import Python standard and third-party packages +from pathlib import Path +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +# Import sting package +from sting.system.core import System +from sting.system.operations import SystemModifier +from sting.modules.power_flow.core import ACPowerFlow +from sting.modules.simulation_emt.core import SimulationEMT +from sting.modules.small_signal_modeling.core import SmallSignalModel + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model +def step1(t): + return 0.3 if t >= 0.5 else 0.0 + +def step2(t): + return 0.0 + +def step3(t): + return 0.1 if t > 1.0 else 0.0 + +inputs = {'infinite_sources_0': {'v_ref_d': step1}, + 'gfmi_e_0': {'p_ref': step2, + 'q_ref': step2, + 'v_ref': step2, + 'v_dc_ref': step2, + 'v_s': step2, + 'i_load_ref': step2}} + +t_max = 2.0 + +# Load system from CSV files +sys = System.from_csv(case_directory=case_dir) + +n = 3 +Prange = np.linspace(100,0,n) +Qrange = np.linspace(-50,50,n) + +Sbase = 100 # MVA +vdc_ref = 1.05 # pu + +tps = np.linspace(0, t_max, 500) +dt = tps[1] - tps[0] + +def run_sim(sys, P, Q, Sbase, vdc_ref, factor): + sys.gfmi_e[0].minimum_active_power_MW = -P*factor + sys.gfmi_e[0].maximum_active_power_MW = -P*factor + sys.gfmi_e[0].minimum_reactive_power_MVAR = Q + sys.gfmi_e[0].maximum_reactive_power_MVAR = Q + sys.gfmi_e[0].i_load_ref = P/Sbase/vdc_ref + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + emt_sc = SimulationEMT(system=sys) + emt_sc.sim(t_max, inputs) + return emt_sc + + +# Case 1: Pref = Pload +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 1.0) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_e[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results +fig, axes = plt.subplots(nrows=2,ncols=3, figsize=(30,15)) + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,1], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,1].set_xlabel("Q_sh") +axes[0,1].set_ylabel("P_load") +axes[0,1].set_title("Pref = Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,1], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,1].set_xlabel("Q_sh") +axes[1,1].set_ylabel("P_load") +axes[1,1].set_title("Pref = Pload") + + +# Case 2: Pref < Pload (Pref=0.8*Pload) + +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 0.8) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_e[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,0], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,0].set_xlabel("Q_sh") +axes[0,0].set_ylabel("P_load") +axes[0,0].set_title("Pref = 0.8*Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,0], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,0].set_xlabel("Q_sh") +axes[1,0].set_ylabel("P_load") +axes[1,0].set_title("Pref = 0.8*Pload") + + +# Case 3: Pref > Pload (Pref=1.2*Pload) + +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 1.2) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_e[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,2], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,2].set_xlabel("Q_sh") +axes[0,2].set_ylabel("P_load") +axes[0,2].set_title("Pref = 1.2*Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,2], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,2].set_xlabel("Q_sh") +axes[1,2].set_ylabel("P_load") +axes[1,2].set_title("Pref = 1.2*Pload") + +plt.show() +plt.savefig(str(case_dir)+"/emt_heatmaps.png") + +print('ok') \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_heatmaps.png b/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_heatmaps.png new file mode 100644 index 0000000..3855df0 Binary files /dev/null and b/examples/small_signal_and_emt/2-bus-src-gfmi_e/emt_heatmaps.png differ diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/inputs/gfmi_e.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/inputs/gfmi_e.csv index 8ae66d8..5e0b55d 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/inputs/gfmi_e.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/inputs/gfmi_e.csv @@ -1,2 +1,2 @@ -name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,rf1_pu,xf1_pu,rsh_pu,csh_pu,txr_power_MVA,txr_voltage1_kV,txr_voltage2_kV,txr_r1_pu,txr_x1_pu,txr_r2_pu,txr_x2_pu,h_s,kd_pu,droop_q_pu,tau_pc_s,kp_vc_pu,ki_vc_puHz,kp_v_dc,ki_v_dc,kp_i_L,ki_i_L,l_dc,c_dc,v_dc_ref,v_s,Ti_L,Tv_dc,Ti_dc,Kff_idc,Kff_iload,Ti_load,Tload,i_load_ref -solar,santiago,-10,-10,0,0,1.00E+02,4.80E-01,60,0,0.01,0.1,10000,0.1,1.00E+02,4.80E-01,2.30E+02,0.01,0.1,0.02,0.1,0.5,70,0.01,0.001,1,10,1.2,20,1,10,1,20,1.0,0.5,0.01,0.01,0.01,1,1,0.01,0.001,0.1 \ No newline at end of file +name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,rf1_pu,xf1_pu,rsh_pu,csh_pu,txr_power_MVA,txr_voltage1_kV,txr_voltage2_kV,txr_r1_pu,txr_x1_pu,txr_r2_pu,txr_x2_pu,h_s,kd_pu,droop_q_pu,tau_pc_s,kp_vc_pu,ki_vc_puHz,kp_v_dc,ki_v_dc,kp_i_L,ki_i_L,l_dc,c_dc,v_dc_ref,v_s,Ti_L,Tv_dc,Ti_dc,Kff_idc,Kff_iload,Ti_load,Tload,i_load_ref,Pbat_max_pu,SOC_max_pu,SOC_init_pu +solar,santiago,-50,-50,-10,10,1.00E+02,4.80E-01,60,0,0.02,0.1,10,1,1.00E+02,4.80E-01,2.30E+02,0.01,0.1,0.02,0.1,0.5,70,0.01,0.001,1,10,1.2,20,1,10,0.1,20,1.05,0.5,0.01,0.01,0.01,1,1,0.01,0.001,0.5,1.5,0.25,0.125 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/active_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/active_power_balance_by_bus.csv index c0a07a8..43499bd 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/active_power_balance_by_bus.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/active_power_balance_by_bus.csv @@ -1,3 +1,3 @@ bus,timepoint,generator_dispatch_MW,load_shedding_MW,load_MW,net_line_leaving_flow_MW -lima,timepoint_1,20.024029596964457,-9.99090909090909e-9,0.0,20.024029586973448 -santiago,timepoint_1,-10.0,-9.990909090909092e-9,0.0,-10.000000009990726 +lima,timepoint_1,60.31569213226618,-9.974940964403198e-9,0.0,60.31569212229119 +santiago,timepoint_1,-50.0,-9.974940964403193e-9,0.0,-50.00000000997488 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/bus_voltage.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/bus_voltage.csv index 753a447..d17c3a2 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/bus_voltage.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/bus_voltage.csv @@ -1,3 +1,3 @@ id,bus,timepoint,voltage_magnitude_pu,voltage_angle_deg -0,lima,timepoint_1,0.9850307325446462,0.0 -1,santiago,timepoint_1,1.0144691438583457,-4.385666517431731 +0,lima,timepoint_1,1.0039676883731015,0.0 +1,santiago,timepoint_1,0.9966223958255749,-15.986449720491722 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/costs_summary.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/costs_summary.csv index 6122372..22bb914 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/costs_summary.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/costs_summary.csv @@ -1,2 +1,2 @@ component,cost -total_cost_USD,-0.00003996363636363637 +total_cost_USD,-0.00003989976385761279 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/generator_dispatch.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/generator_dispatch.csv index c8329f2..22fa1bb 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/generator_dispatch.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/generator_dispatch.csv @@ -1,3 +1,3 @@ id,type,generator,timepoint,active_power_MW,reactive_power_MVAR -0,infinite_sources,gen1,timepoint_1,20.024029596964457,-11.986372758049026 -0,gfmi_e,solar,timepoint_1,-10.0,0.0 +0,infinite_sources,gen1,timepoint_1,60.31569213226618,1.388783529105015 +0,gfmi_e,solar,timepoint_1,-50.0,0.7526101226466527 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/line_flows.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/line_flows.csv index efe99e5..6eac7b5 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/line_flows.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/line_flows.csv @@ -1,2 +1,2 @@ line,from_bus,to_bus,existing_capacity_MW,active_power_from_bus_MW,reactive_power_from_bus_MVAR,active_power_to_bus_MW,reactive_power_to_bus_MVAR,active_power_loss_MW,reactive_power_loss_MVAR -tx_1,lima,santiago,inf,20.02402958697347,-11.986372768040068,-10.000000009990744,-9.99095410228382e-9,10.024029576982725,-11.986372778031022 +tx_1,lima,santiago,inf,60.31569212229122,1.3887835191300466,-50.00000000997491,0.7526101126717135,10.315692112316306,2.14139363180176 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/load_shedding.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/load_shedding.csv index 8c5a706..2061806 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/load_shedding.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/load_shedding.csv @@ -1,3 +1,3 @@ bus,timepoint,active_load_shedding_MW,reactive_load_shedding_MVAR -lima,timepoint_1,-9.99090909090909e-9,-9.99090909090909e-9 -santiago,timepoint_1,-9.990909090909092e-9,-9.990909090909097e-9 +lima,timepoint_1,-9.974940964403198e-9,-9.9749409644032e-9 +santiago,timepoint_1,-9.974940964403193e-9,-9.97494096440319e-9 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv index 726b458..1f256f2 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/reactive_power_balance_by_bus.csv @@ -1,3 +1,3 @@ bus,timepoint,generator_dispatch_MVAR,load_shedding_MVAR,load_MVAR,net_line_leaving_flow_MVAR -lima,timepoint_1,-11.986372758049026,-9.99090909090909e-9,0.0,-11.986372768040068 -santiago,timepoint_1,0.0,-9.990909090909097e-9,0.0,-9.990909050803768e-9 +lima,timepoint_1,1.388783529105015,-9.9749409644032e-9,0.0,1.3887835191300466 +santiago,timepoint_1,0.7526101226466527,-9.97494096440319e-9,0.0,0.7526101126717357 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/solver_status.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/solver_status.csv index 6b473ea..9d22778 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/solver_status.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/ac_power_flow/solver_status.csv @@ -2,4 +2,4 @@ attribute,value solver_name,ipopt solver_status,ok termination_condition,optimal -time_spent_seconds,0.9590749740600586 +time_spent_seconds,0.11365103721618652 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/F.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/F.csv index e41178d..435c050 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/F.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/F.csv @@ -1,4 +1,4 @@ -Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_e_0', 'i_bus_D')","('gfmi_e_0', 'i_bus_Q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_e_0', 'i_bus_D')","('gfmi_e_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" "('infinite_sources_0', 'v_ref_d')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'v_ref_q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 @@ -11,11 +11,11 @@ Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","( "('gfmi_e_0', 'i_load_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 "('gfmi_e_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('pa_rc_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0 -"('pa_rc_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0 -"('pa_rc_1', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('pa_rc_1', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0 -"('se_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/G.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/G.csv index 72d52df..9d27ee0 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/G.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/G.csv @@ -11,11 +11,11 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('gfmi_e_0', 'i_load_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 "('gfmi_e_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/H.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/H.csv index ba4ffa4..1358a61 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/H.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/H.csv @@ -1,11 +1,11 @@ -Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_e_0', 'i_bus_D')","('gfmi_e_0', 'i_bus_Q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_e_0', 'i_bus_D')","('gfmi_e_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" "('infinite_sources_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/L.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/L.csv index aa2b8d8..5b2598d 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/L.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/component_connection_matrices/L.csv @@ -3,9 +3,9 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('infinite_sources_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/A.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/A.csv index dd0ac99..84befb8 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/A.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/A.csv @@ -1,29 +1,29 @@ -Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_e_0', 'angle_pc')","('gfmi_e_0', 'w_pc')","('gfmi_e_0', 'p_pc')","('gfmi_e_0', 'q_pc')","('gfmi_e_0', 'pi_vc')","('gfmi_e_0', 'i_vsc_d')","('gfmi_e_0', 'i_vsc_q')","('gfmi_e_0', 'i_bus_d')","('gfmi_e_0', 'i_bus_q')","('gfmi_e_0', 'v_lcl_sh_d')","('gfmi_e_0', 'v_lcl_sh_q')","('gfmi_e_0', 'i_l_f')","('gfmi_e_0', 'v_dc_f')","('gfmi_e_0', 'i_dc_f')","('gfmi_e_0', 'i_load_f')","('gfmi_e_0', 'x_1')","('gfmi_e_0', 'x_2')","('gfmi_e_0', 'i_L')","('gfmi_e_0', 'v_dc')","('gfmi_e_0', 'i_load')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" -"('infinite_sources_0', 'i_bus_d')",-7.5398223686155035,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-749.3755584175443,-83.21950461965382,0.0,0.0,0.0,0.0 -"('infinite_sources_0', 'i_bus_q')",-376.99111843077515,-7.5398223686155035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,83.21950461965382,-749.3755584175443,0.0,0.0,0.0,0.0 +Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_e_0', 'angle_pc')","('gfmi_e_0', 'w_pc')","('gfmi_e_0', 'p_pc')","('gfmi_e_0', 'q_pc')","('gfmi_e_0', 'pi_vc')","('gfmi_e_0', 'i_vsc_d')","('gfmi_e_0', 'i_vsc_q')","('gfmi_e_0', 'i_bus_d')","('gfmi_e_0', 'i_bus_q')","('gfmi_e_0', 'v_lcl_sh_d')","('gfmi_e_0', 'v_lcl_sh_q')","('gfmi_e_0', 'i_l_f')","('gfmi_e_0', 'v_dc_f')","('gfmi_e_0', 'i_dc_f')","('gfmi_e_0', 'i_load_f')","('gfmi_e_0', 'x_1')","('gfmi_e_0', 'x_2')","('gfmi_e_0', 'i_L')","('gfmi_e_0', 'v_dc')","('gfmi_e_0', 'i_load')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'i_bus_d')",-7.5398223686155035,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-723.1203801581415,-213.50908482472548,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_q')",-376.99111843077515,-7.5398223686155035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,213.50908482472548,-723.1203801581415,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'angle_pc')",0.0,0.0,0.0,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'w_pc')",0.0,0.0,0.0,-70.0,-1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'p_pc')",0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,0.0,1011.6644575859594,8.949041881888602,-98.5341583153472,-2.792568273869858,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'q_pc')",0.0,0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,8.949041881888602,-1011.6644575859594,2.792568273869858,-98.5341583153472,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'pi_vc')",0.0,0.0,0.0,0.0,0.0,-0.1,0.0,0.0,0.0,0.0,0.0,-9.999608776788051,-0.08845513655734374,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_vsc_d')",0.0,0.0,0.0,37.086415468269735,0.0,-37.69911184307752,3769.9111843077517,-37.69911184307751,376.99111843077515,0.0,0.0,-7539.674880939275,-33.34680086169996,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_vsc_q')",0.0,0.0,0.0,37.44573462619731,0.0,0.0,0.0,-376.99111843077515,-37.69911184307751,0.0,0.0,0.0,-3769.9111843077517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_bus_d')",0.0,0.0,-54.17296510215203,-1.052773436860497,0.0,0.0,0.0,0.0,0.0,-56.54866776461627,376.99111843077515,1884.9555921538758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1874.5984341253277,197.32788745394876,0.0,0.0 -"('gfmi_e_0', 'i_bus_q')",0.0,0.0,1911.4617786551519,37.1465025469378,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-56.54866776461627,0.0,1884.9555921538758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-197.32788745394876,-1874.5984341253277,0.0,0.0 -"('gfmi_e_0', 'v_lcl_sh_d')",0.0,0.0,0.0,3.3737093079370326,0.0,0.0,0.0,3769.9111843077517,0.0,-3769.9111843077517,0.0,-0.37699111843077515,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'v_lcl_sh_q')",0.0,0.0,0.0,-381.3885153419943,0.0,0.0,0.0,0.0,3769.9111843077517,0.0,-3769.9111843077517,-376.99111843077515,-0.37699111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'p_pc')",0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,0.0,987.9260565411992,23.78030884341824,-496.76780316078685,-70.54199784602056,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'q_pc')",0.0,0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,23.78030884341824,-987.9260565411992,70.54199784602056,-496.76780316078685,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'pi_vc')",0.0,0.0,0.0,0.0,0.0,-0.1,0.0,0.0,0.0,0.0,0.0,-9.997104207562575,-0.24063969567519944,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_vsc_d')",0.0,0.0,0.0,346.7421388408102,0.0,-37.69911184307752,3769.9111843077517,-75.39822368615502,376.99111843077515,0.0,0.0,-7538.730680585775,-90.71902801143482,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_vsc_q')",0.0,0.0,0.0,158.9980800432565,0.0,0.0,0.0,-376.99111843077515,-75.39822368615502,0.0,0.0,0.0,-3769.9111843077517,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_bus_d')",0.0,0.0,-236.09093185117854,-26.593706664312624,0.0,0.0,0.0,0.0,0.0,-56.54866776461627,376.99111843077515,1884.9555921538758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1732.449388861673,742.7494190000986,0.0,0.0 +"('gfmi_e_0', 'i_bus_q')",0.0,0.0,1863.6945957046444,187.27704971398418,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-56.54866776461627,0.0,1884.9555921538758,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-742.7494190000986,-1732.449388861673,0.0,0.0 +"('gfmi_e_0', 'v_lcl_sh_d')",0.0,0.0,0.0,8.964965227509495,0.0,0.0,0.0,376.99111843077515,0.0,-376.99111843077515,0.0,-37.69911184307752,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'v_lcl_sh_q')",0.0,0.0,0.0,-372.4393489823719,0.0,0.0,0.0,0.0,376.99111843077515,0.0,-376.99111843077515,-376.99111843077515,-37.69911184307752,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_l_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-100.0,0.0,0.0,0.0,0.0,0.0,100.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'v_dc_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-100.0,0.0,0.0,0.0,0.0,0.0,100.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_dc_f')",0.0,0.0,0.0,0.0,0.0,0.09932789605777746,-9.932789605777746,100.08337013864903,1.7018489238183393e-16,0.0,0.0,9.932401011992427,0.0878606260974435,0.0,0.0,-100.0,0.0,0.0,0.0,0.0,9.9410705862438,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_dc_f')",0.0,0.0,0.0,0.0,0.0,0.40167191080960485,-40.167191080960485,84.52521309107098,1.0406627303014625e-14,0.0,0.0,40.155559496144,0.9665820637849917,0.0,0.0,-100.0,0.0,0.0,0.0,0.0,33.9514038538795,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_load_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-100.0,0.0,0.0,0.0,0.0,100.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'x_1')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-20.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'x_2')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-10.0,-12.0,10.0,10.0,10.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_L')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-452.38934211693015,376.99111843077515,376.99111843077515,376.99111843077515,376.99111843077515,0.0,-188.49555921538757,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'v_dc')",0.0,0.0,0.0,0.0,0.0,-0.018722867313098655,1.8722867313098654,-18.86527082244527,-3.207909645952434e-17,0.0,0.0,-1.8722134831069943,-0.01656133784925169,0.022215865600420028,0.02665903872050403,-0.022215865600420028,-0.022215865600420028,-0.022215865600420028,-0.022215865600420028,9.42477796076938,-1.873847659353666,-18.84955592153876,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_L')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-3958.406743523139,-4750.0880922277665,3958.406743523139,3958.406743523139,3958.406743523139,3958.406743523139,0.0,-1795.1958020513098,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'v_dc')",0.0,0.0,0.0,0.0,0.0,-0.07571337144916976,7.571337144916975,-15.932627309401225,-1.9616030330278627e-15,0.0,0.0,-7.569144642832431,-0.18219642664071545,5.680719791051915,6.816863749262298,-5.680719791051915,-5.680719791051915,-5.680719791051915,-5.680719791051915,8.97597901025655,-6.399688855584481,-18.84955592153876,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_load')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",5620.316660029999,-624.1462815266722,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,0.0,0.0,-5654.8667481872935,0.0 -"('pa_rc_0', 'v_bus_Q')",624.1462815266722,5620.316660029999,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,0.0,0.0,-5654.8667481872935 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,-42.625779353978785,0.0,0.0,0.0,0.0,0.0,0.0,5623.795274257007,591.983659401928,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,5654.8667481872935,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,-555.7890886726366,0.0,0.0,0.0,0.0,0.0,0.0,-591.983659401928,5623.795274257007,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,5654.8667481872935 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,0.0,-7.5398223686155035,376.99111843077515 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,-376.99111843077515,-7.5398223686155035 +"('shunt_parallel_rc_0', 'v_bus_D')",5423.402824069048,-1601.3181281788504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,0.0,0.0,-5654.8667481872935,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",1601.3181281788504,5423.402824069048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,0.0,0.0,-5654.8667481872935 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,-740.2906646531766,0.0,0.0,0.0,0.0,0.0,0.0,5197.348140598278,2228.2482458590544,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,5654.8667481872935,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,-2739.060301026596,0.0,0.0,0.0,0.0,0.0,0.0,-2228.2482458590544,5197.348140598278,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,5654.8667481872935 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,0.0,-7.5398223686155035,376.99111843077515 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,-376.99111843077515,-7.5398223686155035 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/B.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/B.csv index 88c69cc..3553091 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/B.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/B.csv @@ -14,16 +14,16 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('gfmi_e_0', 'v_lcl_sh_q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_l_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'v_dc_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_dc_f')",0.0,0.0,0.0,-0.09932789605777746,-9.932789605777746,0.0,0.0,0.0 +"('gfmi_e_0', 'i_dc_f')",0.0,0.0,0.0,-0.4016719108096049,-40.167191080960485,0.0,0.0,0.0 "('gfmi_e_0', 'i_load_f')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'x_1')",0.0,0.0,0.0,0.0,0.0,20.0,0.0,0.0 "('gfmi_e_0', 'x_2')",0.0,0.0,0.0,0.0,0.0,12.0,0.0,0.0 -"('gfmi_e_0', 'i_L')",0.0,0.0,0.0,0.0,0.0,452.38934211693015,376.99111843077515,0.0 -"('gfmi_e_0', 'v_dc')",0.0,0.0,0.0,0.018722867313098655,1.8722867313098654,-0.02665903872050403,0.0,0.0 +"('gfmi_e_0', 'i_L')",0.0,0.0,0.0,0.0,0.0,4750.0880922277665,3769.9111843077517,0.0 +"('gfmi_e_0', 'v_dc')",0.0,0.0,0.0,0.07571337144916976,7.571337144916975,-6.816863749262298,0.0,0.0 "('gfmi_e_0', 'i_load')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1000.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/C.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/C.csv index b1e47fb..7f0ea0e 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/C.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/C.csv @@ -1,11 +1,11 @@ -Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_e_0', 'angle_pc')","('gfmi_e_0', 'w_pc')","('gfmi_e_0', 'p_pc')","('gfmi_e_0', 'q_pc')","('gfmi_e_0', 'pi_vc')","('gfmi_e_0', 'i_vsc_d')","('gfmi_e_0', 'i_vsc_q')","('gfmi_e_0', 'i_bus_d')","('gfmi_e_0', 'i_bus_q')","('gfmi_e_0', 'v_lcl_sh_d')","('gfmi_e_0', 'v_lcl_sh_q')","('gfmi_e_0', 'i_l_f')","('gfmi_e_0', 'v_dc_f')","('gfmi_e_0', 'i_dc_f')","('gfmi_e_0', 'i_load_f')","('gfmi_e_0', 'x_1')","('gfmi_e_0', 'x_2')","('gfmi_e_0', 'i_L')","('gfmi_e_0', 'v_dc')","('gfmi_e_0', 'i_load')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" -"('infinite_sources_0', 'i_bus_D')",0.9938902029533464,-0.11037329601563937,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('infinite_sources_0', 'i_bus_Q')",0.11037329601563937,0.9938902029533464,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_bus_D')",0.0,0.0,-0.007537892801389666,0.0,0.0,0.0,0.0,0.0,0.0,0.9945053570112422,0.10468569566059048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_e_0', 'i_bus_Q')",0.0,0.0,-0.09828509024563639,0.0,0.0,0.0,0.0,0.0,0.0,-0.10468569566059048,0.9945053570112422,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 +Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_e_0', 'angle_pc')","('gfmi_e_0', 'w_pc')","('gfmi_e_0', 'p_pc')","('gfmi_e_0', 'q_pc')","('gfmi_e_0', 'pi_vc')","('gfmi_e_0', 'i_vsc_d')","('gfmi_e_0', 'i_vsc_q')","('gfmi_e_0', 'i_bus_d')","('gfmi_e_0', 'i_bus_q')","('gfmi_e_0', 'v_lcl_sh_d')","('gfmi_e_0', 'v_lcl_sh_q')","('gfmi_e_0', 'i_l_f')","('gfmi_e_0', 'v_dc_f')","('gfmi_e_0', 'i_dc_f')","('gfmi_e_0', 'i_load_f')","('gfmi_e_0', 'x_1')","('gfmi_e_0', 'x_2')","('gfmi_e_0', 'i_L')","('gfmi_e_0', 'v_dc')","('gfmi_e_0', 'i_load')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'i_bus_D')",0.9590681912721563,-0.2831752187073487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_Q')",0.2831752187073487,0.9590681912721563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_bus_D')",0.0,0.0,-0.1309121324371581,0.0,0.0,0.0,0.0,0.0,0.0,0.9190929463128948,0.3940408050416634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_e_0', 'i_bus_Q')",0.0,0.0,-0.484372209460925,0.0,0.0,0.0,0.0,0.0,0.0,-0.3940408050416634,0.9190929463128948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/D.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/D.csv index aa2b8d8..5b2598d 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/D.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/D.csv @@ -3,9 +3,9 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('infinite_sources_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_e_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/u.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/u.csv index a8d0368..6d1790e 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/u.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/u.csv @@ -1,9 +1,9 @@ name,component,type,init -v_ref_d,infinite_sources_0,device,0.9319147420205057 -v_ref_q,infinite_sources_0,device,2.4364261741631428e-17 -p_ref,gfmi_e_0,device,-0.09970849663622566 -q_ref,gfmi_e_0,device,0.0019433557584956256 -v_ref,gfmi_e_0,device,1.0117040377962803 -v_dc_ref,gfmi_e_0,device,1.0 +v_ref_d,infinite_sources_0,device,1.0602915467925695 +v_ref_q,infinite_sources_0,device,-6.184065849485258e-17 +p_ref,gfmi_e_0,device,-0.4924473672884809 +q_ref,gfmi_e_0,device,0.05787698596992697 +v_ref,gfmi_e_0,device,0.9882122222891866 +v_dc_ref,gfmi_e_0,device,1.05 v_s,gfmi_e_0,device,0.5 -i_load_ref,gfmi_e_0,device,0.1 +i_load_ref,gfmi_e_0,device,0.5 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/x.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/x.csv index 8fe7525..787fd4f 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/x.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/x.csv @@ -1,29 +1,29 @@ name,component,type,init -i_bus_d,infinite_sources_0,"",0.21547208231583534 -i_bus_q,infinite_sources_0,"",0.09850474697346907 +i_bus_d,infinite_sources_0,"",0.5722653561902081 +i_bus_q,infinite_sources_0,"",-0.18339083649397844 angle_pc,gfmi_e_0,"",0.0 w_pc,gfmi_e_0,"",1.0 -p_pc,gfmi_e_0,"",-0.09970849663622566 -q_pc,gfmi_e_0,"",0.0019433557584956256 -pi_vc,gfmi_e_0,"",1.0008337013864903 -i_vsc_d,gfmi_e_0,"",-0.09932789605777746 -i_vsc_q,gfmi_e_0,"",0.09837477238891429 -i_bus_d,gfmi_e_0,"",-0.0985341583153472 -i_bus_q,gfmi_e_0,"",-0.0027925682738698583 -v_lcl_sh_d,gfmi_e_0,"",1.0116644575859595 -v_lcl_sh_q,gfmi_e_0,"",0.008949041881888602 -i_l_f,gfmi_e_0,"",0.001178588275124015 -v_dc_f,gfmi_e_0,"",1.0 -i_dc_f,gfmi_e_0,"",-0.099410705862438 -i_load_f,gfmi_e_0,"",0.1 -x_1,gfmi_e_0,"",0.0005892941375620075 -x_2,gfmi_e_0,"",0.5 -i_L,gfmi_e_0,"",0.001178588275124015 -v_dc,gfmi_e_0,"",1.0 -i_load,gfmi_e_0,"",0.1 -v_bus_D,pa_rc_0,"",0.9850307325446462 -v_bus_Q,pa_rc_0,"",0.0 -v_bus_D,pa_rc_1,"",1.0114986905096575 -v_bus_Q,pa_rc_1,"",-0.07757604616073832 -i_br_D,se_rl_0,"",0.15403176129835686 -i_br_Q,se_rl_0,"",0.05601655115598958 +p_pc,gfmi_e_0,"",-0.4924473672884809 +q_pc,gfmi_e_0,"",0.05787698596992697 +pi_vc,gfmi_e_0,"",0.8875147374562453 +i_vsc_d,gfmi_e_0,"",-0.42175550635008513 +i_vsc_q,gfmi_e_0,"",0.9197620895795204 +i_bus_d,gfmi_e_0,"",-0.49676780316078684 +i_bus_q,gfmi_e_0,"",-0.07054199784602057 +v_lcl_sh_d,gfmi_e_0,"",0.9879260565411991 +v_lcl_sh_q,gfmi_e_0,"",0.02378030884341824 +i_l_f,gfmi_e_0,"",0.30137154502195707 +v_dc_f,gfmi_e_0,"",1.05 +i_dc_f,gfmi_e_0,"",-0.35648974046573473 +i_load_f,gfmi_e_0,"",0.5 +x_1,gfmi_e_0,"",0.15786128548769174 +x_2,gfmi_e_0,"",0.5238095238095238 +i_L,gfmi_e_0,"",0.30137154502195707 +v_dc,gfmi_e_0,"",1.05 +i_load,gfmi_e_0,"",0.5 +v_bus_D,shunt_parallel_rc_0,"",1.0039676883731015 +v_bus_Q,shunt_parallel_rc_0,"",0.0 +v_bus_D,shunt_parallel_rc_1,"",0.9580798748577896 +v_bus_Q,shunt_parallel_rc_1,"",-0.2744797866029319 +i_br_D,branch_series_rl_0,"",0.5505748558041546 +i_br_Q,branch_series_rl_0,"",-0.08076412991454072 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/y.csv b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/y.csv index 30a92aa..cf58c36 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/y.csv +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/outputs/small_signal_model/y.csv @@ -1,11 +1,11 @@ name,component,type,init -i_bus_D,infinite_sources_0,"",0.2032832980270174 -i_bus_Q,infinite_sources_0,"",0.12168526688588112 -i_bus_D,gfmi_e_0,"",-0.09828509024563638 -i_bus_Q,gfmi_e_0,"",0.007537892801389665 -v_bus_D,pa_rc_0,"",0.9850307325446462 -v_bus_Q,pa_rc_0,"",0.0 -v_bus_D,pa_rc_1,"",1.0114986905096575 -v_bus_Q,pa_rc_1,"",-0.07757604616073832 -i_br_D,se_rl_0,"",0.15403176129835686 -i_br_Q,se_rl_0,"",0.05601655115598958 +i_bus_D,infinite_sources_0,"",0.6007732403221651 +i_bus_Q,infinite_sources_0,"",-0.013832950454366671 +i_bus_D,gfmi_e_0,"",-0.484372209460925 +i_bus_Q,gfmi_e_0,"",0.1309121324371581 +v_bus_D,shunt_parallel_rc_0,"",1.0039676883731015 +v_bus_Q,shunt_parallel_rc_0,"",0.0 +v_bus_D,shunt_parallel_rc_1,"",0.9580798748577896 +v_bus_Q,shunt_parallel_rc_1,"",-0.2744797866029319 +i_br_D,branch_series_rl_0,"",0.5505748558041546 +i_br_Q,branch_series_rl_0,"",-0.08076412991454072 diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/run.py b/examples/small_signal_and_emt/2-bus-src-gfmi_e/run.py index d862599..2908494 100644 --- a/examples/small_signal_and_emt/2-bus-src-gfmi_e/run.py +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/run.py @@ -1,70 +1,124 @@ + + # In progress - March 5, 2026 - Ruth # Import Python standard and third-party packages from pathlib import Path +from scipy import signal +import numpy as np # Import sting package -from sting.system.core import System -from sting.system.operations import SystemModifier -from sting.modules.power_flow.core import ACPowerFlow -from sting.modules.simulation_emt.core import SimulationEMT -from sting.modules.small_signal_modeling.core import SmallSignalModel +from sting import main +# from sting.system.core import System +# from sting.system.operations import SystemModifier +# from sting.modules.power_flow.core import ACPowerFlow +# from sting.modules.simulation_emt.core import SimulationEMT +# from sting.modules.small_signal_modeling.core import SmallSignalModel # Specify path of the case study directory case_dir = Path(__file__).resolve().parent # Construct system and small-signal model def step1(t): - return 0.1 if t >= 0.5 else 0.0 + return 0.5 if t >= 0.5 else 0.0 def step2(t): return 0.0 def step3(t): - return 0.1 if t > 1.0 else 0.0 + return 0.25 if t > 1.0 else 0.0 + +def step3_neg(t): + return -0.25 if t > 1.0 else 0.0 + +def square_oscillation(t): + osc = 0.1*signal.square(2 * np.pi * 14 * t) + return osc # Specify inputs to excite - any constant input does not need to be specified # NB: input is a perturbation from the nominal value -inputs = {'infinite_sources_0': {'v_ref_d': step1}, - 'gfmi_e_0': {'p_ref': step2, +inputs = {'infinite_sources_0': {'v_ref_d': step2}, + 'gfmi_e_0': {'p_ref': step3_neg, 'q_ref': step2, 'v_ref': step2, 'v_dc_ref': step2, 'v_s': step2, - 'i_load_ref': step2}} + 'i_load_ref': step3}} t_max = 4.0 -# Load system from CSV files -sys = System.from_csv(case_directory=case_dir) +# Construct system and small-signal model +sys, ssm = main.run_ssm(case_directory=case_dir) +ssm.simulate_ssm(t_max=t_max, inputs=inputs) +# Run EMT simulation +main.run_emt(case_directory=case_dir, inputs=inputs, t_max=t_max) + + +# # Load system from CSV files +# sys = System.from_csv(case_directory=case_dir) + +# # Match power reference with load +# P_load = -100 # MW +# sys.gfmi_e[0].minimum_active_power_MW = -P_load +# sys.gfmi_e[0].maximum_active_power_MW = -P_load +# sys.gfmi_e[0].minimum_reactive_power_MVAR = 0 +# sys.gfmi_e[0].maximum_reactive_power_MVAR = 0 + +# # i_load_ref*v_dc_ref = i_load_ref*1 = p_load = i_load_ref +# Sbase = 100 # MVA +# sys.gfmi_e[0].i_load_ref = P_load/Sbase +# sys.gfmi_e[0].i_load_ref = 0 -# Match power reference with load -P_load = 10 # MW -sys.gfmi_e[0].minimum_active_power_MW = -P_load -sys.gfmi_e[0].maximum_active_power_MW = -P_load -sys.gfmi_e[0].minimum_reactive_power_MVAR = 0 -sys.gfmi_e[0].maximum_reactive_power_MVAR = 0 +# # sys.gfmi_e[0].SOC_init_pu = 0.0 +# # sys.gfmi_e[0].Pbat_max_pu = 100.0 +# # sys.gfmi_e[0].v_dc_ref = 1.00 -# i_load_ref*v_dc_ref = i_load_ref*1 = p_load = i_load_ref -Sbase = 100 # MVA -sys.gfmi_e[0].i_load_ref = P_load/Sbase -# Run power flow -pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) -pf.solve() +# # Run power flow +# pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) +# pf.solve() -# Break down lines into branches and shunts for small-signal modeling -sys_modifier = SystemModifier(system=sys) -sys_modifier.decompose_lines() -sys_modifier.combine_shunts() +# # Break down lines into branches and shunts for small-signal modeling +# sys_modifier = SystemModifier(system=sys) +# sys_modifier.decompose_lines() +# sys_modifier.combine_shunts() + +# # Construct small-signal model +# ssm = SmallSignalModel(system=sys) +# ssm.construct_system_ssm() + +# ssm.simulate_ssm(t_max=t_max, inputs=inputs) + +# emt_sc = SimulationEMT(system=sys) +# emt_sc.sim(t_max, inputs) + +# # calculate SIL + +# # characteristic impedance +# import numpy as np +# l = sys.lines[0] +# Vbase = l.base_voltage_kV*1e3 +# Sbase = l.base_power_MVA*1e6 +# wbase = 2*np.pi*60 +# Zbase = Vbase**2/Sbase +# Ybase = 1/Zbase +# l = sys.lines[0] +# x = l.x_pu*Zbase +# r = l.r_pu*Zbase +# g = l.g_pu*Ybase +# b = l.b_pu*Ybase +# Z0 = np.sqrt((r + x*1j)/(g + b*1j)) + +# # for 230kV line, Z0 should be 360-390 Ohms... + +# Z0_ideal = np.sqrt(x/b) +# SIL_ideal_MW = (Vbase**2/Z0_ideal)/1e6 + +# # Average transmission line parameter values +# # HV (69-230kV) - L=1.3mH/km, c=8.75nF/km -# Construct small-signal model -ssm = SmallSignalModel(system=sys) -ssm.construct_system_ssm() -ssm.simulate_ssm(t_max=t_max, inputs=inputs) -emt_sc = SimulationEMT(system=sys) -emt_sc.sim(t_max, inputs) -print('ok') \ No newline at end of file +print('ok') +# %% diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/run_compare_ssm_emt.py b/examples/small_signal_and_emt/2-bus-src-gfmi_e/run_compare_ssm_emt.py new file mode 100644 index 0000000..1785da0 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/run_compare_ssm_emt.py @@ -0,0 +1,453 @@ +""" +In progress (March 6, 2026 - Ruth) + +Simulates a a GFMIe connected to an infinite source via a transmission line. + +1. Computes and simulates the small-signal model using STING. + +2. Runs EMT using sting. + +3. Compares corresponding SSM and EMT states in plots. + +""" + +# Import Python standard and third-party packages +import os +import numpy as np +import plotly.graph_objects as go +from plotly.subplots import make_subplots +from pathlib import Path +from typing import Callable + +# Import sting package +from sting import main +from sting.utils.transformations import dq02abc, abc2dq0 +from sting.modules.small_signal_modeling.core import SmallSignalModel +from sting.system.core import System +from sting.system.component import Component +from sting.system.operations import SystemModifier +from sting.modules.power_flow.core import ACPowerFlow +from sting.modules.simulation_emt.core import SimulationEMT + + +# Define additional functions that return required data in order to compare SSM and EMT + +def simulate_ssm_ruth(ssm: SmallSignalModel, t_max: float, inputs: dict[str, dict[str, Callable[[float], float]]] = None, settings={'dense_output': True, 'method': 'Radau', 'max_step': 0.001}): + """Simulate the small-signal model under a given input profile.""" + + x0 = np.zeros_like(ssm.model.x.init) + tps, solution = ssm.model.simulate(t_max=t_max, inputs=inputs, x0=x0, settings=settings, output_directory=ssm.output_directory, plot=False) + + # Add the initial conditions back to the solution (for plotting purposes) + for i in range(len(ssm.model.x.init)): + solution[i] = solution[i] + ssm.model.x.init[i] + + components_to_plot = np.unique(ssm.model.x.component) # Get the components in the same order as solution vector + i = 0 # Initialize counter + + name_list = [] + component_list = [] + # Make a html file for each component. Each file plots the states corresponding to each component. + for component in components_to_plot: + number_of_states = sum(ssm.model.x.component == component) + nrows = int(np.ceil(number_of_states / 2)) + ncols = 2 if number_of_states > 1 else 1 + #fig = make_subplots(rows=nrows, cols=ncols) + for j in range(number_of_states): + row = j // ncols + 1 + col = j % ncols + 1 + #fig.add_trace(go.Scatter(x=tps, y=solution[i]), row=row, col=col) + #fig.update_xaxes(title_text='Time [s]', row=row, col=col) + #fig.update_yaxes(title_text=ssm.model.x.name[i], row=row, col=col) + name_list.append(ssm.model.x.name[i]) # added + component_list.append(component) + i += 1 + + + #fig.update_layout(title_text = component, title_x=0.5, showlegend = False) + #fig.write_html(os.path.join(ssm.output_directory, f"{component}.html")) + + return tps, solution, name_list, component_list + +def run_emt_ruth(sys, t_max, inputs, case_directory=os.getcwd(), model_settings=None, solver_settings=None): + """ + Routine to simulate the EMT dynamics of the system from a case study directory. + """ + + # Load system from CSV files + sys = System.from_csv(case_directory=case_directory) + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=model_settings, solver_settings=solver_settings) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + emt_sc = SimulationEMT(system=sys) + emt_sc.sim(t_max, inputs) + + return sys, emt_sc + + +def reconstruct_input_timeseries(fcn_name, tps, init_cond): + output = np.zeros_like(tps) + i = 0 + for t in tps: + output[i] = fcn_name(t) + i += 1 + return output + init_cond # add back initial condition + + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model +def step1(t): + return 0.1 if t >= 0.5 else 0.0 + +def no_step(t): + return 0.0 + +def step3(t): + return 0.1 if t > 1.0 else 0.0 + +def noisy_i_load_ref(t): + avg = 0.1*np.sin(2*np.pi*1*t)/2 # 1 Hz + fast = 0.05*np.sin(2*np.pi*20*t)/2 # 20 Hz + return avg + fast + +def p_ref(t): + return -0.1*np.sin(2*np.pi*1*t) if t < 1 else 0 #1 Hz oscillation + +def slow_small_oscillation(t): + return 0.1*np.sin(2*np.pi*1*t) if t < 1 else 0 #1 Hz oscillation + +# Specify inputs to excite - any constant input does not need to be specified +# NB: input is a perturbation from the nominal value +inputs = {'infinite_sources_0': {'v_ref_d': no_step}, + 'gfmi_e_0': {'p_ref': step1, + 'q_ref': no_step, + 'v_ref': no_step, + 'v_dc_ref': no_step, + 'v_s': no_step, + 'i_load_ref': slow_small_oscillation}} + +t_max = 4.0 + +# Load system from CSV files +sys = System.from_csv(case_directory=case_dir) + +# Run power flow +pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) +pf.solve() + +# Build and perturb small-signal model +sys, ssm = main.run_ssm(case_directory=case_dir) +tps, sol, ssm_state_names, component_name = simulate_ssm_ruth(ssm, t_max=t_max, inputs=inputs) + +# Retrieve state traces +i_bus_d_inf = sol[0,:] # infinite source +i_bus_q_inf = sol[1,:] # infinite source +angle_pc = sol[2,:] +w_pc = sol[3,:] +p_pc = sol[4,:] +q_pc = sol[5,:] +pi_vc = sol[6,:] +i_vsc_d = sol[7,:] +i_vsc_q = sol[8,:] +i_bus_d = sol[9,:] # gfmie +i_bus_q = sol[10,:] # gfmie +v_sh_d = sol[11,:] +v_sh_q = sol[12,:] +iLf = sol[13,:] +vdcf = sol[14,:] +idcf = sol[15,:] +iloadf = sol[16,:] +x1 = sol[17,:] +x2 = sol[18,:] +iL = sol[19,:] +vdc = sol[20,:] +i_load = sol[21,:] +v_bus_D_rc0 = sol[22,:] # RC0 +v_bus_Q_rc0 = sol[23,:] # RC0 +v_bus_D_rc1 = sol[24,:] #RC1 +v_bus_Q_rc1 = sol[25,:] #RC1 +i_br_D_br0 = sol[26,:] #BR0 +i_br_Q_br0 = sol[27,:] #BR0 + +# Run EMT + +emt_sc = SimulationEMT(system=sys) +emt_sc.sim(t_max, inputs) + +emt_state_names = emt_sc.variables.x.name +# Define timepoints that will be used to evaluate the solution of the ODEs +tps = np.linspace(0, t_max, 500) +n_tps = len(tps) + +# Extract solutions directly from each component +gfm = emt_sc.system.gfmi_e[0].variables_emt.x.value +gfm_names = emt_sc.system.gfmi_e[0].variables_emt.x.name + +angle_pc_emt = gfm[0,:] +w_pc_emt = gfm[1,:] +p_pc_emt = gfm[2,:] +q_pc_emt = gfm[3,:] +gamma_emt = gfm[4,:] +i_vsc_a = gfm[5,:] +i_vsc_b = gfm[6,:] +i_vsc_c = gfm[7,:] +v_sh_a = gfm[8,:] +v_sh_b = gfm[9,:] +v_sh_c = gfm[10,:] +i_bus_a = gfm[11,:] +i_bus_b = gfm[12,:] +i_bus_c = gfm[13,:] +iLf_emt = gfm[14,:] +vdcf_emt = gfm[15,:] +idcf_emt = gfm[16,:] +iloadf_emt = gfm[17,:] +x1_emt = gfm[18,:] +x2_emt = gfm[19,:] +iL_emt = gfm[20,:] +vdc_emt = gfm[21,:] +i_load_emt = gfm[22,:] + +inf_src = emt_sc.system.infinite_sources[0].variables_emt.x.value + +# convert abc to dq for plotting comparison +angle_pc_emt_init = sys.gfmi_e[0].emt_init.angle_ref * np.pi / 180 + +i_bus_d_emt, i_bus_q_emt, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(i_bus_a, i_bus_b, i_bus_c, angle_pc_emt)]) #? what angle to use here + +i_vsc_d_emt, i_vsc_q_emt, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(i_vsc_a, i_vsc_b, i_vsc_c, angle_pc_emt)]) + +v_sh_d_emt, v_sh_q_emt, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(v_sh_a, v_sh_b, v_sh_c, angle_pc_emt)]) + +fig = make_subplots( + rows=14, cols=2, + horizontal_spacing=0.15, + vertical_spacing=0.05, +) + +r, c = 1,1 # define row, column for convenience +# plot inf source voltages? +fig.add_trace(go.Scatter(x=tps, y=angle_pc_emt, name="angle_pc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=angle_pc, name="angle_pc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='angle_pc', row=r, col=c) + +r, c = 1,2 +fig.add_trace(go.Scatter(x=tps, y=angle_pc_emt, name="angle_pc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=angle_pc, name="angle_pc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='angle_pc', row=r, col=c) + + +r, c = 2,1 +fig.add_trace(go.Scatter(x=tps, y=gamma_emt, name="gamma (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=pi_vc, name="gamma (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='gamma', row=r, col=c) + +r, c = 2, 2 +fig.add_trace(go.Scatter(x=tps, y=w_pc_emt, name="w_pc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=w_pc, name="w_pc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) + +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='w_pc', row=r, col=c) + +r, c = 3,1 +fig.add_trace(go.Scatter(x=tps, y=p_pc_emt, name="p_pc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=p_pc, name="p_pc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) + +pref = reconstruct_input_timeseries(inputs['gfmi_e_0']['p_ref'], tps, sys.gfmi_e[0].emt_init.p_ref) +fig.add_trace(go.Scatter(x=tps, y=pref, name="p_ref", mode='lines', line=dict(color='green', dash='dot'), legendgroup=str(r)), row=r, col=c) + +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p_pc', row=r, col=c) + +r, c = 3,2 +fig.add_trace(go.Scatter(x=tps, y=q_pc_emt, name="q_pc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=q_pc, name="q_pc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +qref = reconstruct_input_timeseries(inputs['gfmi_e_0']['q_ref'], tps, sys.gfmi_e[0].emt_init.q_ref) +fig.add_trace(go.Scatter(x=tps, y=qref, name="q_ref", mode='lines', line=dict(color='green', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='q_pc', row=r, col=c) + +r, c = 4,1 +fig.add_trace(go.Scatter(x=tps, y=i_vsc_d_emt, name="i_vsc_d (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_vsc_d, name="i_vsc_d (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_vsc_d', row=r, col=c) + +r, c = 4,2 +fig.add_trace(go.Scatter(x=tps, y=i_vsc_q_emt, name="i_vsc_q (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_vsc_q, name="i_vsc_q (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_vsc_q', row=r, col=c) + + +r, c = 5,1 +fig.add_trace(go.Scatter(x=tps, y=v_sh_d_emt, name="v_sh_d (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=v_sh_d, name="v_sh_d (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='v_sh_d', row=r, col=c) + + +r, c = 5,2 +fig.add_trace(go.Scatter(x=tps, y=v_sh_q_emt, name="v_sh_q (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=v_sh_q, name="v_sh_q (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='v_sh_q', row=r, col=c) + +r, c = 6,1 +fig.add_trace(go.Scatter(x=tps, y=i_bus_d_emt, name="i_bus_d (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_bus_d, name="i_bus_d (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_bus_d', row=r, col=c) + +r, c = 6,2 +fig.add_trace(go.Scatter(x=tps, y=i_bus_q_emt, name="i_bus_q (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_bus_q, name="i_bus_q (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_bus_q', row=r, col=c) + +r, c = 7,1 +fig.add_trace(go.Scatter(x=tps, y=iLf_emt, name="iLf (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=iLf, name="iLf (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='iLf', row=r, col=c) + + +r, c = 7,2 +fig.add_trace(go.Scatter(x=tps, y=vdcf_emt, name="vdcf (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=vdcf, name="vdcf (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='vdcf', row=r, col=c) + +r, c = 8,1 +fig.add_trace(go.Scatter(x=tps, y=idcf_emt, name="idcf (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=idcf, name="idcf (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='idcf', row=r, col=c) + +r, c = 8,2 +fig.add_trace(go.Scatter(x=tps, y=iloadf_emt, name="iloadf (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=iloadf, name="iloadf (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='iloadf', row=r, col=c) + +r, c = 9,1 +fig.add_trace(go.Scatter(x=tps, y=x1_emt, name="x1 (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=x1, name="x1 (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='x1', row=r, col=c) + +r, c = 9,2 +fig.add_trace(go.Scatter(x=tps, y=x2_emt, name="x2 (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=x2, name="x2 (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='x2', row=r, col=c) + + +r, c = 10,1 +fig.add_trace(go.Scatter(x=tps, y=iL_emt, name="iL (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=iL, name="iL (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='iL', row=r, col=c) + +r, c = 10,2 +fig.add_trace(go.Scatter(x=tps, y=vdc_emt, name="vdc (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=vdc, name="vdc (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +vdc_ref = reconstruct_input_timeseries(inputs['gfmi_e_0']['v_dc_ref'], tps, sys.gfmi_e[0].emt_init.v_dc) +fig.add_trace(go.Scatter(x=tps, y=vdc_ref, name="vdc_ref", mode='lines', line=dict(color='green', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='vdc', row=r, col=c) + +r, c = 11,1 +fig.add_trace(go.Scatter(x=tps, y=i_load_emt, name="iload (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_load, name="iload (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +iload_ref = reconstruct_input_timeseries(inputs['gfmi_e_0']['i_load_ref'], tps, sys.gfmi_e[0].emt_init.i_load) +fig.add_trace(go.Scatter(x=tps, y=iload_ref, name="i_load_ref", mode='lines', line=dict(color='green', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='iload', row=r, col=c) + +r, c = 11, 2 +pload_emt = i_load_emt*vdc_emt +pload = i_load*vdc + +fig.add_trace(go.Scatter(x=tps, y=pload_emt, name="pload (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=pload, name="pload (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='pload (calculated)', row=r, col=c) + +r, c = 12, 1 + +pbattery_emt = iL_emt*sys.gfmi_e[0].v_s # needs fixing if we perturb v_s +pbattery = iL*sys.gfmi_e[0].v_s # needs fixing if we perturb v_s + +fig.add_trace(go.Scatter(x=tps, y=pbattery_emt, name="p_battery (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=pbattery, name="p_battery (ssm)", mode='lines', line=dict(color='blue', dash='dot'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p_battery (calculated)', row=r, col=c) + +r, c = 13, 1 + +# power comparisons +g = sys.gfmi_e[0] +v_vsc_d_emt = v_sh_d_emt + np.multiply(g.rf1_pu, i_vsc_d_emt) - np.multiply(g.xf1_pu, i_vsc_q_emt) +v_vsc_q_emt = v_sh_q_emt + np.multiply(g.rf1_pu, i_vsc_q_emt) + np.multiply(g.xf1_pu, i_vsc_d_emt) + +p_ac_emt = np.multiply(i_vsc_d_emt,v_vsc_d_emt) + np.multiply(i_vsc_q_emt,v_vsc_q_emt) +idc_emt = p_ac_emt/vdc_emt + +duty_cycle_emt = g.kp_i_L*(g.kp_v_dc*(g.v_dc_ref - vdcf_emt) + x1_emt - iLf_emt + g.Kff_idc*idcf_emt + g.Kff_iload*iloadf_emt) + x2_emt + +i_cap = -idc_emt - i_load + (1-duty_cycle_emt)*iL_emt + +p_capacitor_emt = vdc_emt*i_cap +p_bat_inductor = (sys.gfmi_e[0].v_s - (1-duty_cycle_emt)*vdc_emt)*iL_emt + +fig.add_trace(go.Scatter(x=tps, y=pbattery_emt, name="p_battery (emt)", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=np.multiply(pload_emt, -1.0), name="p_load (emt)", mode='lines', line=dict(color='blue', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=p_ac_emt, name="p_ac (emt)", mode='lines', line=dict(color='green', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p (calculated)', row=r, col=c) + +power_sum = pload_emt - np.multiply(p_ac_emt, -1.0) + p_capacitor_emt +r, c = 13,2 +fig.add_trace(go.Scatter(x=tps, y=p_capacitor_emt, name="p_capacitor", mode='lines', line=dict(color='pink', dash='dash'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p capacitor', row=r, col=c) + +r, c = 14,1 +fig.add_trace(go.Scatter(x=tps, y=p_bat_inductor, name="battery inductor power", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p inductor', row=r, col=c) + +r, c = 14, 1 + +# p_sh_emt = np.multiply(i_bus_d_emt,v_sh_d_emt) + np.multiply(i_bus_q_emt,v_sh_q_emt) +# #ptracking = -0.1 -0.1*np.sin(2*np.pi*0.1*tps) + +# fig.add_trace(go.Scatter(x=tps, y=p_pc_emt, name="p_pc", mode='lines', line=dict(color='red', dash='solid'), legendgroup=str(r)), row=r, col=c) +# #fig.add_trace(go.Scatter(x=tps, y=p_sh_emt, name="p_actual", mode='lines', line=dict(color='blue', dash='dash'), legendgroup=str(r)), row=r, col=c) +# #fig.add_trace(go.Scatter(x=tps, y=ptracking, name="p_ref", mode='lines', line=dict(color='green', dash='dot'), legendgroup=str(r)), row=r, col=c) + +# fig.update_xaxes(title_text='Time [s]', row=r, col=c) +# fig.update_yaxes(title_text='p (calculated)', row=r, col=c) + +fig.update_layout(height=1200*4, + width=800*2, + legend_tracegroupgap=400, + margin={'t': 0, 'l': 0, 'b': 0, 'r': 0}) +fig.show() +fig.write_html("examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_emt_comparison.html") +print('ok') diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_analysis.py b/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_analysis.py new file mode 100644 index 0000000..c6442b3 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_analysis.py @@ -0,0 +1,129 @@ +""" + +Small signal analysis of GFMIE v INF source under variation in Pload, Pref, and Qref. + +""" + +# Import Python standard and third-party packages +from pathlib import Path +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +# Import sting package +from sting.system.core import System +from sting.system.operations import SystemModifier +from sting.modules.power_flow.core import ACPowerFlow +from sting.modules.small_signal_modeling.core import SmallSignalModel + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model + +inputs = {} +t_max = 2.0 + +# Load system from CSV files +sys = System.from_csv(case_directory=case_dir) + +# Define range of P and Q to vary over +n = 11 +Prange = np.linspace(100,0,n) +Qrange = np.linspace(-50,50,n) + +Sbase = 100 # MVA +vdc_ref = 1.05 # pu + +def run_sim(sys, P, Q, Sbase, vdc_ref, factor): + sys.gfmi_e[0].minimum_active_power_MW = -P*factor + sys.gfmi_e[0].maximum_active_power_MW = -P*factor + sys.gfmi_e[0].minimum_reactive_power_MVAR = Q + sys.gfmi_e[0].maximum_reactive_power_MVAR = Q + sys.gfmi_e[0].i_load_ref = P/Sbase/vdc_ref + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + return ssm + +# Case 1: Pref = Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + ssm = run_sim(sys, P, Q, Sbase, vdc_ref, 1.0) + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + +# Plot results +fig, axes = plt.subplots(nrows=1,ncols=3, figsize=(30,10)) + +# Colorbar - use the same range for each +vmin = -6 +vmax = 0 +# Plot small-signal stability heatmap +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1], vmin=vmin, vmax=vmax, cbar=False, cbar_kws = {'label': 'maximum eig. real part'}) +axes[1].set_xlabel("Q_sh (MVAR)") +axes[1].set_ylabel("P_load (MW)") +axes[1].set_title("Pref = Pload") + +## Case 2: Pref = 0.5*Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + ssm = run_sim(sys, P, Q, Sbase, vdc_ref, 0.5) + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + + +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0], vmin=vmin, vmax=vmax, cbar=False, cbar_kws = {'label': 'maximum eig. real part'}) +axes[0].set_xlabel("Q_sh (MVAR)") +axes[0].set_ylabel("P_load (MW)") +axes[0].set_title("Pref = 0.5*Pload") + +## Case 3: Pref = 1.5*Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + ssm = run_sim(sys, P, Q, Sbase, vdc_ref, 1.5) + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5,ax=axes[2], vmin=vmin, vmax=vmax, cbar=True, cbar_kws = {'label': 'maximum eig. real part'}) +axes[2].set_xlabel("Q_sh (MVAR)") +axes[2].set_ylabel("P_load (MW)") +axes[2].set_title("Pref = 1.5*Pload") +fig.suptitle("Effect of Pref v Pload across P & Q space") + +plt.show() +plt.savefig(str(case_dir)+"/ssm_heatmaps.png") + +print('ok') + \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_heatmaps.png b/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_heatmaps.png new file mode 100644 index 0000000..1df2492 Binary files /dev/null and b/examples/small_signal_and_emt/2-bus-src-gfmi_e/ssm_heatmaps.png differ diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/emt_analysis.py b/examples/small_signal_and_emt/2-bus_src-gfm/emt_analysis.py new file mode 100644 index 0000000..c3a806c --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src-gfm/emt_analysis.py @@ -0,0 +1,201 @@ +""" + +Analysis of EMT response of gfmi_c v INF bus system to a grid disturbance under different P/Q and different Pref/Pload relationships + +In progress - April 3 (Ruth) + +""" + +# Import Python standard and third-party packages +from pathlib import Path +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +# Import sting package +from sting.system.core import System +from sting.system.operations import SystemModifier +from sting.modules.power_flow.core import ACPowerFlow +from sting.modules.simulation_emt.core import SimulationEMT +from sting.modules.small_signal_modeling.core import SmallSignalModel + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model +def step1(t): + return 0.3 if t >= 0.5 else 0.0 + +def step2(t): + return 0.0 + +def step3(t): + return 0.1 if t > 1.0 else 0.0 + +inputs = {'infinite_sources_0': {'v_ref_d': step1}, + 'gfmi_c_0': {'p_ref': step2, + 'q_ref': step2, + 'v_ref': step2, + 'v_dc_ref': step2, + 'v_s': step2, + 'i_load_ref': step2}} + +t_max = 2.0 + +# Load system from CSV files +sys = System.from_csv(case_directory=case_dir) + +n = 3 +Prange = np.linspace(100,0,n) +Qrange = np.linspace(-50,50,n) + +Sbase = 100 # MVA +vdc_ref = 1.05 # pu + +tps = np.linspace(0, t_max, 500) +dt = tps[1] - tps[0] + +def run_sim(sys, P, Q, Sbase, vdc_ref, factor): + sys.gfmi_c[0].minimum_active_power_MW = -P*factor + sys.gfmi_c[0].maximum_active_power_MW = -P*factor + sys.gfmi_c[0].minimum_reactive_power_MVAR = Q + sys.gfmi_c[0].maximum_reactive_power_MVAR = Q + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + emt_sc = SimulationEMT(system=sys) + emt_sc.sim(t_max, inputs) + return emt_sc + + +# Case 1: Pref = Pload +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 1.0) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_c[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results +fig, axes = plt.subplots(nrows=2,ncols=3, figsize=(30,15)) + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,1], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,1].set_xlabel("Q_sh") +axes[0,1].set_ylabel("P_load") +axes[0,1].set_title("Pref = Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,1], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,1].set_xlabel("Q_sh") +axes[1,1].set_ylabel("P_load") +axes[1,1].set_title("Pref = Pload") + + +# Case 2: Pref < Pload (Pref=0.8*Pload) + +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 0.8) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_c[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,0], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,0].set_xlabel("Q_sh") +axes[0,0].set_ylabel("P_load") +axes[0,0].set_title("Pref = 0.8*Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,0], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,0].set_xlabel("Q_sh") +axes[1,0].set_ylabel("P_load") +axes[1,0].set_title("Pref = 0.8*Pload") + + +# Case 3: Pref > Pload (Pref=1.2*Pload) + +results_rocof = np.zeros([Prange.shape[0],Qrange.shape[0]]) +results_nadir = np.zeros([Prange.shape[0],Qrange.shape[0]]) + +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + emt_sc = run_sim(sys, P, Q, Sbase, vdc_ref, 1.2) + + # Measure some performance metrics - frequency ROCOF and nadir and steady state error ? + gfm = emt_sc.system.gfmi_c[0].variables_emt.x.value + w_pc = gfm[1,:] + # nadir + nadir = np.min(w_pc) + results_nadir[i,j] = nadir + # rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) + df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof + df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) + rocof = np.max(df_dt_ma) + + results_rocof[i,j] = rocof + j += 1 + i += 1 + +# Plot results + +sns.heatmap(results_nadir, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0,2], cbar=True, cbar_kws = {'label': 'nadir'}) +axes[0,2].set_xlabel("Q_sh") +axes[0,2].set_ylabel("P_load") +axes[0,2].set_title("Pref = 1.2*Pload") + +sns.heatmap(results_rocof, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1,2], cbar=True, cbar_kws = {'label': 'rocof'}) +axes[1,2].set_xlabel("Q_sh") +axes[1,2].set_ylabel("P_load") +axes[1,2].set_title("Pref = 1.2*Pload") + +plt.show() +plt.savefig(str(case_dir)+"/emt_heatmaps.png") + +print('ok') \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/emt_heatmaps.png b/examples/small_signal_and_emt/2-bus_src-gfm/emt_heatmaps.png new file mode 100644 index 0000000..72c694a Binary files /dev/null and b/examples/small_signal_and_emt/2-bus_src-gfm/emt_heatmaps.png differ diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/inputs/buses.csv b/examples/small_signal_and_emt/2-bus_src-gfm/inputs/buses.csv index b50acd6..3817d3d 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/inputs/buses.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/inputs/buses.csv @@ -1,3 +1,3 @@ name,base_power_MVA,base_voltage_kV,base_frequency_Hz,minimum_voltage_pu,maximum_voltage_pu -lima,1.00E+02,2.30E+02,60,1,1 -santiago,1.00E+02,2.30E+02,60,0.95,1.3 \ No newline at end of file +lima,1.00E+02,2.30E+02,60,0.95,1.05 +santiago,1.00E+02,2.30E+02,60,0.95,1.05 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/inputs/gfmi_c.csv b/examples/small_signal_and_emt/2-bus_src-gfm/inputs/gfmi_c.csv index 3c5387f..8f66653 100755 --- a/examples/small_signal_and_emt/2-bus_src-gfm/inputs/gfmi_c.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/inputs/gfmi_c.csv @@ -1,2 +1,2 @@ name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,rf1_pu,xf1_pu,rsh_pu,csh_pu,txr_power_MVA,txr_voltage1_kV,txr_voltage2_kV,txr_r1_pu,txr_x1_pu,txr_r2_pu,txr_x2_pu,h_s,kd_pu,droop_q_pu,tau_pc_s,v_dc_pu,kp_vc_pu,ki_vc_puHz -solar,santiago,80,80,50,51,1.00E+02,4.80E-01,60,0,0.02,0.1,1,0.1,1.00E+02,4.80E-01,2.30E+02,0.01,0.1,0.02,0.1,0.5,70,0,0.001,1,1,10 \ No newline at end of file +solar,santiago,-50,-50,-10,10,1.00E+02,4.80E-01,60,0,0.02,0.1,10,1,1.00E+02,4.80E-01,2.30E+02,0.01,0.1,0.02,0.1,0.5,70,0.01,0.001,1.05,1,10 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/active_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/active_power_balance_by_bus.csv index e798b85..43499bd 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/active_power_balance_by_bus.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/active_power_balance_by_bus.csv @@ -1,3 +1,3 @@ bus,timepoint,generator_dispatch_MW,load_shedding_MW,load_MW,net_line_leaving_flow_MW -lima,timepoint_1,-67.08056522433783,-9.97494096311732e-9,0.0,-67.08056523417291 -santiago,timepoint_1,80.0,-9.974940965584796e-9,0.0,79.99999998990339 +lima,timepoint_1,60.31569213226618,-9.974940964403198e-9,0.0,60.31569212229119 +santiago,timepoint_1,-50.0,-9.974940964403193e-9,0.0,-50.00000000997488 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/bus_voltage.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/bus_voltage.csv index aa7960b..d17c3a2 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/bus_voltage.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/bus_voltage.csv @@ -1,3 +1,3 @@ id,bus,timepoint,voltage_magnitude_pu,voltage_angle_deg -0,lima,timepoint_1,1.0,0.0 -1,santiago,timepoint_1,1.2093116675812525,17.191975663648932 +0,lima,timepoint_1,1.0039676883731015,0.0 +1,santiago,timepoint_1,0.9966223958255749,-15.986449720491722 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/costs_summary.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/costs_summary.csv index 004cadd..22bb914 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/costs_summary.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/costs_summary.csv @@ -1,2 +1,2 @@ component,cost -total_cost_USD,-0.0000398997638476992 +total_cost_USD,-0.00003989976385761279 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/generator_dispatch.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/generator_dispatch.csv index 3cbe5a5..3ad6183 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/generator_dispatch.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/generator_dispatch.csv @@ -1,3 +1,3 @@ id,type,generator,timepoint,active_power_MW,reactive_power_MVAR -0,infinite_sources,gen1,timepoint_1,-67.08056522433783,-36.2809234833063 -0,gfmi_c,solar,timepoint_1,80.0,50.227752474633064 +0,infinite_sources,gen1,timepoint_1,60.31569213226618,1.388783529105015 +0,gfmi_c,solar,timepoint_1,-50.0,0.7526101226466527 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/line_flows.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/line_flows.csv index 365c6aa..6eac7b5 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/line_flows.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/line_flows.csv @@ -1,2 +1,2 @@ line,from_bus,to_bus,existing_capacity_MW,active_power_from_bus_MW,reactive_power_from_bus_MVAR,active_power_to_bus_MW,reactive_power_to_bus_MVAR,active_power_loss_MW,reactive_power_loss_MVAR -tx_1,lima,santiago,inf,-67.08056523417287,-36.28092349329843,79.99999998990337,50.22775246504935,12.919434755730506,13.946828971750918 +tx_1,lima,santiago,inf,60.31569212229122,1.3887835191300466,-50.00000000997491,0.7526101126717135,10.315692112316306,2.14139363180176 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/load_shedding.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/load_shedding.csv index 69b1b33..2061806 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/load_shedding.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/load_shedding.csv @@ -1,3 +1,3 @@ bus,timepoint,active_load_shedding_MW,reactive_load_shedding_MVAR -lima,timepoint_1,-9.97494096311732e-9,-9.974940964300128e-9 -santiago,timepoint_1,-9.974940965584796e-9,-9.974940954696962e-9 +lima,timepoint_1,-9.974940964403198e-9,-9.9749409644032e-9 +santiago,timepoint_1,-9.974940964403193e-9,-9.97494096440319e-9 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/reactive_power_balance_by_bus.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/reactive_power_balance_by_bus.csv index 6626494..1f256f2 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/reactive_power_balance_by_bus.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/reactive_power_balance_by_bus.csv @@ -1,3 +1,3 @@ bus,timepoint,generator_dispatch_MVAR,load_shedding_MVAR,load_MVAR,net_line_leaving_flow_MVAR -lima,timepoint_1,-36.2809234833063,-9.974940964300128e-9,0.0,-36.28092349329843 -santiago,timepoint_1,50.227752474633064,-9.974940954696962e-9,0.0,50.22775246504937 +lima,timepoint_1,1.388783529105015,-9.9749409644032e-9,0.0,1.3887835191300466 +santiago,timepoint_1,0.7526101226466527,-9.97494096440319e-9,0.0,0.7526101126717357 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/solver_status.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/solver_status.csv index 0f015d9..69f8c08 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/solver_status.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/ac_power_flow/solver_status.csv @@ -2,4 +2,4 @@ attribute,value solver_name,ipopt solver_status,ok termination_condition,optimal -time_spent_seconds,0.016715049743652344 +time_spent_seconds,0.0771188735961914 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/F.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/F.csv index a6b49a3..f3b6a13 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/F.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/F.csv @@ -1,4 +1,4 @@ -Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_c_0', 'i_bus_D')","('gfmi_c_0', 'i_bus_Q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_c_0', 'i_bus_D')","('gfmi_c_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" "('infinite_sources_0', 'v_ref_d')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'v_ref_q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 @@ -8,11 +8,11 @@ Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","( "('gfmi_c_0', 'v_ref')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 "('gfmi_c_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('pa_rc_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0 -"('pa_rc_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0 -"('pa_rc_1', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('pa_rc_1', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0 -"('se_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-1.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,1.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/G.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/G.csv index 282ae29..703f4ab 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/G.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/G.csv @@ -8,11 +8,11 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('gfmi_c_0', 'v_ref')",0.0,0.0,0.0,0.0,1.0 "('gfmi_c_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_from_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'v_to_bus_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/H.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/H.csv index 05c50bf..8d8fa5a 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/H.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/H.csv @@ -1,11 +1,11 @@ -Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_c_0', 'i_bus_D')","('gfmi_c_0', 'i_bus_Q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" +Index,"('infinite_sources_0', 'i_bus_D')","('infinite_sources_0', 'i_bus_Q')","('gfmi_c_0', 'i_bus_D')","('gfmi_c_0', 'i_bus_Q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" "('infinite_sources_0', 'i_bus_D')",1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('infinite_sources_0', 'i_bus_Q')",0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_D')",0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_Q')",0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/L.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/L.csv index 515e219..279f2e4 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/L.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/component_connection_matrices/L.csv @@ -3,9 +3,9 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('infinite_sources_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/A.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/A.csv index 63dbe2e..813d915 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/A.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/A.csv @@ -1,20 +1,20 @@ -Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_c_0', 'angle_pc')","('gfmi_c_0', 'w_pc')","('gfmi_c_0', 'p_pc')","('gfmi_c_0', 'q_pc')","('gfmi_c_0', 'pi_vc')","('gfmi_c_0', 'i_vsc_d')","('gfmi_c_0', 'i_vsc_q')","('gfmi_c_0', 'i_bus_d')","('gfmi_c_0', 'i_bus_q')","('gfmi_c_0', 'v_lcl_sh_d')","('gfmi_c_0', 'v_lcl_sh_q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" -"('infinite_sources_0', 'i_bus_d')",-7.5398223686155035,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-697.9546674137151,285.21657689930515,0.0,0.0,0.0,0.0 -"('infinite_sources_0', 'i_bus_q')",-376.99111843077515,-7.5398223686155035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-285.21657689930515,-697.9546674137151,0.0,0.0,0.0,0.0 +Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_c_0', 'angle_pc')","('gfmi_c_0', 'w_pc')","('gfmi_c_0', 'p_pc')","('gfmi_c_0', 'q_pc')","('gfmi_c_0', 'pi_vc')","('gfmi_c_0', 'i_vsc_d')","('gfmi_c_0', 'i_vsc_q')","('gfmi_c_0', 'i_bus_d')","('gfmi_c_0', 'i_bus_q')","('gfmi_c_0', 'v_lcl_sh_d')","('gfmi_c_0', 'v_lcl_sh_q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'i_bus_d')",-7.5398223686155035,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-723.1203801581415,-213.50908482472548,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_q')",-376.99111843077515,-7.5398223686155035,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,213.50908482472548,-723.1203801581415,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'angle_pc')",0.0,0.0,0.0,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'w_pc')",0.0,0.0,0.0,-70.0,-1.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'p_pc')",0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,0.0,1305.929900975793,-175.63410139764756,552.3230020226116,-552.3353845084039,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'q_pc')",0.0,0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,-175.63410139764756,-1305.929900975793,552.3353845084039,552.3230020226116,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'pi_vc')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-9.9107712566067,1.3328965073172159,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'i_vsc_d')",0.0,0.0,0.0,-225.20563327909315,0.0,0.0,3769.9111843077517,-75.39822368615502,376.99111843077515,0.0,0.0,-7506.183924847491,502.4901450459911,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'i_vsc_q')",0.0,0.0,0.0,-707.1660898606517,0.0,0.0,0.0,-376.99111843077515,-75.39822368615502,0.0,0.0,0.0,-3769.9111843077517,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'i_bus_d')",0.0,0.0,508.04951771675695,-208.22553435471542,0.0,0.0,0.0,0.0,0.0,-56.54866776461627,376.99111843077515,1884.9555921538758,0.0,0.0,0.0,-1631.2653040736207,-944.4739764110853,0.0,0.0 -"('gfmi_c_0', 'i_bus_q')",0.0,0.0,2222.161205510431,-208.22086626754765,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-56.54866776461627,0.0,1884.9555921538758,0.0,0.0,944.4739764110853,-1631.2653040736207,0.0,0.0 -"('gfmi_c_0', 'v_lcl_sh_d')",0.0,0.0,0.0,-66.21249632048333,0.0,0.0,0.0,3769.9111843077517,0.0,-3769.9111843077517,0.0,-3769.9111843077517,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'v_lcl_sh_q')",0.0,0.0,0.0,-492.3239739610557,0.0,0.0,0.0,0.0,3769.9111843077517,0.0,-3769.9111843077517,-376.99111843077515,-3769.9111843077517,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",5234.6599794295635,2139.124316049167,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,0.0,0.0,-5654.8667481872935,0.0 -"('pa_rc_0', 'v_bus_Q')",-2139.124316049167,5234.6599794295635,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,0.0,0.0,-5654.8667481872935 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,1138.0525352410905,0.0,0.0,0.0,0.0,0.0,0.0,4893.795887751882,-2833.421915066146,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,5654.8667481872935,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,4267.955218941629,0.0,0.0,0.0,0.0,0.0,0.0,2833.421915066146,4893.795887751882,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,5654.8667481872935 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,0.0,-7.5398223686155035,376.99111843077515 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,-376.99111843077515,-7.5398223686155035 +"('gfmi_c_0', 'p_pc')",0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,0.0,987.9260565411992,23.78030884341824,-496.76780316078685,-70.54199784602056,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'q_pc')",0.0,0.0,0.0,0.0,0.0,-1000.0,0.0,0.0,0.0,23.78030884341824,-987.9260565411992,70.54199784602056,-496.76780316078685,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'pi_vc')",0.0,0.0,0.0,0.0,0.0,-0.1,0.0,0.0,0.0,0.0,0.0,-9.997104207562575,-0.24063969567519944,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'i_vsc_d')",0.0,0.0,0.0,346.7421388408102,0.0,-37.69911184307752,3769.9111843077517,-75.39822368615502,376.99111843077515,0.0,0.0,-7538.730680585775,-90.71902801143482,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'i_vsc_q')",0.0,0.0,0.0,158.9980800432565,0.0,0.0,0.0,-376.99111843077515,-75.39822368615502,0.0,0.0,0.0,-3769.9111843077517,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'i_bus_d')",0.0,0.0,-236.09093185117854,-26.593706664312624,0.0,0.0,0.0,0.0,0.0,-56.54866776461627,376.99111843077515,1884.9555921538758,0.0,0.0,0.0,-1732.449388861673,742.7494190000986,0.0,0.0 +"('gfmi_c_0', 'i_bus_q')",0.0,0.0,1863.6945957046444,187.27704971398418,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-56.54866776461627,0.0,1884.9555921538758,0.0,0.0,-742.7494190000986,-1732.449388861673,0.0,0.0 +"('gfmi_c_0', 'v_lcl_sh_d')",0.0,0.0,0.0,8.964965227509495,0.0,0.0,0.0,376.99111843077515,0.0,-376.99111843077515,0.0,-37.69911184307752,376.99111843077515,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'v_lcl_sh_q')",0.0,0.0,0.0,-372.4393489823719,0.0,0.0,0.0,0.0,376.99111843077515,0.0,-376.99111843077515,-376.99111843077515,-37.69911184307752,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",5423.402824069048,-1601.3181281788504,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,0.0,0.0,-5654.8667481872935,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",1601.3181281788504,5423.402824069048,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,0.0,0.0,-5654.8667481872935 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,-740.2906646531766,0.0,0.0,0.0,0.0,0.0,0.0,5197.348140598278,2228.2482458590544,0.0,0.0,0.0,0.0,-282.7433374093647,376.99111843077515,5654.8667481872935,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,-2739.060301026596,0.0,0.0,0.0,0.0,0.0,0.0,-2228.2482458590544,5197.348140598278,0.0,0.0,0.0,0.0,-376.99111843077515,-282.7433374093647,0.0,5654.8667481872935 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,0.0,-7.5398223686155035,376.99111843077515 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,753.9822368615503,0.0,-753.9822368615503,-376.99111843077515,-7.5398223686155035 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/B.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/B.csv index fa9e8a8..4e32179 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/B.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/B.csv @@ -5,16 +5,16 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('gfmi_c_0', 'w_pc')",0.0,0.0,1.0,0.0,0.0 "('gfmi_c_0', 'p_pc')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'q_pc')",0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'pi_vc')",0.0,0.0,0.0,0.0,10.0 -"('gfmi_c_0', 'i_vsc_d')",0.0,0.0,0.0,0.0,3769.9111843077517 +"('gfmi_c_0', 'pi_vc')",0.0,0.0,0.0,0.1,10.0 +"('gfmi_c_0', 'i_vsc_d')",0.0,0.0,0.0,37.69911184307752,3769.9111843077517 "('gfmi_c_0', 'i_vsc_q')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_d')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_q')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'v_lcl_sh_d')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'v_lcl_sh_q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/C.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/C.csv index 424533a..27e8754 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/C.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/C.csv @@ -1,11 +1,11 @@ -Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_c_0', 'angle_pc')","('gfmi_c_0', 'w_pc')","('gfmi_c_0', 'p_pc')","('gfmi_c_0', 'q_pc')","('gfmi_c_0', 'pi_vc')","('gfmi_c_0', 'i_vsc_d')","('gfmi_c_0', 'i_vsc_q')","('gfmi_c_0', 'i_bus_d')","('gfmi_c_0', 'i_bus_q')","('gfmi_c_0', 'v_lcl_sh_d')","('gfmi_c_0', 'v_lcl_sh_q')","('pa_rc_0', 'v_bus_D')","('pa_rc_0', 'v_bus_Q')","('pa_rc_1', 'v_bus_D')","('pa_rc_1', 'v_bus_Q')","('se_rl_0', 'i_br_D')","('se_rl_0', 'i_br_Q')" -"('infinite_sources_0', 'i_bus_D')",0.9256911281079382,0.3782802338772842,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('infinite_sources_0', 'i_bus_Q')",-0.3782802338772842,0.9256911281079382,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'i_bus_D')",0.0,0.0,0.20125187487501822,0.0,0.0,0.0,0.0,0.0,0.0,0.8654131221254014,-0.5010590065582746,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('gfmi_c_0', 'i_bus_Q')",0.0,0.0,0.7547401926508261,0.0,0.0,0.0,0.0,0.0,0.0,0.5010590065582746,0.8654131221254014,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 +Index,"('infinite_sources_0', 'i_bus_d')","('infinite_sources_0', 'i_bus_q')","('gfmi_c_0', 'angle_pc')","('gfmi_c_0', 'w_pc')","('gfmi_c_0', 'p_pc')","('gfmi_c_0', 'q_pc')","('gfmi_c_0', 'pi_vc')","('gfmi_c_0', 'i_vsc_d')","('gfmi_c_0', 'i_vsc_q')","('gfmi_c_0', 'i_bus_d')","('gfmi_c_0', 'i_bus_q')","('gfmi_c_0', 'v_lcl_sh_d')","('gfmi_c_0', 'v_lcl_sh_q')","('shunt_parallel_rc_0', 'v_bus_D')","('shunt_parallel_rc_0', 'v_bus_Q')","('shunt_parallel_rc_1', 'v_bus_D')","('shunt_parallel_rc_1', 'v_bus_Q')","('branch_series_rl_0', 'i_br_D')","('branch_series_rl_0', 'i_br_Q')" +"('infinite_sources_0', 'i_bus_D')",0.9590681912721563,-0.2831752187073487,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('infinite_sources_0', 'i_bus_Q')",0.2831752187073487,0.9590681912721563,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'i_bus_D')",0.0,0.0,-0.1309121324371581,0.0,0.0,0.0,0.0,0.0,0.0,0.9190929463128948,0.3940408050416634,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('gfmi_c_0', 'i_bus_Q')",0.0,0.0,-0.484372209460925,0.0,0.0,0.0,0.0,0.0,0.0,-0.3940408050416634,0.9190929463128948,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,1.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/D.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/D.csv index 515e219..279f2e4 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/D.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/D.csv @@ -3,9 +3,9 @@ Index,"('infinite_sources_0', 'v_ref_d')","('infinite_sources_0', 'v_ref_q')","( "('infinite_sources_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_D')",0.0,0.0,0.0,0.0,0.0 "('gfmi_c_0', 'i_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 -"('pa_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 -"('se_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_0', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_D')",0.0,0.0,0.0,0.0,0.0 +"('shunt_parallel_rc_1', 'v_bus_Q')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_D')",0.0,0.0,0.0,0.0,0.0 +"('branch_series_rl_0', 'i_br_Q')",0.0,0.0,0.0,0.0,0.0 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/u.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/u.csv index e97dff3..0da5867 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/u.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/u.csv @@ -1,6 +1,6 @@ name,component,type,init -v_ref_d,infinite_sources_0,device,0.8770607186443364 -v_ref_q,infinite_sources_0,device,-6.183078103210549e-18 -p_ref,gfmi_c_0,device,0.8183040522662995 -q_ref,gfmi_c_0,device,0.624304539854994 -v_ref,gfmi_c_0,device,1.3176874606052849 +v_ref_d,infinite_sources_0,device,1.0602915467925695 +v_ref_q,infinite_sources_0,device,-6.184065849485258e-17 +p_ref,gfmi_c_0,device,-0.4924473672884809 +q_ref,gfmi_c_0,device,0.05787698596992697 +v_ref,gfmi_c_0,device,0.9882122222891866 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/x.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/x.csv index 85dac69..0abab9f 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/x.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/x.csv @@ -1,20 +1,20 @@ name,component,type,init -i_bus_d,infinite_sources_0,"",-0.7582024031718437 -i_bus_q,infinite_sources_0,"",0.08209677086376665 +i_bus_d,infinite_sources_0,"",0.5722653561902081 +i_bus_q,infinite_sources_0,"",-0.18339083649397844 angle_pc,gfmi_c_0,"",0.0 w_pc,gfmi_c_0,"",0.0 -p_pc,gfmi_c_0,"",0.8183040522662995 -q_pc,gfmi_c_0,"",0.624304539854994 -pi_vc,gfmi_c_0,"",1.4031838768194038 -i_vsc_d,gfmi_c_0,"",1.8758163131381695 -i_vsc_q,gfmi_c_0,"",-0.5973764958084721 -i_bus_d,gfmi_c_0,"",0.5523230020226116 -i_bus_q,gfmi_c_0,"",-0.5523353845084039 -v_lcl_sh_d,gfmi_c_0,"",1.3059299009757932 -v_lcl_sh_q,gfmi_c_0,"",-0.17563410139764757 -v_bus_D,pa_rc_0,"",1.0 -v_bus_Q,pa_rc_0,"",0.0 -v_bus_D,pa_rc_1,"",1.1552793404899095 -v_bus_Q,pa_rc_1,"",0.3574414004915346 -i_br_D,se_rl_0,"",-0.7208056523417289 -i_br_Q,se_rl_0,"",0.2961425679329845 +p_pc,gfmi_c_0,"",-0.4924473672884809 +q_pc,gfmi_c_0,"",0.05787698596992697 +pi_vc,gfmi_c_0,"",0.8875147374562453 +i_vsc_d,gfmi_c_0,"",-0.42175550635008513 +i_vsc_q,gfmi_c_0,"",0.9197620895795204 +i_bus_d,gfmi_c_0,"",-0.49676780316078684 +i_bus_q,gfmi_c_0,"",-0.07054199784602057 +v_lcl_sh_d,gfmi_c_0,"",0.9879260565411991 +v_lcl_sh_q,gfmi_c_0,"",0.02378030884341824 +v_bus_D,shunt_parallel_rc_0,"",1.0039676883731015 +v_bus_Q,shunt_parallel_rc_0,"",0.0 +v_bus_D,shunt_parallel_rc_1,"",0.9580798748577896 +v_bus_Q,shunt_parallel_rc_1,"",-0.2744797866029319 +i_br_D,branch_series_rl_0,"",0.5505748558041546 +i_br_Q,branch_series_rl_0,"",-0.08076412991454072 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/y.csv b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/y.csv index f441917..97bddd7 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/y.csv +++ b/examples/small_signal_and_emt/2-bus_src-gfm/outputs/small_signal_model/y.csv @@ -1,11 +1,11 @@ name,component,type,init -i_bus_D,infinite_sources_0,"",-0.6708056522433783 -i_bus_Q,infinite_sources_0,"",0.36280923483306304 -i_bus_D,gfmi_c_0,"",0.7547401926508261 -i_bus_Q,gfmi_c_0,"",-0.2012518748750182 -v_bus_D,pa_rc_0,"",1.0 -v_bus_Q,pa_rc_0,"",0.0 -v_bus_D,pa_rc_1,"",1.1552793404899095 -v_bus_Q,pa_rc_1,"",0.3574414004915346 -i_br_D,se_rl_0,"",-0.7208056523417289 -i_br_Q,se_rl_0,"",0.2961425679329845 +i_bus_D,infinite_sources_0,"",0.6007732403221651 +i_bus_Q,infinite_sources_0,"",-0.013832950454366671 +i_bus_D,gfmi_c_0,"",-0.484372209460925 +i_bus_Q,gfmi_c_0,"",0.1309121324371581 +v_bus_D,shunt_parallel_rc_0,"",1.0039676883731015 +v_bus_Q,shunt_parallel_rc_0,"",0.0 +v_bus_D,shunt_parallel_rc_1,"",0.9580798748577896 +v_bus_Q,shunt_parallel_rc_1,"",-0.2744797866029319 +i_br_D,branch_series_rl_0,"",0.5505748558041546 +i_br_Q,branch_series_rl_0,"",-0.08076412991454072 diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/run.py b/examples/small_signal_and_emt/2-bus_src-gfm/run.py index bc4a638..5cb7e36 100644 --- a/examples/small_signal_and_emt/2-bus_src-gfm/run.py +++ b/examples/small_signal_and_emt/2-bus_src-gfm/run.py @@ -46,12 +46,12 @@ def step2(t): 'v_ref_d': step2 }, 'gfmi_c_0': { - 'p_ref': step1} + 'p_ref': step2} } t_max = 2.0 # Simulation length # Construct system and small-signal model -_, ssm = main.run_ssm(case_directory=case_dir) +sys, ssm = main.run_ssm(case_directory=case_dir) ssm.simulate_ssm(t_max=t_max, inputs=inputs) # Run EMT simulation main.run_emt(case_directory=case_dir, inputs=inputs, t_max=t_max) diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/ssm_analysis.py b/examples/small_signal_and_emt/2-bus_src-gfm/ssm_analysis.py new file mode 100644 index 0000000..2a08991 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src-gfm/ssm_analysis.py @@ -0,0 +1,157 @@ +""" + +Small signal analysis of GFMI_E v INF source under variation in Pload, Pref, and Qref. + +""" + +# Import Python standard and third-party packages +from pathlib import Path +import numpy as np +import seaborn as sns +import matplotlib.pyplot as plt + +# Import sting package +from sting.system.core import System +from sting.system.operations import SystemModifier +from sting.modules.power_flow.core import ACPowerFlow +from sting.modules.small_signal_modeling.core import SmallSignalModel + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model + +inputs = {} +t_max = 2.0 + +# Load system from CSV files +sys = System.from_csv(case_directory=case_dir) + + +# Define range of P and Q to vary over +n = 11 +Prange = np.linspace(-100,0,n) +Qrange = Prange + +Sbase = 100 # MVA +vdc_ref = 1.05 # pu + +# Case 1: Pref = Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + sys.gfmi_c[0].minimum_active_power_MW = P + sys.gfmi_c[0].maximum_active_power_MW = P + sys.gfmi_c[0].minimum_reactive_power_MVAR = Q + sys.gfmi_c[0].maximum_reactive_power_MVAR = Q + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + +# Plot results +fig, axes = plt.subplots(nrows=1,ncols=3, figsize=(30,10)) + +# Colorbar - use the same range for each +vmin = -6 +vmax = 0 +# Plot small-signal stability heatmap +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[1], vmin=vmin, vmax=vmax, cbar=False, cbar_kws = {'label': 'maximum eig. real part'}) +axes[1].set_xlabel("Q_sh (MVAR)") +axes[1].set_ylabel("P_load (MW)") +axes[1].set_title("Pref = Pload") + +## Case 2: Pref = 0.5*Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + sys.gfmi_c[0].minimum_active_power_MW = P/2 + sys.gfmi_c[0].maximum_active_power_MW = P/2 + sys.gfmi_c[0].minimum_reactive_power_MVAR = Q + sys.gfmi_c[0].maximum_reactive_power_MVAR = Q + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + + +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5, ax=axes[0], vmin=vmin, vmax=vmax, cbar=False, cbar_kws = {'label': 'maximum eig. real part'}) +axes[0].set_xlabel("Q_sh (MVAR)") +axes[0].set_ylabel("P_load (MW)") +axes[0].set_title("Pref = 0.5*Pload") + +## Case 3: Pref = 1.5*Pload +results = np.zeros([n,n]) +i = 0 +for P in Prange: + j = 0 + for Q in Qrange: + sys.gfmi_c[0].minimum_active_power_MW = P*1.5 + sys.gfmi_c[0].maximum_active_power_MW = P*1.5 + sys.gfmi_c[0].minimum_reactive_power_MVAR = Q + sys.gfmi_c[0].maximum_reactive_power_MVAR = Q + + # Run power flow + pf = ACPowerFlow(system=sys, model_settings=None, solver_settings=None) + pf.solve() + + # Break down lines into branches and shunts for small-signal modeling + sys_modifier = SystemModifier(system=sys) + sys_modifier.decompose_lines() + sys_modifier.combine_shunts() + + # Construct small-signal model + ssm = SmallSignalModel(system=sys) + ssm.construct_system_ssm() + + max_eig = np.max(np.linalg.eigvals(ssm.model.A).real) + + results[i,j] = max_eig + j += 1 + i += 1 + +sns.heatmap(results, xticklabels=Qrange, yticklabels=Prange, linewidth=0.5,ax=axes[2], vmin=vmin, vmax=vmax, cbar=True, cbar_kws = {'label': 'maximum eig. real part'}) +axes[2].set_xlabel("Q_sh (MVAR)") +axes[2].set_ylabel("P_load (MW)") +axes[2].set_title("Pref = 1.5*Pload") +fig.suptitle("Effect of Pref v Pload across P & Q space") + +plt.show() +plt.savefig(str(case_dir)+"/ssm_heatmaps.png") + +print('ok') + \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src-gfm/ssm_heatmaps.png b/examples/small_signal_and_emt/2-bus_src-gfm/ssm_heatmaps.png new file mode 100644 index 0000000..1df2492 Binary files /dev/null and b/examples/small_signal_and_emt/2-bus_src-gfm/ssm_heatmaps.png differ diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/buses.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/buses.csv new file mode 100644 index 0000000..3817d3d --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/buses.csv @@ -0,0 +1,3 @@ +name,base_power_MVA,base_voltage_kV,base_frequency_Hz,minimum_voltage_pu,maximum_voltage_pu +lima,1.00E+02,2.30E+02,60,0.95,1.05 +santiago,1.00E+02,2.30E+02,60,0.95,1.05 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/gfli_a.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/gfli_a.csv new file mode 100644 index 0000000..b2beaad --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/gfli_a.csv @@ -0,0 +1,2 @@ +name,bus_idx,p_min,p_max,q_min,q_max,sbase,vbase,fbase,rf1,lf1,rsh,csh,txr_sbase,txr_v1base,txr_v2base,txr_r1,txr_l1,txr_r2,txr_l2,beta,kp_pll,ki_pll,kp_cc,ki_cc,v_dc +solar,2,0.8,0.8,0.5,0.5,1.00E+08,4.80E+02,60,0.02,0.1,1,0.1,1.00E+08,4.80E+02,2.30E+05,0.01,0.1,0.02,0.1,0.75,1,5,1,5,1 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/infinite_sources.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/infinite_sources.csv new file mode 100644 index 0000000..9d95931 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/infinite_sources.csv @@ -0,0 +1,2 @@ +name,bus,minimum_active_power_MW,maximum_active_power_MW,minimum_reactive_power_MVAR,maximum_reactive_power_MVAR,base_power_MVA,base_voltage_kV,base_frequency_Hz,cost_variable_USDperMWh,r_pu,x_pu +gen1,lima,-200,200,-500,500,1.00E+02,2.30E+02,60,0,0.01,0.5 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/lines.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/lines.csv new file mode 100644 index 0000000..74a86b2 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/lines.csv @@ -0,0 +1,2 @@ +name,from_bus,to_bus,base_power_MVA,base_voltage_kV,base_frequency_Hz,r_pu,x_pu,g_pu,b_pu +tx_1,lima,santiago,1.00E+02,2.30E+02,60,0.01,0.5,0.05,0.066666667 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/loads.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/loads.csv new file mode 100644 index 0000000..79d806e --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/loads.csv @@ -0,0 +1,3 @@ +bus,timepoint,load_MW,load_MVAR +lima,t_1,0,0 +chile,t_1,0,0 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/timepoints.csv b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/timepoints.csv new file mode 100644 index 0000000..ad319a5 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/inputs/timepoints.csv @@ -0,0 +1,2 @@ +name +timepoint_1 \ No newline at end of file diff --git a/examples/small_signal_and_emt/2-bus_src_gfli_a/run.py b/examples/small_signal_and_emt/2-bus_src_gfli_a/run.py new file mode 100644 index 0000000..98b8144 --- /dev/null +++ b/examples/small_signal_and_emt/2-bus_src_gfli_a/run.py @@ -0,0 +1,34 @@ + +# Import Python standard and third-party packages +from pathlib import Path + +# Import sting package +from sting import main +from sting.system.core import System + +# Step-change input to applied to the system +def step1(t): + return 0.1 if t >= 0.5 else 0.0 + +def step2(t): + return 0.0 + +inputs = { + 'infinite_sources_0': { + 'v_ref_d': step2 + } + } + +t_max = 2.0 # Simulation length (in seconds) + +# Specify path of the case study directory +case_dir = Path(__file__).resolve().parent + +# Construct system and small-signal model +sys = System.from_csv(case_directory=case_dir) + +# Construct system and small-signal model +_, ssm = main.run_ssm(case_directory=case_dir) +ssm.simulate_ssm(t_max=t_max, inputs=inputs) + +print('\nok') \ No newline at end of file diff --git a/examples/small_signal_and_emt/gfmi_e_v_gfmi_c.py b/examples/small_signal_and_emt/gfmi_e_v_gfmi_c.py new file mode 100644 index 0000000..8f5cb0d --- /dev/null +++ b/examples/small_signal_and_emt/gfmi_e_v_gfmi_c.py @@ -0,0 +1,275 @@ +""" +Compares the EMT and small signal response of the GFMI_C, which does not model the DC side of the converter, +the GFMI_E which models a battery and current-source load on the DC side. + +In progress - March 31 - Ruth +""" + +# Import Python standard and third-party packages +from pathlib import Path +import os +import numpy as np +import pandas as pd +import plotly.graph_objects as go +from plotly.subplots import make_subplots +from scipy.linalg import eig, inv +import seaborn as sns +import matplotlib.pyplot as plt +from sting.utils.transformations import dq02abc, abc2dq0 +from scipy import signal + + +# Import sting package +from sting import main +from sting.system.core import System + +# Specify path of the case study directory + +case_dir_gfmc = os.path.join(Path(__file__).resolve().parent,"2-bus_src-gfm") +case_dir_gfme = os.path.join(Path(__file__).resolve().parent,"2-bus-src-gfmi_e") + +# Define inputs +def step1(t): + return 0.3 if t >= 0.5 else 0.0 + +def step2(t): + return 0.0 + +# Combine inputs for gfmi_c and gfmi_e +inputs = {'infinite_sources_0': {'v_ref_d': step1}, + 'gfmi_e_0': {'p_ref': step2, + 'q_ref': step2, + 'v_ref': step2, + 'v_dc_ref': step2, + 'v_s': step2, + 'i_load_ref': step2}, + 'gfmi_c_0': {'p_ref': step2, + 'q_ref': step2, + 'v_ref': step2}} + +t_max = 2.0 + +# Run GFMI_C +_, ssm_c = main.run_ssm(case_directory=case_dir_gfmc) # Construct system and small-signal model +ssm_c.simulate_ssm(t_max=t_max, inputs=inputs) +sys_c, emt_sc_c = main.run_emt(case_directory=case_dir_gfmc, inputs=inputs, t_max=t_max) # Run EMT simulation + +# Run GFMI_E +_, ssm_e = main.run_ssm(case_directory=case_dir_gfme) # Construct system and small-signal model +ssm_e.simulate_ssm(t_max=t_max, inputs=inputs) +sys_e, emt_sc_e = main.run_emt(case_directory=case_dir_gfme, inputs=inputs, t_max=t_max) # Run EMT simulation + + +# # Compare eigenvalues of A matrix +# gfmic_A = pd.read_csv(case_dir_gfmc+"/outputs/small_signal_model/A.csv") +# gfmie_A = pd.read_csv(case_dir_gfme+"/outputs/small_signal_model/A.csv") + +# gfmie_eigs = np.linalg.eigvals(gfmie_A.iloc[:,1:].to_numpy()) +# gfmic_eigs = np.linalg.eigvals(gfmic_A.iloc[:,1:].to_numpy()) + +# # Plot eigenvalues +# fig = make_subplots( +# rows=1, cols=1, +# horizontal_spacing=0.15, +# vertical_spacing=0.05, +# ) + +# fig.add_trace(go.Scatter(x=gfmie_eigs.real, y=gfmie_eigs.imag, name="GFMI_E", mode="markers", marker=dict(size=12, opacity=1.0, symbol="circle", line=dict(color="black", width=1)))) +# fig.add_trace(go.Scatter(x=gfmic_eigs.real, y=gfmic_eigs.imag, name="GFMI_C", mode="markers", marker=dict(size=12, opacity=0.5, symbol="square", line=dict(color="black", width=1)))) +# fig.show() +# fig.write_html("examples/small_signal_and_emt/2-bus-scr-gfm_comparison/eig_comparison.html") + +# Compare EMT traces +gfmi_c = pd.read_csv(case_dir_gfmc+"/outputs/simulation_emt/gfmi_c_0_states.csv") +gfmi_e = pd.read_csv(case_dir_gfme+"/outputs/simulation_emt/gfmi_e_0_states.csv") + +fig = make_subplots( + rows=9, cols=2, + horizontal_spacing=0.15, + vertical_spacing=0.05, +) + +tps = gfmi_c["time"] + +# converting abc to dq +# GFMI_E +i_bus_de, i_bus_qe, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_e["i_bus_a"], gfmi_e["i_bus_b"], gfmi_e["i_bus_c"], gfmi_e["angle_pc"])]) +i_vsc_de, i_vsc_qe, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_e["i_vsc_a"], gfmi_e["i_vsc_b"], gfmi_e["i_vsc_c"], gfmi_e["angle_pc"])]) +v_sh_de, v_sh_qe, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_e["v_sh_a"], gfmi_e["v_sh_b"], gfmi_e["v_sh_c"], gfmi_e["angle_pc"])]) + +# GFMI_c +i_bus_dc, i_bus_qc, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_c["i_bus_a"], gfmi_c["i_bus_b"], gfmi_c["i_bus_c"], gfmi_c["angle_pc"])]) +i_vsc_dc, i_vsc_qc, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_c["i_vsc_a"], gfmi_c["i_vsc_b"], gfmi_c["i_vsc_c"], gfmi_c["angle_pc"])]) +v_sh_dc, v_sh_qc, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(gfmi_c["v_sh_a"], gfmi_c["v_sh_b"], gfmi_c["v_sh_c"], gfmi_c["angle_pc"])]) + +r, c = 1,1 +fig.add_trace(go.Scatter(x=tps, y=gfmi_c["angle_pc"], name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["angle_pc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='angle_pc', row=r, col=c) + +r, c = 1,2 +fig.add_trace(go.Scatter(x=tps, y=gfmi_c["w_pc"], name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["w_pc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='w_pc', row=r, col=c) + +r, c = 2,1 +fig.add_trace(go.Scatter(x=tps, y=gfmi_c["p_pc"], name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["p_pc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p_pc', row=r, col=c) + +r, c = 2,2 +fig.add_trace(go.Scatter(x=tps, y=gfmi_c["q_pc"], name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["q_pc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='q_pc', row=r, col=c) + +r, c = 3,1 +fig.add_trace(go.Scatter(x=tps, y=gfmi_c["gamma"], name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["gamma"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='gamma', row=r, col=c) + +r, c = 4,1 +fig.add_trace(go.Scatter(x=tps, y=i_vsc_dc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_vsc_de, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_vsc_d', row=r, col=c) + +r, c = 4,2 +fig.add_trace(go.Scatter(x=tps, y=i_vsc_qc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_vsc_qe, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_vsc_q', row=r, col=c) + +r, c = 5,1 +fig.add_trace(go.Scatter(x=tps, y=v_sh_dc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=v_sh_de, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='v_sh_d', row=r, col=c) + +r, c = 5,2 +fig.add_trace(go.Scatter(x=tps, y=v_sh_qc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=v_sh_qe, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='v_sh_q', row=r, col=c) + +r, c = 6,1 +fig.add_trace(go.Scatter(x=tps, y=i_bus_dc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_bus_de, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_bus_d', row=r, col=c) + +r, c = 6,2 +fig.add_trace(go.Scatter(x=tps, y=i_bus_qc, name="GFMI_C", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=r, col=c) +fig.add_trace(go.Scatter(x=tps, y=i_bus_qe, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_bus_q', row=r, col=c) + +r, c = 7,1 +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["i_L"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_L', row=r, col=c) + +r, c = 7,2 +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["v_dc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='v_dc', row=r, col=c) + +r, c = 8,1 +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["i_load"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='i_load', row=r, col=c) + +r, c = 8,2 +fig.add_trace(go.Scatter(x=tps, y=gfmi_e["soc"], name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='soc', row=r, col=c) + +r, c = 9,1 +p_load = np.multiply(gfmi_e["i_load"],gfmi_e["v_dc"]) +fig.add_trace(go.Scatter(x=tps, y=p_load, name="GFMI_E", mode='lines', line=dict(color='blue', dash='dot'), legendgroup='1'), row=r, col=c) +fig.update_xaxes(title_text='Time [s]', row=r, col=c) +fig.update_yaxes(title_text='p_load', row=r, col=c) + + + +# r, c = 9, 1 +# duty_cycle = self.kp_i_L*(self.kp_v_dc*(v_dc_ref - v_dcf) + x1 - i_Lf + self.Kff_idc*i_dcf + self.Kff_iload*i_loadf) + x2 +# duty_cycle = np.clip(duty_cycle, 0.0, 1.0) +# fig.add_trace(go.Scatter(x=tps, y=duty_cycle, name="duty cycle", mode='lines', line=dict(color='blue', dash='dot')), +# row=r, col=c) +# fig.update_xaxes(title_text='Time [s]', row=r, col=c) +# fig.update_yaxes(title_text='duty cycle [p.u.]', row=r, col=c) + + + +fig.update_layout(height=1200*2, + width=800*2, + legend_tracegroupgap=400, + showlegend=False, + margin={'t': 0, 'l': 0, 'b': 0, 'r': 0}) + + + +fig.show() +fig.write_html("examples/small_signal_and_emt/gfmi_e_vs_gfmi_c_emt_traces.html") + + +## Print nadir/rocof + +# Measure some performance metrics - frequency ROCOF and nadir and steady state error ? +gfm = emt_sc_c.system.gfmi_c[0].variables_emt.x.value +w_pc = gfm[1,:] +# nadir +nadir_c = np.min(w_pc) +tps = np.linspace(0, t_max, 500) +dt = tps[1] - tps[0] + +# rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) +df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof +df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) +rocof_c = np.max(df_dt_ma) + +gfm = emt_sc_e.system.gfmi_e[0].variables_emt.x.value +w_pc = gfm[1,:] +# nadir +nadir_e = np.min(w_pc) +tps = np.linspace(0, t_max, 500) +dt = tps[1] - tps[0] + +# rocof - calculate as a moving average of duration 100ms (~25 timesteps for us) +df_dt = np.abs(np.diff(w_pc)/dt) # calculate raw rocof +df_dt_ma = np.convolve(df_dt,np.ones(25)/25) # get moving averages over 25 time steps (~100ms) +rocof_e = np.max(df_dt_ma) + + + +# participation factor analysis - can turn this into a function / method for SSM class + +# def participation_factor_plot(ssm): +# w,vr = eig(ssm.model.A) +# vl = inv(vr) # ensures normalization + +# p = np.zeros_like(vl) +# for i in range(len(w)): +# for k in range(len(w)): +# # use correct formula for complex eigenvalues +# p[k, i] = (vl[i,k].real)**2/(np.dot(vl[i,:].real,vl[i,:].real)) # participation of k-th state (row) in i-th mode (column) + +# pf_df = pd.DataFrame(p.real, index=ssm.model.x.name) +# ax = sns.heatmap(pf_df, yticklabels=pf_df.index, xticklabels=w.real>0, linewidths=1, linecolor='white') +# ax.set_yticklabels(ax.get_yticklabels(), fontsize=8) +# ax.set_xticklabels(ax.get_xticklabels(), fontsize=8) +# plt.show() +# plt.savefig("ssm.png") + + +# participation_factor_plot(ssm_c) +# participation_factor_plot(ssm_e) + + + +print('ok') diff --git a/sting/generator/gfli_c.py b/sting/generator/gfli_c.py new file mode 100644 index 0000000..1d9f15c --- /dev/null +++ b/sting/generator/gfli_c.py @@ -0,0 +1,234 @@ +""" +Untested, still in development. +""" + +# Import standard python packages +import pandas as pd +import numpy as np +from scipy.linalg import block_diag +from dataclasses import dataclass, field +from typing import NamedTuple, Optional + +# Import src packages +from sting.utils import linear_systems_tools +from sting.utils.linear_systems_tools import State_space_model + + +class Power_flow_variables(NamedTuple): + p_bus: float + q_bus: float + vmag_bus: float + vphase_bus: float + + +class EMT_initial_conditions(NamedTuple): + vmag_bus: float + vphase_bus: float + p_bus: float + q_bus: float + angle_ref: float + pi_cc_d: float + pi_cc_q: float + i_bus_d: float + i_bus_q: float + i_bus_D: float + i_bus_Q: float + v_bus_D: float + v_bus_Q: float + v_vsc_mag: float + v_vsc_DQ_phase: float + + +@dataclass(slots=True) +class GFLI_c: + """Grid-following inverter that has L filter and PI current controller. No PLL and No DC-side + dynamics are included.""" + + idx: str + bus_idx: str + p_min: float + p_max: float + q_min: float + q_max: float + sbase: float + vbase: float + vbase: float + fbase: float + v_dc: float + rf: float + lf: float + txr_sbase: float + txr_r1: float + txr_l1: float + txr_r2: float + txr_l2: float + beta: float + kp_cc: float + ki_cc: float + name: str = field(default_factory=str) + type: str = "generator" + pf: Optional[Power_flow_variables] = None + emt_init_cond: Optional[EMT_initial_conditions] = None + ssm: Optional[State_space_model] = None + + @property + def txr_r(self): + return (self.txr_r1 + self.txr_r2) * self.sbase / self.txr_sbase + + @property + def txr_l(self): + return (self.txr_l1 + self.txr_l2) * self.sbase / self.txr_sbase + + @property + def wbase(self): + return 2 * np.pi * self.fbase + + def _load_power_flow_solution(self, power_flow_instance): + sol = power_flow_instance.generators.loc[self.idx] + self.pf = Power_flow_variables( + p_bus=sol.p.item(), + q_bus=sol.q.item(), + vmag_bus=sol.bus_vmag.item(), + vphase_bus=sol.bus_vphase.item(), + ) + + def _calculate_emt_initial_conditions(self): + vmag_bus = self.pf.vmag_bus + vphase_bus = self.pf.vphase_bus + p_bus = self.pf.p_bus + q_bus = self.pf.q_bus + + # Voltage in the end of the L filter + v_bus_DQ = vmag_bus * np.exp(vphase_bus * np.pi / 180 * 1j) + ref_angle = np.angle(v_bus_DQ, deg=True) + + # Current sent from the end of the L filter + i_bus_DQ = (p_bus - q_bus * 1j) / np.conjugate(v_bus_DQ) + + # Voltage at vsc + v_vsc_DQ = ( + v_bus_DQ + (self.rf + self.txr_r + (self.lf + self.txr_l) * 1j) * i_bus_DQ + ) + + # We refer the voltage and currents to the synchronous frames of the + # inverter + v_vsc_dq = v_vsc_DQ * np.exp(-ref_angle * np.pi / 180 * 1j) + v_bus_dq = v_bus_DQ * np.exp(-ref_angle * np.pi / 180 * 1j) + i_bus_dq = i_bus_DQ * np.exp(-ref_angle * np.pi / 180 * 1j) + + # Initial conditions for the integral controller + pi_cc_dq = ( + v_vsc_dq - 1j * (self.lf + self.txr_l) * i_bus_dq - self.beta * v_bus_dq + ) + + self.emt_init_cond = EMT_initial_conditions( + vmag_bus=vmag_bus, + vphase_bus=vphase_bus, + p_bus=p_bus, + q_bus=q_bus, + angle_ref=ref_angle, + pi_cc_d=pi_cc_dq.real, + pi_cc_q=pi_cc_dq.imag, + i_bus_d=i_bus_dq.real, + i_bus_q=i_bus_dq.imag, + i_bus_D=i_bus_DQ.real, + i_bus_Q=i_bus_DQ.imag, + v_bus_D=v_bus_DQ.real, + v_bus_Q=v_bus_DQ.imag, + v_vsc_mag=abs(v_vsc_DQ), + v_vsc_DQ_phase=np.angle(v_vsc_DQ, deg=True), + ) + + def _build_small_signal_model(self): + + # Current PI controller + kp_cc, ki_cc = self.kp_cc, self.ki_cc + pi_cc_d, pi_cc_q = self.emt_init_cond.pi_cc_d, self.emt_init_cond.pi_cc_q + + pi_controller = State_space_model( + A=np.zeros((2, 2)), + B=ki_cc * np.hstack((np.eye(2), -np.eye(2))), + C=np.eye(2), + D=kp_cc * np.hstack((np.eye(2), -np.eye(2))), + inputs=["i_bus_d_ref", "i_bus_q_ref"], + states=["pi_cc_d", "pi_cc_q"], + outputs=["e_d", "e_q"], + initial_states=np.array([[pi_cc_d], [pi_cc_q]]), + ) + + # L filter + rf = self.rf + self.txr_r + lf = self.lf + self.txr_l + wb = self.wbase + beta = self.beta + i_bus_d, i_bus_q = self.emt_init_cond.i_bus_d, self.emt_init_cond.i_bus_q + sinphi = np.sin(self.emt_init_cond.angle_ref * np.pi / 180) + cosphi = np.cos(self.emt_init_cond.angle_ref * np.pi / 180) + # fmt: off + l_filter = State_space_model( A = wb*np.array([[-rf/lf, 1], + [-1 , -rf/lf]]), + B = wb*np.array([[ 1/lf , 0 ,-1/lf ,0] , + [0, 1/lf, 0, -1/lf]]), + C = np.eye(2), + D = np.zeros((2,4)), + states= ['i_bus_d', 'i_bus_q'], + inputs=['v_vsc_d', 'v_vsc_q', 'v_bus_d', 'v_bus_q'], + outputs=['i_bus_d', 'i_bus_q'], + initial_states = np.array([[i_bus_d], [i_bus_q]])) + + + # Interconnection matrices + Fccm = np.vstack( ( np.zeros((1,4)) , + np.zeros((1,4)) , + np.hstack((np.zeros((2,2)), np.eye(2))), + [1, 0, 0, -lf ], + [0, 1, lf, 0 ], + np.zeros((2,4)) )) + + Gccm = np.vstack(( [ 1, 0, 0, 0], + [0, 1, 0, 0], + np.zeros((2,4)), + [0, 0, beta*cosphi , beta*sinphi], + [0, 0, -beta*sinphi, beta*cosphi], + [0, 0, cosphi ,sinphi], + [0, 0, -sinphi ,cosphi], + ) ) + + Hccm = np.vstack(( [ 0, 0 ,cosphi , -sinphi], + [0, 0, sinphi , cosphi ] )) + # fmt: on + Lccm = np.zeros((2, 4)) + + # Generate small-signal model + ssm = linear_systems_tools.connect_models_via_CCM( + Fccm, Gccm, Hccm, Lccm, [pi_controller, l_filter] + ) + + # Note that states and initial states do not need to be defined as they result from stacking states in ccm tool. + + # Inputs and outputs + device_side_inputs = ["i_bus_d_ref", "i_bus_q_ref"] + initial_device_side_inputs = np.array([[i_bus_d], [i_bus_q]]) + + grid_side_inputs = ["v_bus_D", "v_bus_Q"] + v_bus_D, v_bus_Q = self.emt_init_cond.v_bus_D, self.emt_init_cond.v_bus_Q + initial_grid_side_inputs = np.array([[v_bus_D], [v_bus_Q]]) + + outputs = ["i_bus_D", "i_bus_Q"] + i_bus_D, i_bus_Q = self.emt_init_cond.i_bus_D, self.emt_init_cond.i_bus_Q + initial_outputs = np.array([[i_bus_D], [i_bus_Q]]) + + self.ssm = State_space_model( + A=ssm.A, + B=ssm.B, + C=ssm.C, + D=ssm.D, + states=ssm.states, + initial_states=ssm.initial_states, + outputs=outputs, + initial_outputs=initial_outputs, + device_side_inputs=device_side_inputs, + initial_device_side_inputs=initial_device_side_inputs, + grid_side_inputs=grid_side_inputs, + initial_grid_side_inputs=initial_grid_side_inputs, + ) diff --git a/sting/generator/gfli_e.py b/sting/generator/gfli_e.py new file mode 100644 index 0000000..26ce334 --- /dev/null +++ b/sting/generator/gfli_e.py @@ -0,0 +1,576 @@ +""" +This module implements a GFLI that incorporates: +- LCL filter: Two Series RL branches (one branch is the transformer) and one Parallel RC shunt. +- Outer DC voltage controller +- DC-side capacitor dynamics with resistor and current source representing a load +- Current controller: A dq-based frame PI controller +- PLL: A basic implementation + +""" +# ---------------------- +# Import python packages +# ---------------------- +import numpy as np +from dataclasses import dataclass, field +from typing import NamedTuple, Optional +import scipy.linalg + +# ------------------ +# Import sting code +# ------------------ +from sting.utils.dynamical_systems import StateSpaceModel, DynamicalVariables +from sting.utils.transformations import dq02abc, abc2dq0 +from sting.generator.core import Generator + +# ----------- +# Sub-classes +# ----------- +class PowerFlowVariables(NamedTuple): + p_bus: float + q_bus: float + vmag_bus: float + vphase_bus: float + + +class InitialConditionsEMT(NamedTuple): + vmag_bus: float + vphase_bus: float + p_bus: float + q_bus: float + angle_ref: float + pi_cc_d: float + pi_cc_q: float + i_vsc_d: float + i_vsc_q: float + i_bus_d: float + i_bus_q: float + v_lcl_sh_d: float + v_lcl_sh_q: float + i_bus_D: float + i_bus_Q: float + v_bus_D: float + v_bus_Q: float + v_vsc_mag: float + v_vsc_DQ_phase: float + v_vsc_d: float + v_vsc_q: float + p_vsc: float + v_dc: float + int_vdc: float + i_dc: float + i_load_ref: float + + +class VariablesEMT(NamedTuple): + x: DynamicalVariables + u: DynamicalVariables + y: DynamicalVariables + +# ----------- +# Main class +# ----------- +@dataclass(slots=True, kw_only=True, eq=False) +class GFLIe(Generator): + rf1_pu: float + lf1_pu: float + rsh_pu: float + csh_pu: float + txr_power_MVA: float + txr_voltage1_kV: float + txr_voltage2_kV: float + txr_r1_pu: float + txr_l1_pu: float + txr_r2_pu: float + txr_l2_pu: float + beta: float + kp_pll_pu: float + ki_pll_puHz: float + kp_cc_pu: float + ki_cc_puHz: float + v_dc_ref: float # added + c_dc: float # added + kp_oc_pu: float # added + ki_oc_puHz: float # added + Tload: float # added + r_dc: float # added + x_pll_rescale: np.ndarray = field(default_factory=lambda: np.array([[100, 0], [0, 1]])) + name: str = field(default_factory=str) + emt_init: Optional[InitialConditionsEMT] = None + ssm: Optional[StateSpaceModel] = None + + @property + def rf2_pu(self): + return (self.txr_r1_pu + self.txr_r2_pu) * self.base_power_MVA / self.txr_power_MVA + + @property + def lf2_pu(self): + return (self.txr_l1_pu + self.txr_l2_pu) * self.base_power_MVA / self.txr_power_MVA + + @property + def wbase(self): + return 2 * np.pi * self.base_frequency_Hz + + def _build_small_signal_model(self): + + # Current PI controller + kp_cc, ki_cc = self.kp_cc_pu, self.ki_cc_puHz + pi_cc_d, pi_cc_q = self.emt_init.pi_cc_d, self.emt_init.pi_cc_q + + pi_controller = StateSpaceModel( A = np.zeros((2,2)), + B = ki_cc*np.hstack((np.eye(2), -np.eye(2))), + C = np.eye(2), + D = kp_cc*np.hstack((np.eye(2), -np.eye(2))), + u = DynamicalVariables(name=['i_bus_d_ref', 'i_bus_q_ref', 'i_bus_d', 'i_bus_q']), + y = DynamicalVariables(name=['e_d', 'e_q']), + x = DynamicalVariables( name=['pi_cc_d', 'pi_cc_q'], + init= [pi_cc_d, pi_cc_q]) ) + + # LCL filter + rf1, lf1, rf2, lf2, rsh, csh = self.rf1_pu, self.lf1_pu, self.rf2_pu, self.lf2_pu, self.rsh_pu, self.csh_pu + wb = self.wbase + i_vsc_d, i_vsc_q = self.emt_init.i_vsc_d, self.emt_init.i_vsc_q + i_bus_d, i_bus_q = self.emt_init.i_bus_d, self.emt_init.i_bus_q + v_lcl_sh_d, v_lcl_sh_q = self.emt_init.v_lcl_sh_d, self.emt_init.v_lcl_sh_q + + lcl_filter = StateSpaceModel( + A = wb*np.array([[-rf1/lf1 , 1 , 0 , 0 , -1/lf1 , 0], + [-1 , -rf1/lf1, 0 , 0 , 0 , -1/lf1], + [0 , 0 , -rf2/lf2 , 1 , 1/lf2 , 0], + [0 , 0 , -1 , -rf2/lf2, 0 , 1/lf2], + [1/csh , 0 , -1/csh , 0 , -1/(rsh*csh), 1], + [0 , 1/csh , 0 , -1/csh , -1 , -1/(rsh*csh)]]), + B = wb*np.array([[1/lf1 , 0 , 0 , 0 , i_vsc_q], + [0 , 1/lf1 , 0 , 0 , -i_vsc_d], + [0 , 0 , -1/lf2 , 0 , i_bus_q], + [0 , 0 , 0 , -1/lf2 , -i_bus_d], + [0 , 0 , 0 , 0 , v_lcl_sh_q], + [0 , 0 , 0 , 0 , -v_lcl_sh_d]]), + C = np.eye(6), + D = np.zeros((6,5)), + x = DynamicalVariables(name=["i_vsc_d", "i_vsc_q", "i_bus_d", "i_bus_q", "v_lcl_sh_d", "v_lcl_sh_q"], + init=[i_vsc_d, i_vsc_q, i_bus_d, i_bus_q, v_lcl_sh_d, v_lcl_sh_q]), + u = DynamicalVariables(name=['v_vsc_d', 'v_vsc_q', 'v_bus_d', 'v_bus_q', 'w']), + y = DynamicalVariables(name=["i_vsc_d", "i_vsc_q", "i_bus_d", "i_bus_q", "v_lcl_sh_d", "v_lcl_sh_q"])) + + # Phase-locked loop + kp_pll, ki_pll = self.kp_pll_pu, self.ki_pll_puHz + beta = self.beta + vmag_bus = self.emt_init.vmag_bus + sinphi = np.sin(self.emt_init.angle_ref*np.pi/180) + cosphi = np.cos(self.emt_init.angle_ref*np.pi/180) + int_pll = 0 + phase_pll = self.emt_init.angle_ref*np.pi/180 + + pll = StateSpaceModel( A = np.array([ [ 0 , -vmag_bus*ki_pll], + [wb , -wb*vmag_bus*kp_pll]]), + B = np.array([ [-sinphi*ki_pll , +cosphi*ki_pll], + [-wb*kp_pll*sinphi, wb*kp_pll*cosphi]]), + C = np.array([ [0 , 1], + [1 , -1*vmag_bus*kp_pll]]), + D = np.array([ [0 , 0], + [-1*kp_pll*sinphi , 1*kp_pll*cosphi]]), + u = DynamicalVariables(name=['v_bus_D', 'v_bus_Q']), + y = DynamicalVariables(name=['phase', 'w']), + x = DynamicalVariables(name=["int_pll", "phase_pll"], + init=[int_pll, phase_pll] ) ) + + # Re-scale the states so that they are not very small numbers compared to + # other states. It was tested in EMT simulation. + pll.A = self.x_pll_rescale @ pll.A @ scipy.linalg.inv(self.x_pll_rescale) + pll.B = self.x_pll_rescale @ pll.B + pll.C = pll.C @ scipy.linalg.inv(self.x_pll_rescale) + + # Outer control + DC capacitor dynamics + Kp, Ki, Cdc, Tload, r_dc = self.kp_oc_pu, self.ki_oc_puHz, self.c_dc, self.Tload, self.r_dc + outer_control = StateSpaceModel(A = np.array([[0, Ki, 0], + [0, -1/r_dc, -wb/Cdc], + [0, 0, -1/Tload]]), + B = np.array([[-Ki, 0, 0], + [0, -wb/Cdc, -wb/Cdc], + [0, 1/Tload, 0]]), + C = np.array([[1, Kp, 0], + [0, 1, 0]]), + D = np.array([[-Kp, 0, 0], + [0, 0, 0]]), + u = DynamicalVariables(name=["v_dc_ref", "i_load_ref", "idc"]), + y = DynamicalVariables(name=["i_bus_d_ref", "v_dc"]), + x = DynamicalVariables(name=["int_vdc", "v_dc", "i_load"], + init=[self.emt_init.int_vdc, self.emt_init.v_dc, self.emt_init.i_load_ref])) + + # Construction of CCM matrices + # ustack = F*ystack + G*u + + # ustack = i2dq_c, v1dq_c, v2dq_c, w, v2dq, vdcref, iload_ref, idc (12) + # y_stack = e1d, e1q, i1d_c, i1q_c, i2d_c, i2q_c, v3d_c, v3q_c, theta, w, i2d_ref, vdc (12) + # u = vdc_ref, iload_ref, i2q_ref, v2d, v2q + # y = i2dq + + # dc power balance linearization + v_dc = self.emt_init.v_dc + + b1 = self.emt_init.v_vsc_d/v_dc # i1d + b2 = self.emt_init.i_vsc_d/v_dc #e1d + b3 = - (self.emt_init.i_vsc_d/v_dc)*(self.lf1_pu+self.lf2_pu) #i2q + b4 = self.emt_init.v_vsc_q/v_dc # i1q + b5 = self.emt_init.i_vsc_q/v_dc # e1q + b6 = (self.emt_init.i_vsc_q/v_dc)*(self.lf1_pu+self.lf2_pu) #i2d + b7 = - self.emt_init.i_dc/v_dc #vdc + b8 = -(self.emt_init.i_vsc_q/v_dc)*self.beta*vmag_bus # theta + + # Construction of CCM matrices + Fccm = np.vstack( ( np.hstack((np.zeros((10, )), 1, 0)) ,# i2d_ref + np.zeros((12,)), # i2q_ref + np.hstack((np.zeros((2,4)), np.eye(2) ,np.zeros((2,6)))), # i2dq_c + [1, 0, 0, 0, 0, -(lf1+lf2), 0, 0, 0, 0, 0, 0], # v1d_c + [0, 1, 0, 0, (lf1+lf2), 0, 0, 0, -beta*vmag_bus, 0, 0, 0], # v1q_c + np.zeros((12, )) , # v2d_c + np.append( np.zeros((8,)) , [-vmag_bus, 0, 0, 0] ), # v2q_c + np.append( np.zeros((9,)) , [1, 0, 0] ), # w + np.zeros((2, 12)), # v2_dq + np.zeros((2, 12)), #vdc_ref, iload_ref + [b2, b5, b1, b4, b6, b3, 0, 0, b8, 0, 0, b7] #idc + ) + ) + + + Gccm = np.vstack(( np.zeros(5,), # i2ref_d, + [0, 0, 1, 0, 0], #i2q_ref + np.zeros((2,5)), #i2dq_c, + [0, 0, 0, beta*cosphi , beta*sinphi], # v1d_c + [0, 0, 0, -beta*sinphi, beta*cosphi], # v1q_c + [0, 0, 0, cosphi ,sinphi], # v2d_c + [0, 0, 0, -sinphi ,cosphi], # v2q_c + np.zeros((5, )), # w + np.hstack((np.zeros((2,3)), np.eye(2) ) ), # v2dq + [1, 0, 0, 0, 0], #vdc_ref + [0, 1, 0, 0, 0], #iload_ref + np.zeros((1,5)) # idc + ) + ) + + Hccm = np.vstack(( [ 0, 0 , 0, 0, cosphi , -sinphi, 0, 0, -sinphi*i_bus_d-cosphi*i_bus_q, 0, 0, 0], + [0, 0, 0, 0, sinphi , cosphi , 0, 0, cosphi*i_bus_d-sinphi*i_bus_q, 0, 0, 0] )) + + Lccm = np.zeros((2, 5)) + + components = [pi_controller, lcl_filter, pll, outer_control] + connections = [Fccm, Gccm, Hccm, Lccm] + + # Inputs and outputs + v_bus_D, v_bus_Q= self.emt_init.v_bus_D, self.emt_init.v_bus_Q + u = DynamicalVariables( + name=["v_dc_ref", "i_load_ref", "i_bus_q_ref", "v_bus_D", "v_bus_Q"], + type=["device", "device", "device", "grid", "grid"], + init=[self.emt_init.v_dc, self.emt_init.i_load_ref, self.emt_init.i_bus_q, v_bus_D, v_bus_Q]) + + i_bus_D, i_bus_Q= self.emt_init.i_bus_D, self.emt_init.i_bus_Q + y = DynamicalVariables( + name=['i_bus_D', 'i_bus_Q'], + init=[i_bus_D, i_bus_Q]) + + # Generate small-signal model + ssm = StateSpaceModel.from_interconnected(components, connections, u, y, component_label=f"{self.type_}_{self.id}") + + self.ssm = ssm + + def _calculate_emt_initial_conditions(self): + + + # Extract power flow solution + vmag_bus = self.power_flow_variables.vmag_bus + vphase_bus = self.power_flow_variables.vphase_bus + p_bus = self.power_flow_variables.p_bus + q_bus = self.power_flow_variables.q_bus + + # Voltage in the end of the LCL filter + v_bus_DQ = vmag_bus * np.exp(vphase_bus * np.pi / 180 * 1j) + angle_ref = np.angle(v_bus_DQ, deg=True) + + # Current sent from the end of the LCL filter + i_bus_DQ = (p_bus - q_bus * 1j) / np.conjugate(v_bus_DQ) + + # Voltage across the shunt element in the LCL filter + v_lcl_sh_DQ = v_bus_DQ + (self.rf2_pu + self.lf2_pu * 1j) * i_bus_DQ + + # Current flowing through shunt element of LCL filter + i_lcl_sh_DQ = v_lcl_sh_DQ * (self.csh_pu * 1j) + v_lcl_sh_DQ / self.rsh_pu + + # Current sent from the beginning of the LCL filter + i_vsc_DQ = i_bus_DQ + i_lcl_sh_DQ + v_vsc_DQ = v_lcl_sh_DQ + (self.rf1_pu + self.lf1_pu * 1j) * i_vsc_DQ + + # We refer the voltage and currents to the synchronous frames of the + # inverter + v_vsc_dq = v_vsc_DQ * np.exp(-angle_ref * np.pi / 180 * 1j) + i_vsc_dq = i_vsc_DQ * np.exp(-angle_ref * np.pi / 180 * 1j) + + v_bus_dq = v_bus_DQ * np.exp(-angle_ref * np.pi / 180 * 1j) + i_bus_dq = i_bus_DQ * np.exp(-angle_ref * np.pi / 180 * 1j) + + v_lcl_sh_dq = v_lcl_sh_DQ * np.exp(-angle_ref * np.pi / 180 * 1j) + + # Initial conditions for the integral controller + pi_cc_dq = ( + v_vsc_dq - self.beta * v_bus_dq - 1j * (self.lf1_pu + self.lf2_pu) * i_bus_dq + ) + + # DC-side initial conditions + v_dc = self.v_dc_ref + p_vsc = (v_vsc_dq*np.conjugate(i_vsc_dq)).real # power at converter terminals + i_dc = p_vsc/v_dc + i_load = -v_dc/self.r_dc - i_dc + + self.emt_init = InitialConditionsEMT( + vmag_bus=vmag_bus, + vphase_bus=vphase_bus, + p_bus=p_bus, + q_bus=q_bus, + angle_ref=angle_ref, + pi_cc_d=pi_cc_dq.real, + pi_cc_q=pi_cc_dq.imag, + i_vsc_d=i_vsc_dq.real, + i_vsc_q=i_vsc_dq.imag, + i_bus_d=i_bus_dq.real, + i_bus_q=i_bus_dq.imag, + v_lcl_sh_d=v_lcl_sh_dq.real, + v_lcl_sh_q=v_lcl_sh_dq.imag, + i_bus_D=i_bus_DQ.real, + i_bus_Q=i_bus_DQ.imag, + v_bus_D=v_bus_DQ.real, + v_bus_Q=v_bus_DQ.imag, + v_vsc_mag = abs(v_vsc_DQ), + v_vsc_DQ_phase = np.angle(v_vsc_DQ, deg=True), + v_dc=v_dc, + p_vsc=p_vsc, + i_dc=i_dc, + int_vdc=i_bus_dq.real, + i_load_ref=i_load, + v_vsc_d=v_vsc_dq.real, + v_vsc_q=v_vsc_dq.imag + ) + + def define_variables_emt(self): + # States + # ------ + + # Initial conditions + angle_ref = self.emt_init.angle_ref + pi_cc_d, pi_cc_q = self.emt_init.pi_cc_d, self.emt_init.pi_cc_q + + # these quantities are already in the converter ref frame (defined by angle_ref) + i_bus_d, i_bus_q = self.emt_init.i_bus_d, self.emt_init.i_bus_q + i_vsc_d, i_vsc_q = self.emt_init.i_vsc_d, self.emt_init.i_vsc_q + v_sh_d, v_sh_q = self.emt_init.v_lcl_sh_d, self.emt_init.v_lcl_sh_q + + # convert to abc + i_bus_a, i_bus_b, i_bus_c = dq02abc(i_bus_d, i_bus_q, 0, angle_ref*np.pi/180) + i_vsc_a, i_vsc_b, i_vsc_c = dq02abc(i_vsc_d, i_vsc_q, 0, angle_ref*np.pi/180) + v_sh_a, v_sh_b, v_sh_c = dq02abc(v_sh_d, v_sh_q, 0, angle_ref*np.pi/180) + + x = DynamicalVariables( + name = ['pi_cc_d', 'pi_cc_q', 'theta_pll', 'gamma_pll', "i_vsc_a", "i_vsc_b", "i_vsc_c", "v_sh_a", "v_sh_b","v_sh_c", "i_bus_a", "i_bus_b", "i_bus_c", "int_vdc", "v_dc", "i_load"], + component = f"{self.type_}_{self.id}", + init = [pi_cc_d, pi_cc_q, angle_ref * np.pi/180, 0, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, self.emt_init.int_vdc, self.emt_init.v_dc, self.emt_init.i_load_ref] + ) + + # Inputs + # ------ + + # Initial conditions + v_bus_D, v_bus_Q = self.emt_init.v_bus_D, self.emt_init.v_bus_Q + v_bus_a, v_bus_b, v_bus_c = dq02abc(v_bus_D, v_bus_Q, 0, 0) + + u = DynamicalVariables( + name=["v_dc_ref", "i_load_ref", "i_bus_q_ref", "v_bus_a", "v_bus_b", "v_bus_c"], + component=f"{self.type_}_{self.id}", + type=["device", "device", "device", "grid", "grid", "grid"], + init=[self.emt_init.v_dc, self.emt_init.i_load_ref, self.emt_init.i_bus_q, v_bus_a, v_bus_b, v_bus_c] + ) + + # Outputs + # ------- + + y = DynamicalVariables( + name=["i_bus_a", "i_bus_b", "i_bus_c"], + component=f"{self.type_}_{self.id}", + init=[i_bus_a, i_bus_b, i_bus_c] + ) + + self.variables_emt = VariablesEMT(x=x,u=u,y=y) + + def get_derivative_state_emt(self): + """ + It returns a vector with the differential equations that describe the dynamics of the GFLI. + This model includes: pi controller, pll, and LCL filter. + """ + # Get state values # here in progress + pi_cc_d, pi_cc_q, theta_pll, gamma_pll, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, int_vdc, v_dc, i_load = self.variables_emt.x.value + + # Get input values (external inputs) + v_dc_ref, i_load_ref, i_bus_q_ref, v_bus_a, v_bus_b, v_bus_c = self.variables_emt.u.value + + # convert relevant quantities to dq + v_bus_d, v_bus_q, _ = abc2dq0(v_bus_a, v_bus_b, v_bus_c, theta_pll) + i_bus_d, i_bus_q, _ = abc2dq0(i_bus_a, i_bus_b, i_bus_c, theta_pll) + + # Update algebraic states + + # outer loop Vdc control + i_bus_d_ref = self.kp_oc_pu*(-v_dc_ref + v_dc) + int_vdc + + # current controller output + e_d = pi_cc_d + self.kp_cc_pu * (i_bus_d_ref - i_bus_d) + e_q = pi_cc_q + self.kp_cc_pu * (i_bus_q_ref - i_bus_q) + + v_vsc_d = e_d + self.beta * v_bus_d - (self.lf1_pu + self.lf2_pu) * i_bus_q + v_vsc_q = e_q + self.beta * v_bus_q + (self.lf1_pu + self.lf2_pu) * i_bus_d + + # calculate idc + i_vsc_d, i_vsc_q, _ = abc2dq0(i_vsc_a, i_vsc_b, i_vsc_c, theta_pll) + i_dc = (v_vsc_d*i_vsc_d + v_vsc_q*i_vsc_q)/v_dc + + # convert to abc to feed into filter dynamics + v_vsc_a, v_vsc_b, v_vsc_c = dq02abc(v_vsc_d, v_vsc_q, 0, theta_pll) + + def current_controller_dynamics(y, internal_inputs): + """ + It returns the differential equations that describe the dynamics of the current controller. + The current controller has: virtual inertia, filter for active and reactive power. + """ + + # Definition of states for the ODEs of the current controller + pi_cc_d, pi_cc_q = y[0], y[1] + + # Extract the list of parameters + kp_cc = self.kp_cc_pu # proportional gain of current controller + ki_cc = self.ki_cc_puHz # integral gain of current controller + + # Define internal inputs for the current controller at timepoint "t" + i_bus_d_ref, i_bus_q_ref, i_bus_d, i_bus_q = internal_inputs + + # Define ODEs that describe the dynamics of the current controller + d_pi_cc_d = ki_cc * (i_bus_d_ref - i_bus_d) + d_pi_cc_q = ki_cc * (i_bus_q_ref - i_bus_q) + + return [d_pi_cc_d, d_pi_cc_q] + + def pll_dynamics(y, internal_inputs): + """ + It returns the differential equations that describe the dynamics of the PLL. + The PLL tracks the phase of the grid voltage. + """ + # Definition of states for the ODEs of the pll + theta_pll, gamma_pll = y[0], y[1] + + # Extract the list of parameters + kp_pll = self.kp_pll_pu # proportional gain of PLL + ki_pll = self.ki_pll_puHz # integral gain of PLL + w_base = self.wbase # base frequency of the system + + # Define voltage at bus + v_bus_q = internal_inputs + + # Define ODEs that describe the dynamics of the PLL + d_theta_pll = kp_pll * v_bus_q * w_base + gamma_pll + w_base + d_gamma_pll = ki_pll * v_bus_q + + return [d_theta_pll, d_gamma_pll] + + def lcl_filter_dynamics(y, internal_inputs): + """ + It returns the differential equations that describe the dynamics of the LCL filter. + The LCL filter connects the VSC to the grid. It has three branches: the first branch (RL) connects + the VSC to the shunt element, the second branch is the shunt element (RC), and the third branch (RL) + connects the shunt element to the grid. + """ + + # Definition of states for the ODEs of the LCL filter + i_vsc_a , i_vsc_b, i_vsc_c = y[0], y[1], y[2] # currents flowing out of VSC + v_sh_a, v_sh_b, v_sh_c = y[3], y[4], y[5] # currents flowing through paralell RC shunt + i_bus_a, i_bus_b, i_bus_c = y[6], y[7], y[8] # currents flowing to bus + + # Extract the list of parameters + r1 = self.rf1_pu # resistance [p.u.] of first branch of filter + l1 = self.lf1_pu # inductance [p.u.] of first branch of filter + r2 = self.rf2_pu # resistance [p.u.] of second branch of filter + l2 = self.lf2_pu # inductance [p.u.] of second branch of filter + rsh = self.rsh_pu # resistance [p.u.] of series RC shunt + csh = self.csh_pu # capacitance [p.u.] of series RC shunt + wb = self.wbase # nominal frequency of the system + + # Define voltage at vsc at timepoint "t" + v_vsc_a, v_vsc_b, v_vsc_c, v_bus_a, v_bus_b, v_bus_c = internal_inputs + + # Define ODEs that describe the dynamics of the LCL filter + di_vsc_a = wb/l1 *(v_vsc_a - v_sh_a - r1 * i_vsc_a) + di_vsc_b = wb/l1 *(v_vsc_b - v_sh_b - r1 * i_vsc_b) + di_vsc_c = wb/l1 *(v_vsc_c - v_sh_c - r1 * i_vsc_c) + + dv_sh_a = wb/csh * (-v_sh_a/rsh + i_vsc_a - i_bus_a) + dv_sh_b = wb/csh * (-v_sh_b/rsh + i_vsc_b - i_bus_b) + dv_sh_c = wb/csh * (-v_sh_c/rsh + i_vsc_c - i_bus_c) + + di_bus_a = wb/l2 *(v_sh_a - v_bus_a - r2 * i_bus_a) + di_bus_b = wb/l2 *(v_sh_b - v_bus_b - r2 * i_bus_b) + di_bus_c = wb/l2 *(v_sh_c - v_bus_c - r2 * i_bus_c) + + return [di_vsc_a, di_vsc_b, di_vsc_c, dv_sh_a, dv_sh_b, dv_sh_c, di_bus_a, di_bus_b, di_bus_c] + + def outer_loop_and_dc_side(y, internal_inputs): + int_vdc, v_dc, i_load = y[0], y[1], y[2] + + v_dc_ref, i_load_ref, i_dc = internal_inputs + + d_int_vdc = self.ki_oc_puHz*(-v_dc_ref + v_dc) + d_vdc = (self.wbase/self.c_dc)*(-i_load - v_dc/self.r_dc - i_dc) + d_iload = 1/(self.Tload)*(i_load_ref - i_load) + + return [d_int_vdc, d_vdc, d_iload] + + d_pi_cc_d, d_pi_cc_q = current_controller_dynamics([pi_cc_d, pi_cc_q], [i_bus_d_ref, i_bus_q_ref, i_bus_d, i_bus_q]) + + d_theta_pll, d_gamma_pll = pll_dynamics([theta_pll, gamma_pll], v_bus_q) + + di_vsc_a, di_vsc_b, di_vsc_c, dv_sh_a, dv_sh_b, dv_sh_c, di_bus_a, di_bus_b, di_bus_c = lcl_filter_dynamics([i_vsc_a , i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c], [v_vsc_a, v_vsc_b, v_vsc_c, v_bus_a, v_bus_b, v_bus_c]) + + d_int_vdc, d_vdc, d_iload = outer_loop_and_dc_side([int_vdc, v_dc, i_load], [v_dc_ref, i_load_ref, i_dc]) + + return [d_pi_cc_d, d_pi_cc_q, d_theta_pll, d_gamma_pll, di_vsc_a, di_vsc_b, di_vsc_c, dv_sh_a, dv_sh_b, dv_sh_c, di_bus_a, di_bus_b, di_bus_c, d_int_vdc, d_vdc, d_iload] + + def get_output_emt(self): + + pi_cc_d, pi_cc_q, theta_pll, gamma_pll, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, int_vdc, v_dc, i_load = self.variables_emt.x.value + return [i_bus_a, i_bus_b, i_bus_c] + + def plot_results_emt(self) -> DynamicalVariables: + """ + Plot EMT simulation results + """ + + pi_cc_d, pi_cc_q, theta_pll, gamma_pll, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, int_vdc, v_dc, i_load = self.variables_emt.x.value + + tps = self.variables_emt.x.time + + # Transform abc to dq0 + i_vsc_d, i_vsc_q, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(i_vsc_a, i_vsc_b, i_vsc_c, theta_pll)]) + v_sh_d, v_sh_q, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(v_sh_a, v_sh_b, v_sh_c, theta_pll)]) + i_bus_d, i_bus_q, _ = zip(*[abc2dq0(a, b, c, ang) for a, b, c, ang in zip(i_bus_a, i_bus_b, i_bus_c, theta_pll)]) + + v_sh_dq = v_sh_d + np.multiply(v_sh_q, 1j) + i_vsc_dq = i_vsc_d + np.multiply(i_vsc_q, 1j) + i_bus_dq = i_bus_d + np.multiply(i_bus_q, 1j) + v_vsc_dq = v_sh_dq + np.multiply((self.rf1_pu + self.lf1_pu * 1j), i_vsc_dq) + p_vsc = (v_vsc_dq*np.conjugate(i_vsc_dq)).real + + p_cap = (v_sh_dq*np.conjugate(i_bus_dq)).real + q_cap = (v_sh_dq*np.conjugate(i_bus_dq)).imag + + p_load = v_dc*i_load + + results = DynamicalVariables( + name=['pi_cc_d', 'pi_cc_q', 'theta_pll', 'gamma_pll', 'i_vsc_d', 'i_vsc_q', 'v_sh_d', 'v_sh_q', 'i_bus_d', 'i_bus_q', 'int_vdc', 'v_dc', 'i_load', 'p_vsc', 'p_cap', 'pload', 'q_cap'], + component=f"{self.type_}_{self.id}", + value=[pi_cc_d, pi_cc_q, theta_pll, gamma_pll, i_vsc_d, i_vsc_q, v_sh_d, v_sh_q, i_bus_d, i_bus_q, int_vdc, v_dc, i_load, p_vsc, p_cap, p_load, q_cap], + time=tps + ) + return results \ No newline at end of file diff --git a/sting/generator/gfmi_e.py b/sting/generator/gfmi_e.py index 99cb9db..7a06f9f 100644 --- a/sting/generator/gfmi_e.py +++ b/sting/generator/gfmi_e.py @@ -113,12 +113,12 @@ class GFMIe(Generator): Ti_load: float # for DC/DC controller - measurement filter Tload: float # time constant for actuation of load current change i_load_ref: float - #bus_id: int = None + Pbat_max_pu: float # maximum power capacity of battery (pu by S) + SOC_max_pu: float # maximum energy capacity of battery (pu by S) + SOC_init_pu: float # initial battery state of charge (pu) name: str = field(default_factory=str) - #pf: Optional[Power_flow_variables] = None emt_init: Optional[InitialConditionsEMT] = None ssm: Optional[StateSpaceModel] = None - #tags: ClassVar[list[str]] = ["generator"] @property def rf2_pu(self): @@ -470,9 +470,9 @@ def define_variables_emt(self): v_dc, i_dc, i_L, x1, x2, i_load = self.emt_init.v_dc, self.emt_init.i_dc, self.emt_init.i_L, self.emt_init.x_1, self.emt_init.x_2, self.emt_init.i_load x = DynamicalVariables( - name = ['angle_pc', 'w_pc', 'p_pc', 'q_pc', 'gamma',"i_vsc_a", "i_vsc_b","i_vsc_c", "v_sh_a", "v_sh_b","v_sh_c", "i_bus_a", "i_bus_b", "i_bus_c", 'i_l_f', 'v_dc_f', 'i_dc_f', 'i_load_f','x_1', 'x_2', 'i_L', 'v_dc', 'i_load'], + name = ['angle_pc', 'w_pc', 'p_pc', 'q_pc', 'gamma',"i_vsc_a", "i_vsc_b","i_vsc_c", "v_sh_a", "v_sh_b","v_sh_c", "i_bus_a", "i_bus_b", "i_bus_c", 'i_l_f', 'v_dc_f', 'i_dc_f', 'i_load_f','x_1', 'x_2', 'i_L', 'v_dc', 'i_load', 'soc', 'x3'], component = f"{self.type_}_{self.id}", - init=[angle_ref*np.pi/180, 1.0, p_ref, q_ref, v_vsc_d, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_L, v_dc, i_dc, i_load, x1, x2, i_L, v_dc, i_load] + init=[angle_ref*np.pi/180, 1.0, p_ref, q_ref, v_vsc_d, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_L, v_dc, i_dc, i_load, x1, x2, i_L, v_dc, i_load, self.SOC_init_pu, 0.0] ) # Inputs @@ -504,7 +504,7 @@ def define_variables_emt(self): def get_derivative_state_emt(self): # Get state values - angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load = self.variables_emt.x.value + angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load, soc, x3 = self.variables_emt.x.value # Get input values (external inputs) p_ref, q_ref, v_ref, v_dc_ref, v_s, i_load_ref, v_bus_a, v_bus_b, v_bus_c = self.variables_emt.u.value @@ -515,20 +515,24 @@ def get_derivative_state_emt(self): i_vsc_d, i_vsc_q, _ = abc2dq0(i_vsc_a, i_vsc_b, i_vsc_c, angle_pc) # Do Q-V droop - v_sh_mag_ref = v_ref - self.droop_q_pu*(q_pc - q_ref) # droop on error from ref + v_sh_mag_ref = v_ref - self.droop_q_pu*(q_pc - q_ref) # adjusting voltage reference based on reactive power error (measured at capacitor) # NB updating algebraic states! + # Updating converter terminal voltages v_vsc_d = gamma + self.kp_vc_pu*(v_sh_mag_ref - (v_sh_d**2 + v_sh_q**2)**0.5) # update v_vsc_q = 0.0 # update + # # check magnitude wrt v_dc and limit if necessary + # if v_vsc_d > v_dc: # can check only d component because v_vsc_q= 0 + # v_vsc_d = v_dc + # convert to abc to feed into filter dynamics v_vsc_a, v_vsc_b, v_vsc_c = dq02abc(v_vsc_d, v_vsc_q, 0, angle_pc) # correct to use this angle? - # power balance + # DC/AC power balance i_dc = (v_vsc_d*i_vsc_d + v_vsc_q*i_vsc_q)/v_dc - # abc->dq conversions # Differential equations # ---------------------- @@ -623,7 +627,7 @@ def dc_side(y, internal_inputs): DC-DC controller + circuit + load control """ # Define states - i_Lf, v_dcf, i_dcf, i_loadf, x_1, x_2, i_L, v_dc, i_load = y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7], y[8] + i_Lf, v_dcf, i_dcf, i_loadf, x_1, x_2, i_L, v_dc, i_load, soc = y[0], y[1], y[2], y[3], y[4], y[5], y[6], y[7], y[8], y[9] # Inputs i_dc, i_load_ref, v_dc_ref, v_s = internal_inputs @@ -632,6 +636,11 @@ def dc_side(y, internal_inputs): l_dc, c_dc, TiL, Tvdc, Tidc, Kp_vdc, Ki_vdc, Kp_iL, Ki_iL, Kff_idc, Kff_iload, Ti_load, Tload = self.l_dc, self.c_dc, self.Ti_L, self.Tv_dc, self.Ti_dc, self.kp_v_dc, self.ki_v_dc, self.kp_i_L, self.ki_i_L, self.Kff_idc, self.Kff_iload, self.Ti_load, self.Tload wb = self.wbase + # # DC side limits + # # P_battery = i_L*v_s + # if i_L > 1.0: + # i_L = 1.0 + # ODEs # DC-DC controller @@ -643,6 +652,14 @@ def dc_side(y, internal_inputs): d_x_2 = Ki_iL*(Kp_vdc*(v_dc_ref - v_dcf) + x_1 - i_Lf + Kff_idc*i_dcf + Kff_iload*i_loadf) duty_cycle = Kp_iL*(Kp_vdc*(v_dc_ref - v_dcf) + x_1 - i_Lf + Kff_idc*i_dcf + Kff_iload*i_loadf) + x_2 + # # limit duty cycle + # if duty_cycle > 0.9: + # duty_cycle = 0.9 + + d_soc = i_L*v_s + # soc controller + d_x3 = (soc - self.SOC_init_pu) + # Circuit equations d_v_dc = (wb/c_dc)*(-i_dc - i_load + (1-duty_cycle)*i_L) d_i_L = (wb/l_dc)*(v_s - (1-duty_cycle)*v_dc) @@ -650,14 +667,13 @@ def dc_side(y, internal_inputs): # Load control d_i_load = (1/Tload)*(i_load_ref - i_load) - return [d_i_Lf, d_v_dcf, d_i_dcf, d_i_load_f, d_x_1, d_x_2, d_i_L, d_v_dc, d_i_load] - #return [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] + return [d_i_Lf, d_v_dcf, d_i_dcf, d_i_load_f, d_x_1, d_x_2, d_i_L, d_v_dc, d_i_load, d_soc, d_x3] dy_pc = power_controller_dynamics([angle_pc, w_pc, p_pc, q_pc], [v_sh_d, v_sh_q, i_bus_d, i_bus_q, p_ref]) dy_vc = voltage_controller_dynamics([gamma], [v_sh_mag_ref, v_sh_d, v_sh_q]) dy_lcl = lcl_filter_dynamics([i_vsc_a , i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c], [v_vsc_a, v_vsc_b, v_vsc_c, v_bus_a, v_bus_b, v_bus_c]) - dy_dc_side = dc_side([i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load], [i_dc, i_load_ref, v_dc_ref, v_s]) + dy_dc_side = dc_side([i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load, soc, x3], [i_dc, i_load_ref, v_dc_ref, v_s]) return np.hstack([dy_pc, dy_vc, dy_lcl, dy_dc_side]) @@ -665,13 +681,15 @@ def dc_side(y, internal_inputs): def get_output_emt(self): # Output is i_bus_abc - angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load = self.variables_emt.x.value + angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load, soc, x3 = self.variables_emt.x.value return [i_bus_a, i_bus_b, i_bus_c] def plot_results_emt(self, output_dir): - angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load = self.variables_emt.x.value + angle_pc, w_pc, p_pc, q_pc, gamma, i_vsc_a, i_vsc_b, i_vsc_c, v_sh_a, v_sh_b, v_sh_c, i_bus_a, i_bus_b, i_bus_c, i_Lf, v_dcf, i_dcf, i_loadf, x1, x2, i_L, v_dc, i_load, soc, x3 = self.variables_emt.x.value + + #i_L = np.clip(i_L, -1000.0, 1.0) tps = self.variables_emt.x.time @@ -686,9 +704,7 @@ def plot_results_emt(self, output_dir): v_vsc_dq = v_sh_dq + np.multiply((self.rf1_pu + self.xf1_pu * 1j), i_vsc_dq) fig = make_subplots( - rows=12, cols=2, - horizontal_spacing=0.15, - vertical_spacing=0.05, + rows=14, cols=2 ) fig.add_trace(go.Scatter(x=tps, y=w_pc, mode='lines', line=dict(color='red', dash='solid')), @@ -721,8 +737,6 @@ def plot_results_emt(self, output_dir): fig.update_xaxes(title_text='Time [s]', row=3, col=2) fig.update_yaxes(title_text='iload_f [p.u.]', row=3, col=2) - - fig.add_trace(go.Scatter(x=tps, y=i_vsc_d, mode='lines', line=dict(color='red', dash='solid')), row=4, col=1) fig.update_xaxes(title_text='Time [s]', row=4, col=1) @@ -800,16 +814,20 @@ def plot_results_emt(self, output_dir): p_load = i_load*v_dc p_ref, q_ref, v_ref, v_dc_ref, v_s, i_load_ref, v_bus_a, v_bus_b, v_bus_c = self.variables_emt.u.value p_bat = i_L*v_s - fig.add_trace(go.Scatter(x=tps, y=p_vsc, name="p_vsc", mode='lines', line=dict(color='red', dash='solid')), + p_capacitor = p_vsc + p_load - p_bat + fig.add_trace(go.Scatter(x=tps, y=p_vsc, name="p_vsc", mode='lines', line=dict(color='red', dash='solid'), legendgroup='1'), row=11, col=1) - fig.add_trace(go.Scatter(x=tps, y=p_load, name="p_load", mode='lines', line=dict(color='blue', dash='solid')), + fig.add_trace(go.Scatter(x=tps, y=p_load, name="p_load", mode='lines', line=dict(color='blue', dash='solid'), legendgroup='1'), row=11, col=1) - fig.add_trace(go.Scatter(x=tps, y=p_bat, name="p_bat", mode='lines', line=dict(color='green', dash='solid')), + fig.add_trace(go.Scatter(x=tps, y=p_bat, name="p_bat", mode='lines', line=dict(color='green', dash='solid'), legendgroup='1'), + row=11, col=1) + fig.add_trace(go.Scatter(x=tps, y=p_capacitor, name="p_cap", mode='lines', line=dict(color='pink', dash='solid'), legendgroup='1'), + row=11, col=1) + fig.add_trace(go.Scatter(x=tps, y=np.ones_like(p_bat)*self.Pbat_max_pu, name="p_bat_lim", mode='lines', line=dict(color='green', dash='dot'), legendgroup='1'), row=11, col=1) - fig.update_xaxes(title_text='Time [s]', row=11, col=1) - fig.update_yaxes(title_text='p [p.u.]', row=11, col=1) + fig.update_yaxes(title_text='power [p.u.]', row=11, col=1) # v_vsc (calculated) fig.add_trace(go.Scatter(x=tps, y=v_vsc_dq.real, mode='lines', line=dict(color='red', dash='solid')), @@ -822,6 +840,32 @@ def plot_results_emt(self, output_dir): fig.update_xaxes(title_text='Time [s]', row=12, col=2) fig.update_yaxes(title_text='v_vsc_q [p.u.]', row=12, col=2) + e_cap = 0.5*self.c_dc*(v_dc**2) + e_ind = 0.5*self.l_dc*(i_L**2) + fig.add_trace(go.Scatter(x=tps, y=soc, name='battery soc', mode='lines', line=dict(color='red', dash='solid')), + row=13, col=1) + fig.add_trace(go.Scatter(x=tps, y=e_cap, name='cap energy', mode='lines', line=dict(color='blue', dash='dot')), + row=13, col=1) + fig.add_trace(go.Scatter(x=tps, y=e_ind, name='ind energy', mode='lines', line=dict(color='pink', dash='dot')), + row=13, col=1) + + fig.add_trace(go.Scatter(x=tps, y=np.ones_like(soc)*self.SOC_max_pu, name="soc lim", mode='lines', line=dict(color='green', dash='dot')), + row=13, col=1) + fig.update_xaxes(title_text='Time [s]', row=13, col=1) + fig.update_yaxes(title_text='energy [p.u.]', row=13, col=1) + + duty_cycle = self.kp_i_L*(self.kp_v_dc*(v_dc_ref - v_dcf) + x1 - i_Lf + self.Kff_idc*i_dcf + self.Kff_iload*i_loadf) + x2 + duty_cycle = np.clip(duty_cycle, 0.0, 1.0) + fig.add_trace(go.Scatter(x=tps, y=duty_cycle, name="duty cycle", mode='lines', line=dict(color='red', dash='solid')), + row=13, col=2) + fig.update_xaxes(title_text='Time [s]', row=13, col=2) + fig.update_yaxes(title_text='duty cycle [p.u.]', row=13, col=2) + + fig.add_trace(go.Scatter(x=tps, y=x3, mode='lines', line=dict(color='red', dash='solid')), + row=14, col=1) + fig.update_xaxes(title_text='Time [s]', row=14, col=1) + fig.update_yaxes(title_text='x3 [p.u.]', row=14, col=1) + name = f"{self.type_}_{self.id}" fig.update_layout( title_text = name, @@ -829,9 +873,9 @@ def plot_results_emt(self, output_dir): showlegend = False, ) - fig.update_layout(height=1200*2, + fig.update_layout(height=1200*3, width=800*2, - showlegend=False, + showlegend=True, margin={'t': 0, 'l': 0, 'b': 0, 'r': 0}) fig.write_html(os.path.join(output_dir, name + ".html")) diff --git a/sting/system/core.py b/sting/system/core.py index aaddfa3..976f144 100644 --- a/sting/system/core.py +++ b/sting/system/core.py @@ -28,6 +28,7 @@ from sting.generator.gfmi_c import GFMIc from sting.generator.gfmi_d import GFMId from sting.generator.gfmi_e import GFMIe +from sting.generator.gfli_e import GFLIe from sting.reduced_order_model.linear_subsystem import LinearSubsystem from sting.line.pi_model import LinePiModel from sting.branch.series_rl import BranchSeriesRL @@ -59,6 +60,7 @@ class System: gfmi_d: list[GFMId] = None gfmi_e: list[GFMIe] = None gfli_a: list[GFLIa] = None + gfli_e: list[GFLIe] = None linear_subsystems: list[LinearSubsystem] = None buses: list[Bus] = None loads: list[Load] = None