OpenDSS Generator User DLL
OpenDSS Generator User DLL
Sept, 5, 2012
The OpenDSS Generator element model supports user-written DLLS for both power flow
and dynamics applications.
An example of where this model is useful is the IndMach012 model supplied with
OpenDSS. The model implements a simple symmetrical component model of an
induction machine.
The Pascal declaration of the public data structure for the Storage element is:
{Struct to pass basic data to user-written DLLs}
TGeneratorVars = packed Record
{32-bit integers}
NumPhases, {Number of phases}
NumConductors, {Total Number of conductors (wye-connected will have 4)}
Conn :Integer; // 0 = wye; 1 = Delta
1
}
Pshart :Double;
Shaft power, W;
Speed :Double;
w0 :Double;
Hmass :Double;
Mmass :Double;
D, Dpu :Double;
Damping factor in actual units and in per unit. D := Dpu * kVArating *1000.0/(w0);
kVArating :Double;
kVGeneratorBase:Double;
Machine Xd, Xd’, Xd” in per unit as defined by the user using the Generator
object properties.
dTheta :Double;
Derivative of Theta (usually the same as Speed) at the current time step.
2
dSpeed :Double;
ThetaHistory :Double;
SpeedHistory :Double;
PnominalPerPhase :Double;
QnominalPerPhase :Double;
NumPhases,
NumConductors,
Conn :Integer
VthevMag :Double;
Thevenin voltage magnitude, volts, used in Dynamics model for the direct axis
voltage. Along with Theta, this value is initialized so that the power produced by
the Generator object is approximately the same as the most recent power flow
solution prior to entering Dynamics mode.
VThevHarm:Double;
ThetaHarm:Double;
VTarget :Double;
Zthev :Complex;
3
Generator User DLL Function Interface
The declaration of the functions and procedures in the DLL interface for a user-written
DLL is for dynamics simulation only. The name of the DLL is specified by the
UserModel=MyUserWrittenDLL statement in the description of the Generator element.
The OpenDSS will then load the DLL and attempt to use it. All the functions described
here will have to be found before the OpenDSS will continue.
User-written DLLs should be capable of supporting more than one instance of a model.
Each of several Storage elements in the OpenDSS circuit model could invoke the same
DLL. The DLL is only loaded one time, but could be called by more than one Storage
element. Therefore, the DLL must be able to manage multiple instances. An integer
handle is assigned to each instance by the DLL (see below).
All function calls use the Stdcall calling convention. This is also the convention used in
the Windows API.
If you would like to study the DLL interface in OpenDSS, please see the
StoreUserModel.Pas file in the ..\Source\PCelement folder on the source code sharing
site.
Function New
(Var GenVars : TGeneratorVars;
Var DynaData : TDynamicsRec;
Var CallBacks : TDSSCallBacks) : Integer; Stdcall;// Make a new instance
This function creates a new instance of the model defined by the DLL. It returns
an integer handle to the instance that may be used to specifically select this
instance at a later time.
Note that for some OpenDSS objects, the New function may take a different
number of parameters. It depends on when the model was written. Both the
TGeneratorVars and TDynamicsRec structures can also be obtained now from
the callback function.
User-written DLLs should have some mechanism for keeping track of instances
of the class represented by the DLL. This could be a simple array of pointers or a
linked list or some other mechanism of the programmer’s choosing. There is no
internal OpenDSS mechanism to support this. Each Generator object that
creates a Usermodel object will keep track of only the one that belongs to it and
use the Select function to instruct the DLL with instance to make active.
Arguments:
4
tstart,
tstop:Double;
IterationFlag:Integer;
{0=New Time Step; 1= Same Time Step as last iteration}
SolutionMode :Integer;
intHour :Integer; // time, in hours as an integer
dblHour :Double; // time, in hours as a floating point
number including fractional part
End;
Procedure Delete
(var ID:Integer); Stdcall; // deletes specified instance
This procedure deletes a specific instance referenced by the ID. This is the value
returned by the New function when the instance was created. Note it is passed
by reference.
Function Select
(var ID:Integer):Integer; Stdcall; // Select active instance
This function selects an instance of the objects instantiated by the DLL. The ID is
the value returned by the New function. ID is passed by reference (i.e., expect a
pointer to an integer).
Procedure Init
(V, I:pComplexArray);Stdcall;
This procedure is called when the OpenDSS is entering Dynamics mode from
one of the power flow modes. Two pointers to complex number arrays are
passed representing the present voltage, V, and current, I, at the Storage
element terminals. The user-written DLL uses these values to perform whatever
calculations are required to initialize the active model.
Procedure Calc
(V, I:pComplexArray); stdcall;
This procedure invokes the main electrical calculation algorithm of the model.
This will usually be to compute the terminal currents, I, given the present
estimate of the voltages, V, and internal state variables. For "usermodel", this
function basically computes I given V. For "shaftmodel", uses V and I to
calculate Pshaft, speed, etc. in the GeneratorVars data structures
V and I are pointers to complex number arrays. There will be one complex value
for each conductor of the Storage element terminal. If there is any question how
many conductors are present, the GetActiveElementTerminalInfo call back
function may be called or, for the Generator element, the values are available on
the public data structure (GeneratorVars).
This calc procedure should work for the various solution modes that the model
will be used for. The SolutionMode field of the DynaData structure can be
5
checked for the present solution mode and allow appropriate action. For
example, from the IndMach012 code:
With ActiveModel Do
Begin
Case DynaData^.SolutionMode of
DYNAMICMODE: Begin
CalcDynamic(V012, I012);
End;
Else {All other modes are power flow modes}
Begin
CalcPflow(V012, I012);
End;
End;
End;
This model has separate algorithms for power flow modes and Dynamic mode.
Procedure Integrate;
stdcall; // Integrates any state vars
Most other models in the OpenDSS use a forward Euler for the predictor step
and trapezoidal for the corrector step. The derivatives from the previous time
step – necessary for the trapezoidal integration step – are captured during the
predictor step.
Note that the Integrate function is called prior to the Calc function.
Procedure Edit
(EditStr:pAnsichar; Maxlen:Cardinal); Stdcall;
The length of the string is passed in the Maxlen argument, which is pushed onto
the calling stack in case it is expected by the language in which the DLL is
implemented (some languages expect this argument).
Note that it is not necessary to support OpenDSS syntax. Any format may be
used for the data required to define the model. If the model requires an extensive
amount of data, one approach is to pass a file name in MyString and have the
DLL’s Edit procedure read the data from the file.
Procedure UpdateModel;
StdCall;
6
models. Many models will not need this, but it is provided. It is typically called
after calling the Edit procedure.
Procedure Save;
StdCall;
This procedure is called by the OpenDSS to allow a user model to save its state
variables to a file somewhere for a quick restart. The Restore procedure retrieves
the values.
Procedure Restore;
StdCall;
This procedure is called by the OpenDSS to allow a user model to recover data
written to a file by the Save procedure.
Note that as of this writing (2012) the Save .. Restore functionality is not used in the
Generator model. However, the function interfaces must exist in the DLL so that the DLL
will load without error.
The values returned by these functions are automatically captured by Monitor elements
assigned to Power Conversion (PC) elements and defined with Mode=3. The variables
exposed by the programmer are appended to the default list of variables in the parent PC
element (i.e., a Storage element). A Monitor will put the names of the variables in the
header record and then capture the numeric values for each sample.
The user may return a number of double-precision floating point values for monitoring.
These are frequently values of the state variables, but can be any number the programmer
desires.
Function NumVars:
Integer;Stdcall; // Number of variables that can be returned for monitoring
Procedure GetAllVars
(Vars:pDoubleArray);StdCall;
Function GetVariable
(var i:Integer):double;StdCall; // returns a i-th variable value only
This function returns the value of the i-th variable. Note that i is passed by
reference, That is, the user-written program should expect to receive a pointer to
this index.
7
Procedure SetVariable
(var i:Integer;var value:Double); StdCall;
This procedure is provided to allow the user to set the value of a variable internal
to the model. Both arguments are passed by reference. That is, the user-written
program should expect to receive pointers to the values of these arguments.
The DLL is not obligated to set the internal variable to the value and should not
permit it if it will break the model.
Procedure GetVarName
(var VarNum:Integer; VarName:pAnsiChar; maxlen:Cardinal); StdCall;
VarNum is the index of the variable name requested and will be passed by
reference (i.e., expect a pointer to an integer).
The OpenDSS will allocate space for VarName, a null-terminated Ansi character
string, and pass the size of the allocation in the maxlen argument, which is an
unsigned integer passed by value. The DLL implementation of this procedure will
copy the string name of the requested variable into the buffer up to the limit given
by maxlen.
8
Example
The entire source code for the IndMach012 DLL is supplied on line at the OpenDSS
source sharing site.