Code Snippets and Tutorials¶
The general workflow when approaching simulation of controlled elements within pandapower could be outlined like this:
- Get an overview of your project. Which network elements do you need, what and how should these elements accomplish their task?
- Checkout current implementations. Maybe there is a controller that does something similar, so you can save work and also get a point to start with.
- Implement your own controller/controlling-strategy.
- Setup your simulation and give it a go.
Single Load-Flow with one Controller¶
For introduction purposes an easy example will be described.
The task at hand would be to simulate a Trafo Controller with local continous tap changer voltage control.
First we load a network and define it as
net (if you dont know how, have a look at
Pandapower Pro Networks). Next we need one object: an instance of
ContinuousTapControl, for example StatCurtPv. We want the transformer with ID 114 to be controlled by this controller, hence we pass
Have a look at all transformer IDs by typing
net.trafo.index and chose the ones to be controlled.
import pandapower as pp import control from pandapower.networks import mv_oberrhein # loading the network with the usecase 'generation' net = mv_oberrhein() # initialising controller tol = 1e-6 trafo_controller = control.ContinuousTapControl(net=net, tid=114, u_set=0.98, tol=tol) # running a control-loop control.run_control(net)
We imported pandapower and the control module and created the object of a controller we need. You can look up which parameters are mandatory and which are optional in the constructor of the class you are creating an instance of. In our example we need to pass a reference to the net, the ID of the controlled transformer, the voltage setpoint and a calculation tolerance.
import pandapower as pp which provides me a handy
pp for the whole import-reference. These abbreviations have to
be unique throughout your code.
Now we look at our network that contains our controller.
The output in the console shows, that the controller is active and has the default values for order and level (we’ll look at
these in more detail shortly).
Now we run a loadflow-simulation with our controlling unit using the
Have a look at
net.res_trafo to check the results of the transformers. You can compare them with results of a normal loadflow-simulation
pp.runpp(net) and checking
net.res_trafo again. Check the results at the buses and lines in the network aswell for further informations.
Simulating time-series with Controllers¶
If you want to simulate time-series, you may also do so using the controller framework. First you need
a DataSource for the profiles loads or pv-plants should be using. Most commonly CSV-files are being used
to provide data values over time, but you could also implement a DataSource of your own which e.g.
generates data on-the-fly. In our example we use an instance of CsvData. It expects a column named
time containing consecutive timestamps. You may simply use values from zero counting upwards for each
time step or use UNIX-timestamps if you like. Each column contains a profile with a value
for each time step at the corresponding row. You have to pass a datasource as well as the name of the column
a controller should use as profile as depicted below.
import pandapower as pp import control import timeseries # loading the network with the usecase 'generation' net = pp.networks.mv_oberrhein(scenario='generation') # loading a timeseries ds = timeseries.CsvData("PATH\\FILE.csv", sep=";") # initialising ConstControl to update values at the regenerative generators const = control.ConstControl(net, element='sgen', element_index=net.sgen.index, variable='p_mw', data_source=ds, profile_name='P_PV_1', level=0) # initialising controller tol = 1e-6 trafo_controller = control.ContinuousTapControl(net=net, tid=114, u_set=0.98, tol=tol, level=0) # starting the timeseries simulation for one day -> 96 15 min values. timeseries.run_timeseries(net, time_steps=(0,95))
We created a DataSource and passed it to the
ConstControl, while also providing the name of the
P-profile. For simplification purposes we used one profile for all generators.
We may want to save certain values at each calculated timestep. In order to do that,
we build an OutputWriter.
# initialising the outputwriter to save data ow = timeseries.OutputWriter(net) ow.log_variable('res_sgen', 'p_kw') ow.log_variable('res_bus', 'vm_pu') # starting the timeseries simulation for one day -> 96 15 min values. timeseries.run_timeseries(net, time_steps=(0,95)) # results in ow.output
We created an OutputWriter and added a few functions to store values we are intersted in. Have a
look at the implementation of the OutputWriter to find out more about saving values during time-series
simulation. Note that the invokation of the simulation differs
from above: we use
timeseries.run_timeseries() and pass on the start- and stop step of the simulation. Results of
the simulation are being stored in a pandas dataframe called
output in the