Stroika Library 3.0d16
 
Loading...
Searching...
No Matches
PIDLoop.inl
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2025. All rights reserved
3 */
4#include "Sleep.h"
7
8// Comment this in to turn on aggressive noisy DbgTrace in this module (note the extra long name since its in a header)
9//#define Stroika_Foundation_Execution_PIDLoop_USE_NOISY_TRACE_IN_THIS_MODULE_ 1
10
12
13 /*
14 ********************************************************************************
15 ********************* PIDLoop<CONTROL_VAR_TYPE>::ControlParams *****************
16 ********************************************************************************
17 */
18 template <typename CONTROL_VAR_TYPE>
19 inline PIDLoop<CONTROL_VAR_TYPE>::ControlParams::ControlParams (ValueType p, ValueType i, ValueType d)
20 : P{p}
21 , I{i}
22 , D{d}
23 {
24 }
25 template <typename CONTROL_VAR_TYPE>
27 {
29 out << "{"sv;
30 out << "P: "sv << P << "',"sv;
31 out << "I: "sv << I << "',"sv;
32 out << "D: "sv << D;
33 out << "}"sv;
34 return out.str ();
35 }
36
37 /*
38 ********************************************************************************
39 ************************** PIDLoop<CONTROL_VAR_TYPE> ***************************
40 ********************************************************************************
41 */
42 template <typename CONTROL_VAR_TYPE>
43 PIDLoop<CONTROL_VAR_TYPE>::PIDLoop (const ControlParams& pidParams, Time::DurationSeconds updatePeriod, const function<ValueType ()>& measureFunction,
44 const function<void (ValueType o)>& outputFunction, ValueType initialSetPoint)
45 : fPIDParams_{pidParams}
46 , fUpdatePeriod_{updatePeriod}
47 , fMeasureFunction_{measureFunction}
48 , fOutputFunction_{outputFunction}
49 {
50 Require (updatePeriod > 0);
51 fUpdatableParams_.rwget ()->fSetPoint_ = (initialSetPoint);
52 }
53 template <typename CONTROL_VAR_TYPE>
54 PIDLoop<CONTROL_VAR_TYPE>::PIDLoop (AutoStartFlag, const ControlParams& pidParams, Time::DurationSeconds updatePeriod,
55 const function<ValueType ()>& measureFunction, const function<void (ValueType o)>& outputFunction,
56 ValueType initialSetPoint)
57 : PIDLoop{pidParams, updatePeriod, measureFunction, outputFunction, initialSetPoint}
58 {
59 (void)RunInThread ();
60 }
61 template <typename CONTROL_VAR_TYPE>
63 {
64 if (fThread_) {
65 fThread_->AbortAndWaitForDone ();
66 }
67 }
68 template <typename CONTROL_VAR_TYPE>
69 inline auto PIDLoop<CONTROL_VAR_TYPE>::GetSetPoint () const -> ValueType
70 {
71 return fUpdatableParams_->fSetPoint_;
72 }
73 template <typename CONTROL_VAR_TYPE>
74 inline void PIDLoop<CONTROL_VAR_TYPE>::SetSetPoint (ValueType sp)
75 {
76 if (sp != fUpdatableParams_->fSetPoint_) {
77 // we cannot predict how fPrevError_/fIntegral_ should change with a new setpoint, so clear them
78 fUpdatableParams_ = {sp, ValueType{}, ValueType{}};
79 }
80 }
81 template <typename CONTROL_VAR_TYPE>
83 {
84 return fPIDParams_;
85 }
86 template <typename CONTROL_VAR_TYPE>
87 inline auto PIDLoop<CONTROL_VAR_TYPE>::GetUpdatePeriod () const -> Time::DurationSeconds
88 {
89 return fUpdatePeriod_;
90 }
91 template <typename CONTROL_VAR_TYPE>
93 {
94 Time::DurationSeconds nextRunAt = Time::GetTickCount ();
95 while (true) {
96 SleepUntil (nextRunAt);
97 try {
98 ValueType measuredValue = fMeasureFunction_ ();
99 ValueType setPoint = fUpdatableParams_->fSetPoint_;
100 ValueType error = setPoint - measuredValue;
101 ValueType derivative = (error - fUpdatableParams_->fPrevError_) / fUpdatePeriod_;
102 {
103 auto updateUpdatableParams = fUpdatableParams_.rwget ();
104 updateUpdatableParams->fIntegral_ += error * fUpdatePeriod_;
105 updateUpdatableParams->fPrevError_ = error;
106 }
107 ValueType outputFunctionArgument = fPIDParams_.P * error + fPIDParams_.I * fUpdatableParams_->fIntegral_ + fPIDParams_.D * derivative;
108 fOutputFunction_ (outputFunctionArgument);
109 nextRunAt += fUpdatePeriod_;
110#if Stroika_Foundation_Execution_PIDLoop_USE_NOISY_TRACE_IN_THIS_MODULE_
111 DbgTrace ("Completed PIDLoop update: set-point={}, measuredValue{}, error={}, derivative={}, integral={}, outputFunctionArgument={}, nextRunAt={}"_f,
112 setPoint, measuredValue, error, derivative, fUpdatableParams_->fIntegral_, outputFunctionArgument, nextRunAt);
113#endif
114 }
115 catch (const Thread::AbortException&) {
117 }
118 catch (...) {
119 DbgTrace (L"Suppressing exception in PIDLoop: {}"_f, current_exception ());
120 }
121 }
122 }
123 template <typename CONTROL_VAR_TYPE>
125 {
126 Require (not fThread_.has_value ());
127 fThread_ = Thread::New ([this] () { RunDirectly (); }, Thread::eAutoStart);
128 return *fThread_;
129 }
130
131}
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
Definition Realtime.h:57
#define DbgTrace
Definition Trace.h:309
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual Thread::Ptr RunInThread()
Definition PIDLoop.inl:124
nonvirtual ControlParams GetControlParams() const
Definition PIDLoop.inl:82
nonvirtual void SetSetPoint(ValueType sp)
Definition PIDLoop.inl:74
nonvirtual WritableReference rwget()
get a read-write smart pointer to the underlying Synchronized<> object, holding the full lock the who...
Thread::Ptr is a (unsynchronized) smart pointer referencing an internally synchronized std::thread ob...
Definition Thread.h:334
Ptr New(const function< void()> &fun2CallOnce, const optional< Characters::String > &name, const optional< Configuration > &configuration)
Definition Thread.cpp:955
void SleepUntil(Time::TimePointSeconds untilTickCount)
Definition Sleep.inl:91