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 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
TextLabel(,"======== Optimise PID Gain ========")
Long ClassAsArray
String UnitNameTag@{Tag}
Integer PID_Number*<<1>>
String PID_Name@{Tag} ;full name of the PID controller
CheckBox Optimiser_On*<<1>>
CheckBox SetOutput_MinMax*<<0>>
TextLabel()
Options InitGain*<<1>>{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*<<5>> ; iterations between gain increase
Real AdjustmentFactor*<<2>><1.1,10> ; adjustment factor for division or multiplication
TextLabel()
Real OutputMin**, OutputMax**<<10>>
;full PID tags
String GainTag@@{Tag}
String SPTag@@{Tag}
String MeasTag@@{Tag}
String RelErrorTag@@{Tag}
String OutMinTag@@{Tag}
String OutMaxTag@@{Tag}
Real OldDiff ;holds the previous error
Real Diff ;holds the current error
long classtag_length
;iteration counters for determining when to adjust
Integer ItersSinceLastDecrease
Integer ItersSinceLastIncrease
;internal flags
Bit IsFirstIteration
Bit SetOutputState
Sub Initialise()
;Check if the Class is defined as an array, if so, need to remove [index] from the classtag()
ClassAsArray = StrStr(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
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.
Sub CheckVersion()
Bit BuildOK
Const long VersionNumber = 32346
BuildOK = PM.Version(0)>=9 AND PM.Version(1)>=3 AND PM.Version(2)>=139 AND PM.Version(3)>=VersionNumber
If NOT BuildOK
;use the next line for latest versions of SysCAD, Build 139.32346 or later.
StopSolver("Incorrect version of SysCAD, needs SysCAD9.3 Build139.", IntToStr(VersionNumber)," or later.")
;OR use the next two lines for older versions of SysCAD, Build 139.32346 or earlier.
;LogError("Incorrect version of SysCAD, needs SysCAD9.3 Build139.", IntToStr(VersionNumber)," or later.")
;StopSimulation = true
Endif
EndSub
>>OptimiseGain.pgm
PageLabel("Acid")
;define the class instances
;We can use the PID unit Tag as the Class Tag, use the 2nd line (array) if multiple control blocks are from the same PID unit.
Class_OptimiseGain NonOxidising_Leach_Control
;Class_OptimiseGain NonOxidising_Leach_Control[2]
;initialise the class tags (user will need to specify the controller tag in the access window)
Sub PreStart()
CheckVersion()
;initialise the optimise sub routine. Use the 2nd line if class is defined as array.
ForEachClass(Class_OptimiseGain, Initialise())
;ForEachClass(NonOxidising_Leach_Control, Initialise())
EndSub
;execute the optimise sub routine. Use the 2nd line if class is defined as array.
ForEachClass(Class_OptimiseGain, Optimise())
;ForEachClass(NonOxidising_Leach_Control, 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. We can try and adjust the "NonOxidising_Leach_Control" - PID block 2.
NOTE:
|