diff --git a/docs/make.jl b/docs/make.jl index b3311add38..bd72aca01d 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -12,7 +12,7 @@ pages = OrderedDict( "Tutorials" => Any[ "Create and Explore a Power `System`" => "tutorials/creating_system.md", "Working with Time Series" => "tutorials/working_with_time_series.md", - "Adding dynamic devices" => "tutorials/add_dynamic_device.md", + "Adding Data for Dynamic Simulations" => "tutorials/add_dynamic_data.md", ], "How to..." => Any[ "...install PowerSystems.jl" => "how_to/install.md", @@ -37,7 +37,7 @@ pages = OrderedDict( "explanation/type_structure.md", "explanation/per_unit.md", "explanation/time_series.md", - "explanation/example_dynamic_data.md", + "explanation/dynamic_data.md", ], "Model Library" => Any[], "Reference" => diff --git a/docs/src/explanation/dynamic_data.md b/docs/src/explanation/dynamic_data.md new file mode 100644 index 0000000000..b365b671ff --- /dev/null +++ b/docs/src/explanation/dynamic_data.md @@ -0,0 +1,83 @@ +# Dynamic Devices + +## Static and Dynamic Data Layers + +`PowerSystems.jl` uses two data layers to define data for dynamic simulations: +1. [Static](@ref S) components, which includes the data needed to run a power flow problem +2. [Dynamic](@ref D) components are those that define differential equations to run a transient simulation. These dyanamic + data are attached to the static components. + +Although `PowerSystems.jl` is not constrained to only PSS/e files, commonly the data for a +dynamic simulation comes in a pair of files: One for the static data power flow case (e.g., +`.raw` file) and a second one with the dynamic components information (e.g., `.dyr` file). +However, `PowerSystems.jl` is able to take any power flow case and specify dynamic +components to it. The two data layers in `PowerSystems.jl` are similar to the data +division between those two files. + +### Layer 1: Static Components + +The first data layer contains all the information necessary to run a power flow problem: + +- Vector of `Bus` elements, that define all the buses in the network. +- Vector of `Branch` elements, that define all the branches elements (that connect two buses) in the network. +- Vector of `StaticInjection` elements, that define all the devices connected to buses that can inject (or withdraw) power. These static devices, typically generators, in `PowerSimulationsDynamics` are used to solve the Power Flow problem that determines the active and reactive power provided for each device. +- Vector of `PowerLoad` elements, that define all the loads connected to buses that can withdraw current. These are also used to solve the Power Flow. +- Vector of `Source` elements, that define source components behind a reactance that can inject or withdraw current. +- The base of power used to define per unit values, in MVA as a `Float64` value. +- The base frequency used in the system, in Hz as a `Float64` value. + +### Layer 2: Dynamic Components + +The second data layer contains the *additional* information describing the dynamic response +of certain components in the `System`. This data is all attached to components defined in +the static data layer: + +- (Optional) Selecting which of the `Lines` (of the `Branch` vector) elements must be modeled of `DynamicLines` elements, that can be used to model lines with differential equations. +- Vector of `DynamicInjection` elements. These components must be attached to a `StaticInjection` that connects the power flow solution to the dynamic formulation of such device. + +`DynamicInjection` can be `DynamicGenerator` or `DynamicInverter`, and its specific formulation (i.e. differential equations) will depend on the specific components that define each device (see the sections below). As +a result, it is possible to flexibly define dynamic data models and methods according to +the analysis requirements. [`DynamicInjection`](@ref) components use a parametric +type pattern to materialize the full specification of the dynamic injection model with +parameters. This design enable the use of parametric methods to specify the mathematical +model of the dynamic components separately. + +[`DynamicInjection`](@ref) components also implement some additional information useful for +the modeling, like the usual states assumed by the model and the number of states. These values are +derived from the documentation associated with the model, for instance PSS/e models provide +parameters, states and variables. Although `PowerSystems.jl` doesn't assume a specific +mathematical model for the components, the default values for these parameters are derived +directly from the data model source. + +## Dynamic Generator Structure + +Each generator is a data structure that is defined by the following components: + +- [Machine](@ref Machine): That defines the stator electro-magnetic dynamics. +- [Shaft](@ref Shaft): That describes the rotor electro-mechanical dynamics. +- [Automatic Voltage Regulator](@ref AVR): Electromotive dynamics to model an AVR controller. +- [Power System Stabilizer](@ref PSS): Control dynamics to define an stabilization signal for the AVR. +- [Prime Mover and Turbine Governor](@ref TurbineGov): Thermo-mechanical dynamics and associated controllers. + +```@raw html + +``` + +## Dynamic Inverter Structure + +Each inverter is a data structure that is defined by the following components: + +- [DC Source](@ref DCSource): Defines the dynamics of the DC side of the converter. +- [Frequency Estimator](@ref FrequencyEstimator): That describes how the frequency of the grid + can be estimated using the grid voltages. Typically a phase-locked loop (PLL). +- [Outer Loop Control](@ref OuterControl): That describes the active and reactive power + control dynamics. +- [Inner Loop Control](@ref InnerControl): That can describe virtual impedance, + voltage control and current control dynamics. +- [Converter](@ref Converter): That describes the dynamics of the pulse width modulation (PWM) + or space vector modulation (SVM). +- [Filter](@ref Filter): Used to connect the converter output to the grid. + +```@raw html + +``` ⠀ diff --git a/docs/src/explanation/example_dynamic_data.md b/docs/src/explanation/example_dynamic_data.md deleted file mode 100644 index b64f61a3dd..0000000000 --- a/docs/src/explanation/example_dynamic_data.md +++ /dev/null @@ -1,46 +0,0 @@ -# Dynamic Devices - -Each sub-type is composed of the corresponding dynamic components that define the model. As -a result, it is possible to flexibly define dynamic data models and methods according to -the analysis requirements. [`DynamicInjection`](@ref) components use parametric a parametric -type pattern to materialize the full specification of the dynamic injection model with -parameters. This design enable the use of parametric methods to specify the mathematical -model of the dynamic components separately. - -[`DynamicInjection`](@ref) components also implement some additional information useful for -the modeling like the usual states assumed by the model and the number. These values are -derived from the documentation associated with the model, for instance PSS/e models provide -parameters, states and variables. Although `PowerSystems.jl` doesn't assume a specific -mathematical model for the components, the default values for these parameters are derived -directly from the data model source. - -## Dynamic Generator - -Each generator is a data structure that is defined by the following components: - -- [Machine](@ref Machine): That defines the stator electro-magnetic dynamics. -- [Shaft](@ref Shaft): That describes the rotor electro-mechanical dynamics. -- [Automatic Voltage Regulator](@ref AVR): Electromotive dynamics to model an AVR controller. -- [Power System Stabilizer](@ref PSS): Control dynamics to define an stabilization signal for the AVR. -- [Prime Mover and Turbine Governor](@ref TurbineGov): Thermo-mechanical dynamics and associated controllers. - -```@raw html - -``` - -Each inverter is a data structure that is defined by the following components: - -- [DC Source](@ref DCSource): Defines the dynamics of the DC side of the converter. -- [Frequency Estimator](@ref FrequencyEstimator): That describes how the frequency of the grid - can be estimated using the grid voltages. Typically a phase-locked loop (PLL). -- [Outer Loop Control](@ref OuterControl): That describes the active and reactive power - control dynamics. -- [Inner Loop Control](@ref InnerControl): That can describe virtual impedance, - voltage control and current control dynamics. -- [Converter](@ref Converter): That describes the dynamics of the pulse width modulation (PWM) - or space vector modulation (SVM). -- [Filter](@ref Filter): Used to connect the converter output to the grid. - -```@raw html - -``` ⠀ diff --git a/docs/src/index.md b/docs/src/index.md index 1d3f6cd192..999b1632e5 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -77,8 +77,7 @@ If you are new to `PowerSystems.jl`, here's how we suggest getting started: 3. Work through the other basic tutorials based on your interests - See [Working with Time Series Data](@ref tutorial_time_series) if you will be doing production cost modeling or working with time series - - See [Creating a System with Dynamic devices](@ref) and the - [tutorial in PowerSimulationsDynamics](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/tutorials/tutorial_dynamic_data/) + - See [Adding Data for Dynamic Simulations](@ref) if you are interested in [dynamic](@ref D) simulations 4. Then, see the how-to's on parsing [Matpower](@ref pm_data) or [PSS/e files](@ref dyr_data) or [CSV files](@ref table_data) to begin loading your own data into `PowerSystems.jl` diff --git a/docs/src/tutorials/add_dynamic_data.md b/docs/src/tutorials/add_dynamic_data.md new file mode 100644 index 0000000000..624a59cb30 --- /dev/null +++ b/docs/src/tutorials/add_dynamic_data.md @@ -0,0 +1,391 @@ +# Adding Data for Dynamic Simulations + +In this tutorial, we are going to add dynamic data to a power [`System`](@ref), including +a dynamic generator suitable for phasor-type simulations, as well as a dynamic inverter +and dynamic lines necessary for more complex EMT (electro-magnetic transient) +simulations. + +To run a dynamic simulation in Sienna\Dyn using +[`PowerSimulationsDynamics.jl`](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/), +two data layers are required: +1. A base layer of [static](@ref S) components, which includes the data needed to run a + power flow problem +2. An additional layer of [dynamic](@ref D) components, which define differential equations + to run a transient simulation + +We'll define these two layers sequentially. + +## Defining the Static Data Layer + +Instead of defining the static data in the `System` manually, we will load an existing three-bus system using +[`PowerSystemCaseBuilder.jl`](https://github.com/NREL-Sienna/PowerSystemCaseBuilder.jl) +to use as a starting point. + +Start by importing these packages: + +```@repl dyn_data +using PowerSystems +using PowerSystemCaseBuilder +const PSY = PowerSystems; +``` + +To create the system, load pre-existing data for a 3-bus system using +`PowerSystemCaseBuilder.jl`: +```@repl dyn_data +threebus_sys = build_system(PSIDSystems, "3 Bus Inverter Base") +``` +See that there is a table of "Static Components", but no "Dynamic" data yet. + +Let's view the generators in the system with [`show_components`](@ref), +including which bus they are connected at: +```@repl dyn_data +show_components(ThermalStandard, threebus_sys, [:bus]) +``` +Notice that there are generators connected at Buses 2 and 3, but not Bus 1. + +Now, we are going to add the data needed to run an EMT simulation. +We will add an infinite voltage source to Bus 1, which is the last component we +need to complete the static data layer. Then, we will a dynamic +generator or inverter model to the two generators, as well as adding dynamic lines. + +## Add an Infinite Voltage Source + +Add a infinite voltage source with small impedance to Bus 1 (the reference bus). +First, retrieve the reference bus using [`get_components`](@ref): +```@repl dyn_data +slack_bus = first(get_components(x -> get_bustype(x) == ACBusTypes.REF, Bus, threebus_sys)) +``` +Notice we filtered by the [bus type](@ref acbustypes_list) to get the bus(es) we wanted. + +Next, manually define a [`Source`](@ref): +```@repl dyn_data +inf_source = Source( + name = "InfBus", #name + available = true, #availability + active_power = 0.0, + reactive_power = 0.0, + bus = slack_bus, #bus + R_th = 0.0, #Rth + X_th = 5e-6, #Xth +); +``` + +And add it to the system: +```@repl dyn_data +add_component!(threebus_sys, inf_source) +``` + +This completes the first layer of [static](@ref S) data, using components similar to those +we added manually in the [Create and Explore a Power `System`](@ref) tutorial. + +## Adding a Dynamic Generator + +Now, we will connect a classic machine model to the generator at bus 102. +Dynamic generator devices +are composed by 5 components: a [Machine](@ref Machine), +[Shaft](@ref Shaft), [Automatic Voltage Regulator](@ref AVR) (AVR), +[Power System Stabilizer](@ref PSS) (PSS), and +[Prime Mover and Turbine Governor](@ref TurbineGov). +For each of those 5 components, we will select a specific model that defines the data and +differential equations for that component, +and then use those 5 components to define the complete dynamic generator. + +```@raw html + +``` + +!!! note + When defining dynamic data, by convention `PowerSystems.jl` assumes that all data is + in [`DEVICE_BASE`](@ref per_unit). + +First, define a [Machine](@ref Machine) that describes the the stator electro-magnetic dynamics: +```@repl dyn_data +# Create the machine +machine_oneDoneQ = OneDOneQMachine( + R = 0.0, + Xd = 1.3125, + Xq = 1.2578, + Xd_p = 0.1813, + Xq_p = 0.25, + Td0_p = 5.89, + Tq0_p = 0.6, +) +``` +Notice that we selected a specific model, [`OneDOneQMachine`](@ref), with the parameters +tailored to a One-d-one-q dynamic machine model. + +Next, define a specific [Shaft](@ref Shaft) model, [`SingleMass`](@ref) that describes the +rotor electro-mechanical dynamics: +```@repl dyn_data +# Shaft +shaft_no_damping = SingleMass( + H = 3.01, #(M = 6.02 -> H = M/2) + D = 0.0, +) +``` + +Represent the electromotive dynamics of the AVR controller using a specific +[Automatic Voltage Regulator](@ref AVR) model, [`AVRTypeI`](@ref): +```@repl dyn_data +# AVR: Type I: Resembles a DC1 AVR +avr_type1 = AVRTypeI( + Ka = 20.0, + Ke = 0.01, + Kf = 0.063, + Ta = 0.2, + Te = 0.314, + Tf = 0.35, + Tr = 0.001, + Va_lim = (min = -5.0, max = 5.0), + Ae = 0.0039, #1st ceiling coefficient + Be = 1.555, #2nd ceiling coefficient +) +``` + +Define a fixed efficiency [Prime Mover and Turbine Governor](@ref TurbineGov) with +[`TGFixed`](@ref): +```@repl dyn_data +#No TG +tg_none = TGFixed(efficiency = 1.0) #efficiency +``` +See that we are modeling a machine that does not include a Turbine Governor +(or PSS below), but you must define components for them to build a +complete machine model. + +Similarly, define a PSS using [`PSSFixed`](@ref), which is used to describe the stabilization +signal for the AVR: +```@repl dyn_data +#No PSS +pss_none = PSSFixed(V_pss = 0.0) +``` + +Now, we are ready to add a dynamic generator to the static +generator at bus 102. First, let's get that static generator: +```@repl dyn_data +static_gen = get_component(Generator, threebus_sys, "generator-102-1") +``` +Notice that its `dynamic_injector` field is currently `nothing`. + +Use its name and the 5 components above to define its [`DynamicGenerator`](@ref) model: +```@repl dyn_data +dynamic_gen = DynamicGenerator( + name = get_name(static_gen), + ω_ref = 1.0, # frequency reference set-point + machine = machine_oneDoneQ, + shaft = shaft_no_damping, + avr = avr_type1, + prime_mover = tg_none, + pss = pss_none, +) +``` +See that the specific component models that we selected and defined above were used to +specify the states needed to model this generator in a dynamic simulation. + +Finally, use the dynamic version of [`add_component!`](@ref add_component!( + sys::System, + dyn_injector::DynamicInjection, + static_injector::StaticInjection; + kwargs..., +)) to add this data to the `System`: +```@repl dyn_data +add_component!(threebus_sys, dynamic_gen, static_gen) +``` +Notice that unlike static components, which are just added to the `System`, +this dynamic component is added to a specific static component within the `System`. + +!!! tip + To define identical dynamic devices for multiple generators at once, define the pieces of the + generator model as *functions*, such as: + ``` + avr_type1() = AVRTypeI(... + ``` + When called in the `DynamicGenerator` constructor, this will create a new AVR for each generator, so + they are different in memory. Later, if you decide to modify the AVR parameters for + a specific generator, it will not modify the AVR in another generator. + +Recall that you can print the system to see a summary of its data: +```@repl dyn_data +threebus_sys +``` +See that a new table has been added: "Dynamic Components." + +Also, print the static generator to double-check the dynamic layer has been added: +```@repl dyn_data +static_gen +``` +Verify that `dynamic_injector` now contains our dynamic generator model. + +Up to this point, you have added the dynamic data necessary to do a phaser-type simulation, +which focuses on machine behavior. Now we will also add dynamic inverters and lines to enable +EMT simulations. + +## Adding a Dynamic Inverter + +Next we will connect a Virtual Synchronous Generator Inverter at bus 103. + +An inverter is composed of [Converter](@ref), [OuterControl](@ref), [InnerControl](@ref), +[DCSource](@ref), [FrequencyEstimator](@ref), and [Filter](@ref) components: +```@raw html + +``` + +As we did for the generator, we will define each of these six components with a specific +model, which defines its differential equations. + +First, define an [`AverageConverter`](@ref) as the specific model for the [Converter](@ref) +component: +```@repl dyn_data +converter_high_power() = AverageConverter( + rated_voltage = 138.0, + rated_current = 100.0 + ) +``` +Recall from the tip above that we can define these components as *functions* instead of +objects for reusability across multiple generators, and notice that that is what we have +done here. + +Define [OuterControl](@ref) using [Virtual Inertia](@ref) for the active power control and +[ReactivePowerDroop](@ref) for the reactive power control: +```@repl dyn_data +outer_control() = OuterControl( + VirtualInertia(Ta = 2.0, kd = 400.0, kω = 20.0), + ReactivePowerDroop(kq = 0.2, ωf = 1000.0), +) +``` + +Define an [InnerControl](@ref) as a Voltage+Current Controller with Virtual Impedance, +using [`VoltageModeControl`](@ref): +```@repl dyn_data +inner_control() = VoltageModeControl( + kpv = 0.59, #Voltage controller proportional gain + kiv = 736.0, #Voltage controller integral gain + kffv = 0.0, #Binary variable enabling voltage feed-forward in current controllers + rv = 0.0, #Virtual resistance in pu + lv = 0.2, #Virtual inductance in pu + kpc = 1.27, #Current controller proportional gain + kic = 14.3, #Current controller integral gain + kffi = 0.0, #Binary variable enabling the current feed-forward in output of current controllers + ωad = 50.0, #Active damping low pass filter cut-off frequency + kad = 0.2, #Active damping gain +) +``` + +Define a [`FixedDCSource`](@ref) for the [DCSource](@ref): +```@repl dyn_data +dc_source_lv() = FixedDCSource(voltage = 600.0) +``` + +Define a [FrequencyEstimator](@ref) as a phase-locked loop (PLL) using [`KauraPLL`](@ref): +```@repl dyn_data +pll() = KauraPLL( + ω_lp = 500.0, #Cut-off frequency for LowPass filter of PLL filter. + kp_pll = 0.084, #PLL proportional gain + ki_pll = 4.69, #PLL integral gain +) +``` + +Finally, define an [`LCLFilter`](@ref) for the [Filter](@ref): +```@repl dyn_data +filt() = LCLFilter( + lf = 0.08, + rf = 0.003, + cf = 0.074, + lg = 0.2, + rg = 0.01, +) +``` + +Now, use those six functions to define a complete dynamic inverter +by getting the static component at bus 103: +```@repl dyn_data +gen_103 = get_component(Generator, threebus_sys, "generator-103-1"); +``` + +using it and our six functions to define a [`DynamicInverter`](@ref): +```@repl dyn_data +dynamic_inv = DynamicInverter( + name = get_name(gen_103), + ω_ref = 1.0, # frequency reference set-point + converter = converter_high_power(), + outer_control = outer_control(), + inner_control = inner_control(), + dc_source = dc_source_lv(), + freq_estimator = pll(), + filter = filt(), +) +``` + +and adding it to the `System`: +```@repl dyn_data +add_component!(threebus_sys, dynamic_inv, gen_103) +``` + +Both generators have now been updated with dynamic data. Let's complete the `System` +updates by adding dynamic lines. + +## Adding Dynamic Lines + +!!! warning + A `System` must have at least two buses and one branch to run a dynamic simulation in + [`PowerSimulationsDynamics.jl`](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/). + +Let's review the AC branches currently in the system: +```@repl dyn_data +get_components(ACBranch, threebus_sys) +``` +Notice that we have three static `Line` components. + +Let's also print the first line to review its format: +```@repl dyn_data +first(get_components(Line, threebus_sys)) +``` +See that these components do not have the fields for dynamic modeling, such as fields for +different [states](@ref S). + +Let's update that by cycling through these lines and using [`DynamicBranch`](@ref) to extend +each static line with the necessary fields: +```@repl dyn_data +for l in get_components(Line, threebus_sys) + # create a dynamic branch + dyn_branch = DynamicBranch(l) + # add dynamic branch to the system, replacing the static branch + add_component!(threebus_sys, dyn_branch) +end +``` + +Take a look at the AC branches in the system again: +```@repl dyn_data +branches = get_components(ACBranch, threebus_sys) +``` +Notice that now there are 3 `DynamicBranch` components instead the `Line` components. + +Let's take a look by printing first one: +```@repl dyn_data +first(branches) +``` +Observe that this is a wrapper around the static data, with the additional states +data for dynamic modeling. + +Finally, let's print the `System` again to summarize our additions: +```@repl dyn_data +threebus_sys +``` +Verify that the additions were successful, with an added voltage `Source`, `DynamicBranch`es +replacing the static `Lines`, and two new dynamic components with the generator and inverter models. + +## Next Steps + +In this tutorial, you have updated a static system with a second dynamic data layer. +The data you added can enable a phasor-based simulation using the dynamic generator, or +a more complex EMT simulation with the additional dynamic inverter and dynamic lines. + +Next, you might like to: +- Read more about the static and dynamic data layers and the dynamic data format in + [Dynamic Devices](@ref). +- Review the specific sub-system models available in `PowerSystems.jl` for [Machine](@ref), + [Shaft](@ref), [AVR](@ref), [PSS](@ref), + [Prime Mover and Turbine Governor](@ref TurbineGov), [Converter](@ref), + [OuterControl](@ref), [InnerControl](@ref), [DCSource](@ref), + [FrequencyEstimator](@ref), and [Filter](@ref) components +- Explore [`PowerSimulationsDynamics.jl`](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/) + for dynamics modeling in Sienna\Dyn \ No newline at end of file diff --git a/docs/src/tutorials/add_dynamic_device.md b/docs/src/tutorials/add_dynamic_device.md deleted file mode 100644 index c246c6b41b..0000000000 --- a/docs/src/tutorials/add_dynamic_device.md +++ /dev/null @@ -1,311 +0,0 @@ -# Creating a System with Dynamic devices - -You can access example data in the [Power Systems Test Data Repository](https://github.com/NREL-Sienna/PowerSystemsTestData). Most of these systems are available to use using [PowerSystemCaseBuilder.jl](@ref psb). - -```@repl dynamic_data -using PowerSystems -const PSY = PowerSystems -file_dir = joinpath(pkgdir(PowerSystems), "docs", "src", "tutorials", "tutorials_data") -``` - -Although `PowerSystems.jl` is not constrained to only PSS/e files, commonly the data available -comes in a pair of files: One for the static data power flow case and a second one with the -dynamic components information. However, `PowerSystems.jl` is able to take any power flow case -and specify dynamic components to it. - -The following describes the system creation for the one machine infinite bus case using custom -component specifications. - -## One Machine Infinite Bus Example - -First load data from any format (see [Constructing a System from RAW data](@ref parsing) for -details. In this example we will load a [PTI power flow data format](https://labs.ece.uw.edu/pstca/formats/pti.txt) -(`.raw` file) as follows: - -```raw -0, 100, 33, 0, 0, 60 / 24-Apr-2020 17:05:49 - MATPOWER 7.0.1-dev - - - 101, 'BUS 1 ', 230, 3, 1, 1, 1, 1.05, 0, 1.06, 0.94, 1.06, 0.94 - 102, 'BUS 2 ', 230, 2, 1, 1, 1, 1.04, 0, 1.06, 0.94, 1.06, 0.94 -0 / END OF BUS DATA, BEGIN LOAD DATA -0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA -0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA - 102, 1, 50, 0, 100, -100, 1.00, 0, 100, 0, 1, 0, 0, 1, 1, 100, 100, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1 -0 / END OF GENERATOR DATA, BEGIN BRANCH DATA - 101, 102, 1, 0.00, 0.05, 0.000, 100, 100, 100, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 -0 / END OF BRANCH DATA, BEGIN TRANSFORMER DATA -0 / END OF TRANSFORMER DATA, BEGIN AREA DATA -0 / END OF AREA DATA, BEGIN TWO-TERMINAL DC DATA -0 / END OF TWO-TERMINAL DC DATA, BEGIN VOLTAGE SOURCE CONVERTER DATA -0 / END OF VOLTAGE SOURCE CONVERTER DATA, BEGIN IMPEDANCE CORRECTION DATA -0 / END OF IMPEDANCE CORRECTION DATA, BEGIN MULTI-TERMINAL DC DATA -0 / END OF MULTI-TERMINAL DC DATA, BEGIN MULTI-SECTION LINE DATA -0 / END OF MULTI-SECTION LINE DATA, BEGIN ZONE DATA -0 / END OF ZONE DATA, BEGIN INTER-AREA TRANSFER DATA -0 / END OF INTER-AREA TRANSFER DATA, BEGIN OWNER DATA -0 / END OF OWNER DATA, BEGIN FACTS CONTROL DEVICE DATA -0 / END OF FACTS CONTROL DEVICE DATA, BEGIN SWITCHED SHUNT DATA -0 / END OF SWITCHED SHUNT DATA, BEGIN GNE DEVICE DATA -0 / END OF GNE DEVICE DATA, BEGIN INDUCTION MACHINE DATA -0 / END OF INDUCTION MACHINE DATA -Q -``` - -Based on the description provided in PTI files, this is a two-bus system, on which the bus -101 (bus 1) is the reference bus at 1.05 pu, and bus 102 (bus 2) is PV bus, to be set at -1.04 pu. There is one 100 MVA generator connected at bus 2, producing 50 MW. There is an -equivalent line connecting buses 1 and 2 with a reactance of ``0.05`` pu. - -We can load this data file first - -```@repl dynamic_data -omib_sys = System(joinpath(file_dir, "OMIB.raw"), runchecks = false) -``` - -### Dynamic Generator - -We are now interested in attaching to the system the dynamic component that will be modeling -our dynamic generator. The data can be added by directly passing a `.dyr` file, but in this -example we want to add custom dynamic data. - -Dynamic generator devices are composed by 5 components, namely, `machine`, `shaft`, `avr`, -`tg` and `pss` (see [`DynamicGenerator`](@ref)). So we will be adding functions to create all -of its components and the generator itself. The example code creates all the components -for a [`DynamicGenerator`](@ref) based on specific models for its components. This result -will be a classic machine model without AVR, Turbine Governor and PSS. - -```@repl dynamic_data -#Machine -machine_classic = BaseMachine( - R = 0.0, - Xd_p = 0.2995, - eq_p = 0.7087, -) - -#Shaft -shaft_damping = SingleMass( - H = 3.148, - D = 2.0, -) - -#AVR -avr_none = AVRFixed(Vf = 0.0) - -#TurbineGovernor -tg_none = TGFixed(efficiency = 1.0) - -#PSS -pss_none = PSSFixed(V_pss = 0.0); -``` - -Then we can collect all the dynamic components and create the dynamic generator and assign it -to a static generator of choice. In this example we will add it to the generator "generator-102-1" -as follows: - -```@repl dynamic_data -#Collect the static gen in the system -static_gen = get_component(Generator, omib_sys, "generator-102-1") -#Creates the dynamic generator -dyn_gen = DynamicGenerator( - name = get_name(static_gen), - ω_ref = 1.0, - machine = machine_classic, - shaft = shaft_damping, - avr = avr_none, - prime_mover = tg_none, - pss = pss_none, - ) -#Add the dynamic generator the system -add_component!(omib_sys, dyn_gen, static_gen) -``` - -Once the data is created, we can export our system data such that it can be reloaded later: - -```julia -to_json(omib_sys, "YOUR_DIR/omib_sys.json") -``` - -## Example with Dynamic Inverter - -We will now create a three bus system with one inverter and one generator. In order to do so, -we will parse the following file `ThreebusInverter.raw`: - -```raw -0, 100, 33, 0, 0, 60 / 24-Apr-2020 19:28:39 - MATPOWER 7.0.1-dev - - - 101, 'BUS 1 ', 138, 3, 1, 1, 1, 1.02, 0, 1.1, 0.9, 1.1, 0.9 - 102, 'BUS 2 ', 138, 2, 1, 1, 1, 1.0142, 0, 1.1, 0.9, 1.1, 0.9 - 103, 'BUS 3 ', 138, 2, 1, 1, 1, 1.0059, 0, 1.1, 0.9, 1.1, 0.9 -0 / END OF BUS DATA, BEGIN LOAD DATA - 101, 1, 1, 1, 1, 50, 10, 0, 0, 0, 0, 1, 1, 0 - 102, 1, 1, 1, 1, 100, 30, 0, 0, 0, 0, 1, 1, 0 - 103, 1, 1, 1, 1, 30, 10, 0, 0, 0, 0, 1, 1, 0 -0 / END OF LOAD DATA, BEGIN FIXED SHUNT DATA -0 / END OF FIXED SHUNT DATA, BEGIN GENERATOR DATA - 102, 1, 70, 0, 100, -100, 1.0142, 0, 100, 0, 1, 0, 0, 1, 1, 100, 318, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1 - 103, 1, 80, 0, 100, -100, 1.0059, 0, 100, 0, 1, 0, 0, 1, 1, 100, 318, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1 -0 / END OF GENERATOR DATA, BEGIN BRANCH DATA - 101, 103, 1, 0.01000, 0.12, 0.2, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 - 101, 102, 1, 0.01000, 0.12, 0.2, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 - 102, 103, 1, 0.02000, 0.9, 1.0, 250, 250, 250, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1 -0 / END OF BRANCH DATA, BEGIN TRANSFORMER DATA -0 / END OF TRANSFORMER DATA, BEGIN AREA DATA -0 / END OF AREA DATA, BEGIN TWO-TERMINAL DC DATA -0 / END OF TWO-TERMINAL DC DATA, BEGIN VOLTAGE SOURCE CONVERTER DATA -0 / END OF VOLTAGE SOURCE CONVERTER DATA, BEGIN IMPEDANCE CORRECTION DATA -0 / END OF IMPEDANCE CORRECTION DATA, BEGIN MULTI-TERMINAL DC DATA -0 / END OF MULTI-TERMINAL DC DATA, BEGIN MULTI-SECTION LINE DATA -0 / END OF MULTI-SECTION LINE DATA, BEGIN ZONE DATA -0 / END OF ZONE DATA, BEGIN INTER-AREA TRANSFER DATA -0 / END OF INTER-AREA TRANSFER DATA, BEGIN OWNER DATA -0 / END OF OWNER DATA, BEGIN FACTS CONTROL DEVICE DATA -0 / END OF FACTS CONTROL DEVICE DATA, BEGIN SWITCHED SHUNT DATA -0 / END OF SWITCHED SHUNT DATA, BEGIN GNE DEVICE DATA -0 / END OF GNE DEVICE DATA, BEGIN INDUCTION MACHINE DATA -0 / END OF INDUCTION MACHINE DATA -Q -``` - -That describes a three bus connected system, with generators connected at bus 2 and 3, and -loads in three buses. We can load the system and attach an infinite source on the reference bus: - -```@repl dynamic_data -threebus_sys = System(joinpath(file_dir, "ThreeBusInverter.raw"), runchecks = false) -``` - -We will connect a [`OneDOneQMachine`](@ref) machine at bus 102, and a Virtual Synchronous Generator Inverter -at bus 103. An inverter is composed by a `converter`, `outer control`, `inner control`, -`dc source`, `frequency estimator` and a `filter` (see [`DynamicInverter`](@ref)). - -### Dynamic Inverter definition - -We will create specific components of the inverter as follows: - -```@repl dynamic_data -#Define converter as an AverageConverter -converter_high_power = AverageConverter(rated_voltage = 138.0, rated_current = 100.0) - -#Define Outer Control as a composition of Virtual Inertia + Reactive Power Droop -outer_cont = OuterControl( - active_power_control = VirtualInertia(Ta = 2.0, kd = 400.0, kω = 20.0), - reactive_power_control = ReactivePowerDroop(kq = 0.2, ωf = 1000.0), -) - -#Define an Inner Control as a Voltage+Current Controler with Virtual Impedance: -inner_cont = VoltageModeControl( - kpv = 0.59, #Voltage controller proportional gain - kiv = 736.0, #Voltage controller integral gain - kffv = 0.0, #Binary variable enabling the voltage feed-forward in output of current controllers - rv = 0.0, #Virtual resistance in pu - lv = 0.2, #Virtual inductance in pu - kpc = 1.27, #Current controller proportional gain - kic = 14.3, #Current controller integral gain - kffi = 0.0, #Binary variable enabling the current feed-forward in output of current controllers - ωad = 50.0, #Active damping low pass filter cut-off frequency - kad = 0.2, #Active damping gain -) - -#Define DC Source as a FixedSource: -dc_source_lv = FixedDCSource(voltage = 600.0) - -#Define a Frequency Estimator as a PLL based on Vikram Kaura and Vladimir Blaskoc 1997 paper: -pll = KauraPLL( - ω_lp = 500.0, #Cut-off frequency for LowPass filter of PLL filter. - kp_pll = 0.084, #PLL proportional gain - ki_pll = 4.69, #PLL integral gain -) - -#Define an LCL filter: -filt = LCLFilter(lf = 0.08, rf = 0.003, cf = 0.074, lg = 0.2, rg = 0.01) -``` - -Similarly we will construct a dynamic generator as follows: - -```@repl dynamic_data -#Create the machine -machine_oneDoneQ = OneDOneQMachine( - R = 0.0, - Xd = 1.3125, - Xq = 1.2578, - Xd_p = 0.1813, - Xq_p = 0.25, - Td0_p = 5.89, - Tq0_p = 0.6, -) - -#Shaft -shaft_no_damping = SingleMass( - H = 3.01, - D = 0.0, -) - -#AVR: Type I: Resembles a DC1 AVR -avr_type1 = AVRTypeI( - Ka = 20.0, - Ke = 0.01, - Kf = 0.063, - Ta = 0.2, - Te = 0.314, - Tf = 0.35, - Tr = 0.001, - Va_lim = (min = -5.0, max = 5.0), - Ae = 0.0039, #1st ceiling coefficient - Be = 1.555, #2nd ceiling coefficient -) - -#No TG -tg_none = TGFixed(efficiency = 1.0) - -#No PSS -pss_none = PSSFixed(V_pss = 0.0); -``` - -### Add the components to the System - -```@repl dynamic_data -for g in get_components(Generator, threebus_sys) - #Find the generator at bus 102 - if get_number(get_bus(g)) == 102 - #Create the dynamic generator - case_gen = DynamicGenerator( - name = get_name(g), - ω_ref = 1.0, - machine = machine_oneDoneQ, - shaft = shaft_no_damping, - avr = avr_type1, - prime_mover = tg_none, - pss = pss_none, - ) - #Attach the dynamic generator to the system - add_component!(threebus_sys, case_gen, g) - #Find the generator at bus 103 - elseif get_number(get_bus(g)) == 103 - #Create the dynamic inverter - case_inv = DynamicInverter( - name = get_name(g), - ω_ref = 1.0, - converter = converter_high_power, - outer_control = outer_cont, - inner_control = inner_cont, - dc_source = dc_source_lv, - freq_estimator = pll, - filter = filt, - ) - #Attach the dynamic inverter to the system - add_component!(threebus_sys, case_inv, g) - end -end - -# We can check that the system has the Dynamic Inverter and Generator -threebus_sys -``` - -Finally we can seraliaze the system data for later reloading - -```julia -to_json(threebus_sys, "YOUR_DIR/threebus_sys.json") -``` - -For more details to handle dynamic data, [check the tutorial in PowerSimulationsDynamics](https://nrel-sienna.github.io/PowerSimulationsDynamics.jl/stable/tutorials/tutorial_dynamic_data/). diff --git a/docs/src/tutorials/creating_system.md b/docs/src/tutorials/creating_system.md index cb7c056020..b19a85a18f 100644 --- a/docs/src/tutorials/creating_system.md +++ b/docs/src/tutorials/creating_system.md @@ -328,6 +328,7 @@ and modified the `System` per-unit settings. Next, you might want to: - [Add time series data to components in the `System`](@ref tutorial_time_series) +- [Add necessary data for dynamic simulations](@ref "Adding Data for Dynamic Simulations") - [Import a `System` from an existing Matpower or PSSE file instead of creating it manually](@ref parsing) - [Create your own `System` from .csv files instead of creating it manually](@ref table_data) - [Read more to understand per-unitization in PowerSystems.jl](@ref per_unit)