PGM Example - PGM Class to assist with solving sensitive PID control loops
Jump to navigation
Jump to search
Navigation: PGMs ➔ Example PGM Files ➔ PGM Example - PGM Class to assist with solving sensitive PID control loops
Related Links: Defining a Class
This PGM class is useful for PID loops with a fast response where oscillations can occur between consecutive iterations for high gain values. Where the response is more slow, i.e. where the control point and measured point in the model are separated by a number of units, this class may not work well.
;This class is used to optimise the value of the gain for a PID controller
DropList Options{"Maximum Gain", "Minimum Gain", "Geometric Mean"}
Class Class_OptimiseGain
ClassGridColumnWidth 20 ;if you want multiple optimisers displayed as a grid, set this value so that the column displays are wide enough, search for ClassGrid for more details
TextLabel ," ======== Optimise PID Gain ========"
Integer ClassAsArray
String UnitNameTag@{Tag}
Integer PID_Number*<<1>>
String PID_Name@{Tag} ;full name of the PID controller
String PID_Description@ ;description given to the controller by the user
Memo PID_Description2@
CheckBox Optimiser_On*<<1>>
CheckBox SetOutput_MinMax*<<0>>
Textbreak
Options InitGain*<<0>>{Comment("Initial Gain (if RelError > 0.1%)")}
Real MaxGain*<<0.05>><1e-12,> ;the maximum gain that will be used
Real MinGain*<<0.0001>><1e-12,> ;the minimum gain that will be used (also used as the initial value)
Real CurGain@ ;current gain
Real MinPB@@{Comment("1/MaxGain")}, MaxPB@@{Comment("1/MinGain")}, CurPB@@{Comment("1/CurGain")}
Integer ItersBetweenGainDecrease*<<5>> ; iterations between gain decrease
Integer ItersBetweenGainIncrease*<<100>> ; iterations between gain increase
Real AdjustmentFactor*<<2>><1.1,10> ; adjustment factor for division or multiplication
Textbreak
Real OutputMin**, OutputMax**<<10>>
String GainTag@@{Tag}, SPTag@@{Tag}, MeasTag@@{Tag}, RelErrorTag@@{Tag}, OutMinTag@@{Tag}, OutMaxTag@@{Tag}
Real OldDiff ;holds the previous error
Real Diff ;holds the current error
Integer classtag_length, ItersSinceLastDecrease, ItersSinceLastIncrease
Bit IsFirstIteration, SetOutputState
Sub Initialise()
;Check if the Class is defined as an array, if so, need to remove [index] from the ClassTag()
ClassAsArray = StrFind(ClassTag(), "[" )
if ClassAsArray == -1
UnitNameTag = ClassTag()
Else
classtag_length = StrLen(ClassTag())
UnitNameTag = Left(ClassTag(), ClassAsArray)
Endif
;calculate and store the PID tags
PID_Name = Concatenate(UnitNameTag,".Cfg.[", InttoStr(PID_Number),"]")
GainTag = Concatenate(PID_Name,".Gain")
SPTag = Concatenate(PID_Name,".SptUsed")
MeasTag = Concatenate(PID_Name,".Meas")
RelErrorTag = Concatenate(PID_Name,".RelError (%)")
OutMinTag = Concatenate(PID_Name,".OutMin")
OutMaxTag = Concatenate(PID_Name,".OutMax")
;initialise key values
ItersSinceLastDecrease = 0
ItersSinceLastIncrease = 0
SetConcealedState(OutputMin, (SetOutput_MinMax==False))
SetConcealedState(OutputMax, (SetOutput_MinMax==False))
SetOutputstate = SetOutput_MinMax
IsFirstIteration = True
PID_Description = [Concatenate(UnitNameTag,".Cfg.[",InttoStr(PID_Number),"].Name")]
PID_Description2 = [Concatenate(UnitNameTag,".Cfg.[",InttoStr(PID_Number),"].Description")]
EndSub
Sub Optimise()
If (Optimiser_On)
If (IsFirstIteration)
If (Abs([RelErrorTag]) > 0.1) ;if not currently converged
If InitGain == 0 ;start at max gain
[GainTag] = MaxGain
ElseIf InitGain == 1 ;start at min gain
[GainTag] = MinGain
ElseIf InitGain == 2 ;start at geometric mean
[GainTag] = Sqrt(MinGain * MaxGain)
EndIf
EndIf
CurGain = [GainTag]
OldDiff = [RelErrorTag]
IsFirstIteration = False ;reset flag
EndIf
;grab current error
Diff = [RelErrorTag]
If (Diff * OldDiff < 0) ;error has switched sign (oscillating around SP) - decrease gain
If (ItersSinceLastDecrease > ItersBetweenGainDecrease)
CurGain = Max(CurGain/AdjustmentFactor, MinGain)
[GainTag] = CurGain
ItersSinceLastDecrease = 0
EndIf
Else ;error has the same sign (approaching SP) - increase gain
If (ItersSinceLastIncrease > ItersBetweenGainIncrease)
CurGain = Min(CurGain*AdjustmentFactor, MaxGain)
[GainTag] = CurGain
ItersSinceLastIncrease = 0
EndIf
EndIf
;update counter and previous error
ItersSinceLastDecrease = ItersSinceLastDecrease + 1
ItersSinceLastIncrease = ItersSinceLastIncrease + 1
OldDiff = Diff
EndIf
;update concealed state of output min/max if changed
If SetOutput_MinMax <> SetOutputState
SetConcealedState(OutputMin, (SetOutput_MinMax==False))
SetConcealedState(OutputMax, (SetOutput_MinMax==False))
SetOutputState = SetOutput_MinMax
EndIf
;update PID output min/max
If SetOutput_MinMax
[OutMinTag] = OutputMin
[OutMaxTag] = OutputMax
EndIf
CurPB = 1/CurGain
MaxPB = 1/MinGain
MinPB = 1/MaxGain
EndSub
EndClass
;Please make sure there is no dollar sign or end of file marker here for this to be an include file.
Adding the OptimiseGain class to PGM file.
>>OptimiseGain.pgm
;==================================================================
;Main Program
PageLabel "OptimisePIDs"
Textbreak
;Define the class instances
;For PID Controller with a single control block requiring optimisation, simply define the class instance using the unit tag name.
Class_OptimiseGain Autoclave2_Steam
;For PID Controller with multiple control blocks requiring optimisation, define the class instance using the unit tag name in an array.
Class_OptimiseGain NonOxidising_Leach_Control[2]
;Define class list for use in class macros or class functions
ClassList PIDs{Autoclave2_Steam, NonOxidising_Leach_Control}
;Display results in Grid format
ClassGrid PIDs
;initialise the class tags
Sub PreStart()
ForEachSub(PIDs, Initialise())
EndSub
;execute the optimise sub routine.
ForEachSub(PIDs, Optimise())
$ ; --- end of file ---
Setting up the Access Window: For example, user can add the above PGM class and PGM file to the Nickel Copper Project.
NOTE:
|