One of the core strengths of ElecNetKit lies in data manipulation and transformation. To that effect, the generation of sensitivity data has been found to be incredibly helpful for the purposes of exploring network P-Q-V relationships and planning for the installation of distributed generation, storage, and voltage support systems.
ElecNetKit features a module designed for simplifying perturb-and-observe-style experiments, and for generating sensitivity information from these experiments. This module is introduced in this topic.
This topic contains the following sections.
Perturb-and-Observe Experiments are run using the PerturbAndObserveRunner TObserve class.
Setting Up a Perturb-and-Observe Experiment
Specify the NetworkFilename of the network to run the perturb-and-observe experiment on.
Specify selector functions, that take a NetworkModel and return a set of NetworkElements. You should specify a selector function for all elements that are to be perturbed (PerturbElementSelector) and for all elements that are to be observed (ObserveElementSelector). It is common to set the observed elements to the buses in the network, for example:
myPerturbAndObserveRunner.ObserveElementSelector = network => network.Buses.Values;
The choice of PerturbElementSelector is a little more arbitrary due to the way that perturbation commands are issued to the simulator (this will be explained later).
Specify value selector functions PerturbElementValuesSelector and ObserveElementValuesSelector. These take the network elements selected by PerturbElementSelector and ObserveElementSelector, and obtain values that will be observed or used in the perturbation command. For example, if we wish to observe the bus voltages, we can use the statement:
myPerturbAndObserveRunner.ObserveElementValuesSelector = networkElement => ((Bus)networkElement).Voltage.Magnitude;
As an example of pulling data from perturbation elements to be used in the perturbation command, the following two commands specify perturbation on buses, and select some values to populate the perturbation commands:
myPerturbAndObserveRunner.PerturbElementSelector = network => network.Buses.Values; myPerturbAndObserveRunner.PerturbElementValuesSelector = bus => new Object[] {bus.ID};
In the above example, only the bus ID is selected. The data that needs to be selected depends upon the specific use case and perturbation commands.
Specify a set of PerturbCommands. Each command can have optional placeholders that will be filled in with values from the PerturbElementValuesSelector specified earlier. Placeholders are specified as {0}, {1}, {2} etc., where the number between the curly braces is the index in the array of objects returned by the value selector. For example, if the PerturbElementValuesSelector returned {25, "myBus", 11}, the command string
"new Generator.testgenerator-{1} bus1={1} phases=3 model=1 status=fixed kV={2} Vminpu=0.9 Vmaxpu=1.1 kW={0} kvAR=0"
would resolve to
"new Generator.testgenerator-myBus bus1=myBus phases=3 model=1 status=fixed kV=11 Vminpu=0.9 Vmaxpu=1.1 kW=25 kvAR=0"
You can set up this command string using the code:
myPerturbAndObserveRunner.PerturbCommands = new String[] { "new Generator.testgenerator-{1} bus1={1} phases=3 model=1 status=fixed kV={2} Vminpu=0.9 Vmaxpu=1.1 kW={0} kvAR=0"};
Tip You can specify multiple commands to be run in sequence by adding a comma and another command immediately before the closing curly brace:
myPerturbAndObserveRunner.PerturbCommands = new String[] { "command1", "command2"};
Now, call RunPerturbAndObserve to run the perturb-and-observe experiment. The perturbations given by the PerturbCommands will be applied at each element in PerturbElementSelector individually. The observed values before and after perturbation will be stored in BeforeValues and AfterValues. See the documentation for each of those members for a description of the way that observed data is stored.
Once a Perturb-and-Observe experiment has been run, the PerturbAndObserveRunner TObserve can be passed to a SensitivityGenerator T to generate the sensitivities of the observed quantities to the perturbed quantities.
Generating Sensitivity Information from Perturb-and-Observe Results
Instantiate a new SensitivityGenerator T .
Set the ResultSelector to a function that takes the observed results provided by the PerturbAndObserveRunner TObserve and transforms them into some numerical quantity that can be converted to Double. For most cases, one of these lines of code will suffice:
//Use this if you're observing a complex number and the magnitude component is important. mySensitivityGenerator.ResultSelector = complex => complex.Magnitude; //Use this if you're observing a simple number (double, int, etc) mySensitivityGenerator.ResultSelector = x => x;
Set the RecordedPerturbationSelector to obtain a value from the recorded perturbation values. Remember how before we had set of values that we got from PerturbElementValuesSelector? These got passed to the PerturbCommands, and the example we used was {25, "myBus", 11}. We need to extract a numerical value from this array to obtain some kind of quantifiable cause-and-effect relationship. The way to do this is through the RecordedPerturbationSelector, but we've got a couple of options:
Option 1: Limit what gets recorded by the PerturbAndObserveRunner TObserve with the PerturbValuesToRecord property, and then just select that:
//Take {25, "myBus", 11} and only save 25 myPerturbAndObserveRunner.PerturbValuesToRecord = array => array[0]; //do the rest of the setup and call myPerturbAndObserveRunner.RunPerturbAndObserve(); //Just pull in that 25 mySensitivityGenerator.RecordedPerturbationSelector = x => x;
Option 2: Record everything from the perturb-and-observe experiment and then just select the relevant data with RecordedPerturbationSelector:
Option 2 is especially useful for situations in which you would use the same perturb-and-observe results for multiple purposes, including a sensitivity calculation, because no loss of data occurs.
Note The output of RecordedPerturbationSelector needs to be convertible to Double, and thus needs to be a simple number. Call GenerateSensitivities, passing the PerturbAndObserveRunner TObserve as a parameter: