FhSim  3.1.0
Marine systems simulation
Loading...
Searching...
No Matches
Simple PID Controller

Class modelling a simple PID controller.

+ Collaboration diagram for Simple PID Controller:
Author
Karl-Johan Reite
Date
13.08.2013 KJR: Initial version.

The law

The controller is a PidWithExternalState, the law TrawlDoorControlledLift uses too. The integral of the error is the state IntegratedError, which FhSim integrates with the plant, and Out is evaluated from the state at every call:

\[ \mathrm{Out} = \mathrm{bound}\Big(k_P e + \big(\mathrm{InitOutput} + k_I \textstyle\int e\,\mathrm{d}t\big) + \mathrm{bound}\big(k_D \dot e, \pm\mathrm{MaxDerivativePart}\big), \mathrm{MinOut}, \mathrm{MaxOut}\Big), \qquad e = r - y. \]

Until fishery 3.1.1 the class used sfh::filters::PID: Out was a sample held from the last accepted step, the integral was summed by Euler at accepted steps, MaxIntegratorPart clamped the integrator value (which included InitOutput) and Out was InitOutput until the first accepted step. See CHANGELOG.md.

The sign of the gains

This class forms error = measurement - reference, which is the opposite of the usual convention, and PidWithExternalState then forms -kP * error, and likewise for the integral and derivative parts. The two inversions cancel, so the composition is the ordinary law above with \(e = r - y\), and each gain simply takes the sign of the plant it drives: positive when the measurement rises as the output rises, negative when it falls. An AUV heading loop on Auv.RudderYaw takes positive gains; an AUV pitch loop on Auv.RudderDive takes negative ones, because that port is named for its effect and a dive is a negative pitch. See tests/in/Auv/Auv_ClosedLoop_in.xml for all three worked out.

Neither inversion may be removed on its own, and removing both at once is pointless: the pair is already correct, and touching either would silently flip every gain in every existing trawl model. See FISH-0035 (resolved).

Example configuration excerpt

<Lib
LibName = "fishery"
SimObject = "Trawl/PIDController"
Name = "PID"
InitOutput = "0"
ProportionalGain = "1"
IntegratorGain = "0"
DerivativeGain = "0"
MinOut = "-1e10"
MaxOut = "1e10"
MaxDerivativePart = "1e10"
MaxIntegratorPart = "1e10"
/>

Input Ports

Name Width Description
Measurement 1 The measured value.
Reference 1

The desired value.

Output Ports

Name Width Description
Out 1 The output from the PID controller.

Configuration parameters

Name Width Description
InitOutput 1 Constant offset of the integral part (feed-forward). Default: 0.
ProportionalGain 1 Proportional gain on Reference - Measurement. Negative for a plant whose measurement falls when Out rises; see "The sign of the gains". @addoption{IntegratorGain, 1, Integral gain on Reference - Measurement. Takes the sign of the plant, like ProportionalGain. } @addoption{DerivativeGain, 1, Derivative gain on Reference - Measurement. Takes the sign of the plant, like ProportionalGain.}
MinOut 1 Minimum out value. Default: unbounded.
MaxOut 1 Maximum out value. Default: unbounded.
MaxDerivativePart 1 Bound of the magnitude of the derivative part. Default: unbounded.
MaxIntegratorPart 1 Anti-windup: the integral freezes while the magnitude of the integral part is past this (or past MinOut/MaxOut). Default: unbounded.

Initial conditions

Name Width Description
IntegratedError 1 The integral of Measurement - Reference, the error as this class forms it (see "The sign of the gains"). Default: 0.

Full example file

<Contents>
<OBJECTS>
<Lib
LibName = "fishery"
SimObject = "Trawl/PIDController"
Name = "PID"
InitOutput = "0"
ProportionalGain = "1"
IntegratorGain = "0"
DerivativeGain = "0"
MinOut = "-1e10"
MaxOut = "1e10"
MaxDerivativePart = "1e10"
MaxIntegratorPart = "1e10"
/>
</OBJECTS>
<INTERCONNECTIONS>
<Connection
PID.Measurement = "3"
PID.Reference = "4"
/>
</INTERCONNECTIONS>
<INITIALIZATION>
<InitialCondition
/>
</INITIALIZATION>
<SIMULATION>
<Timing TStart="0" TEnd="30"/>
<Integrator Method="RK45_i" NumCores="1" LogStates="1" UseRSSNorm="0">
<StepControl StepMax="0.002" StepMin="0.00000001" AbsTol="1e-3" RelTol="1e-3"/>
</Integrator>
<!-- TODO migrate_v3: FileOutput="objects:all" -> configure via <OBSERVERS> section -->
</SIMULATION>
</Contents>

This SimObject is referred to as Trawl/PIDController