Skip to content

Commit e2295b2

Browse files
author
camilo
committed
Added smithPredictor to ltisys. bump to 1.3.7
1 parent bd14729 commit e2295b2

File tree

6 files changed

+147
-16
lines changed

6 files changed

+147
-16
lines changed

library.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
"maintainer": true
1717
}
1818
],
19-
"version": "1.3.6",
19+
"version": "1.3.7",
2020
"license": "MIT",
2121
"frameworks": "arduino",
2222
"platforms": "*"

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=qlibs
2-
version=1.3.6
2+
version=1.3.7
33
license=MIT
44
author=J. Camilo Gomez C. <[email protected]>
55
maintainer=J. Camilo Gomez C. <[email protected]>

src/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required( VERSION 3.2 )
22
project( qlibs-cpp
3-
VERSION 1.3.6
3+
VERSION 1.3.7
44
DESCRIPTION "A collection of useful C++ libraries for embedded systems"
55
LANGUAGES CXX )
66

src/include/ltisys.hpp

Lines changed: 127 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,16 @@ namespace qlibs {
137137
return static_cast<size_t>( ( Time.value/dt ) + 0.5_re );
138138
}
139139

140+
/** @cond **/
141+
class ITransportDelay {
142+
public:
143+
virtual ~ITransportDelay() = default;
144+
virtual real_t delay(const real_t xInput) noexcept = 0;
145+
virtual real_t operator()(const real_t xInput) noexcept = 0;
146+
virtual size_t getNumberOfDelays() const noexcept = 0;
147+
};
148+
/** @cond **/
149+
140150
/**
141151
* @brief Delays the input by a specified amount of time. You can use this
142152
* class to simulate a time delay.
@@ -150,11 +160,12 @@ namespace qlibs {
150160
* @endcode
151161
*/
152162
template<size_t numberOfDelays>
153-
class transportDelay {
163+
class transportDelay : public ITransportDelay {
154164
private:
155165
real_t buf[ numberOfDelays + 1 ];
156-
tdl delay;
166+
tdl dl;
157167
public:
168+
virtual ~transportDelay() {}
158169
/**
159170
* @brief Constructor for the transportDelay class
160171
* @param[in] initValue The output generated by the block between the
@@ -163,17 +174,28 @@ namespace qlibs {
163174
transportDelay( const real_t initValue = 0.0_re )
164175
{
165176
static_assert( numberOfDelays >= 1 , "Delay taps should be greater than 0" );
166-
delay.setup( buf, initValue);
177+
dl.setup( buf, initValue);
178+
}
179+
180+
/**
181+
* @brief Delays the input by a specified amount of time.
182+
* @param[in] xInput The signal to be delayed.
183+
* @return The delayed input signal
184+
*/
185+
real_t delay( const real_t xInput ) noexcept override
186+
{
187+
dl.insertSample( xInput );
188+
return dl.getOldest();
167189
}
190+
168191
/**
169192
* @brief Delays the input by a specified amount of time.
170193
* @param[in] xInput The signal to be delayed.
171194
* @return The delayed input signal
172195
*/
173-
real_t operator()( const real_t xInput ) noexcept
196+
real_t operator()( const real_t xInput ) noexcept override
174197
{
175-
delay.insertSample( xInput );
176-
return delay.getOldest();
198+
return delay( xInput );
177199
}
178200

179201
constexpr size_t getNumberOfDelays() const noexcept {
@@ -276,7 +298,7 @@ namespace qlibs {
276298
* @param[in] u A new input sample that excites (drives) the system.
277299
* @return The system's output (response) at the current time step.
278300
*/
279-
real_t excite( real_t u );
301+
real_t excite( real_t u ) noexcept;
280302

281303
/// @copydoc excite(real_t)
282304
real_t operator()( const real_t u ) {
@@ -721,6 +743,104 @@ namespace qlibs {
721743
bool setIntegrationMethod( integrationMethod m );
722744
};
723745

746+
/**
747+
* @brief A Smith Predictor implementation for compensating time delays in
748+
* control systems.
749+
* @details The Smith Predictor is a model-based feedforward control strategy
750+
* designed to improve performance in systems with significant dead time.
751+
* It estimates the delay-free output using an internal model of the process,
752+
* a delay block, and optionally an output filter model.
753+
*/
754+
class smithPredictor {
755+
private:
756+
ltisys *model;
757+
ITransportDelay *modelDelay;
758+
ltisys *filter{ nullptr };
759+
real_t yp_hat;
760+
public:
761+
virtual ~smithPredictor() {}
762+
/**
763+
* @brief Constructs a Smith Predictor with a plant model, delay model,
764+
* and optional initial output estimate.
765+
* @param[in] modelTf Reference to the LTI system model representing the
766+
* delay-free plant.
767+
* @param[in] mDelay Reference to the transport delay block modeling the
768+
* plant’s dead time.
769+
* @param[in] initialCondition Initial value for the internal output
770+
* prediction (@c yp_hat). Default is 0.0.
771+
*
772+
* @note Both the model and delay block are passed by reference and stored internally as pointers.
773+
*/
774+
smithPredictor( ltisys& modelTf,
775+
ITransportDelay& mDelay,
776+
const real_t initialCondition = 0.0_re )
777+
: model(&modelTf), modelDelay(&mDelay), yp_hat(initialCondition) {}
778+
779+
/**
780+
* @brief Constructs a Smith Predictor with a plant model, delay model,
781+
* and optional initial output estimate.
782+
* @param[in] modelTf Reference to the LTI system model representing the
783+
* delay-free plant.
784+
* @param[in] mDelay Reference to the transport delay block modeling the
785+
* plant’s dead time.
786+
* @param[in] filterTf Reference to the LTI system used as the robustness
787+
* filter.
788+
* @param[in] initialCondition Initial value for the internal output
789+
* prediction (@c yp_hat). Default is 0.0.
790+
*
791+
* @note Both the model and delay block are passed by reference and stored internally as pointers.
792+
*/
793+
smithPredictor( ltisys& modelTf,
794+
ITransportDelay& mDelay,
795+
ltisys& filterTf,
796+
const real_t initialCondition = 0.0_re )
797+
: model(&modelTf), modelDelay(&mDelay), filter(&filterTf), yp_hat(initialCondition) {}
798+
799+
/**
800+
* @brief Updates the internal prediction based on control input and
801+
* measured plant output.
802+
* @details This method should be called at each control step. It updates
803+
* the internal predicted output by propagating the input through the
804+
* internal delay-free model and adjusting the prediction using the
805+
* actual plant output.
806+
*
807+
* @param[in] ut The control input applied to the real plant.
808+
* @param[in] yt The actual measured output from the delayed plant.
809+
* @return @c true if the prediction was successfully updated, @c false otherwise.
810+
*
811+
* @note The time-step used to call this function must match the time
812+
* base used by both the plant model and the delay block.
813+
*/
814+
bool updatePrediction( const real_t ut,
815+
const real_t yt ) noexcept;
816+
817+
/**
818+
* @brief Retrieves the current delay-free predicted output of the system.
819+
* @return The internally computed predicted output.
820+
*/
821+
real_t getPrediction() const noexcept {
822+
return yp_hat;
823+
}
824+
825+
/**
826+
* @brief Sets an optional filter for the internal Smith Predictor model.
827+
* @details The filter is used to improve the system's robustness, attenuate
828+
* measurement noise, and ensure internal stability, particularly in the case
829+
* of unstable plant dynamics.
830+
*
831+
* @param[in] filterTf Reference to the LTI system used as the robustness
832+
* filter.
833+
* @return @c true if the filter was set successfully.
834+
*
835+
* @note The filter is applied internally to the model-based prediction
836+
* and does not affect the plant or delay block directly.
837+
*/
838+
bool setFilter( ltisys& filterTf ) noexcept {
839+
filter = &filterTf;
840+
return true;
841+
}
842+
};
843+
724844
/** @}*/
725845
}
726846

src/ltisys.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ bool ltisys::setSaturation( const real_t minV,
6262
return retValue;
6363
}
6464
/*============================================================================*/
65-
real_t ltisys::excite( real_t u )
65+
real_t ltisys::excite( real_t u ) noexcept
6666
{
6767
real_t y = 0.0_re;
6868

@@ -283,4 +283,15 @@ bool continuousSystem::setIntegrationMethod( integrationMethod m )
283283

284284
return retValue;
285285
}
286+
/*============================================================================*/
287+
bool smithPredictor::updatePrediction( const real_t ut,
288+
const real_t yt ) noexcept
289+
{
290+
const real_t yt_hat_d = model->excite( ut );
291+
const real_t yt_hat = modelDelay->delay( yt_hat_d );
292+
const real_t ep_hat = yt - yt_hat;
293+
294+
yp_hat = yt_hat_d + ( filter ? filter->excite( ep_hat ) : ep_hat );
295+
return true;
296+
}
286297
/*============================================================================*/

src/qlibs.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*!
22
* @file qlibs.h
33
* @author J. Camilo Gomez C.
4-
* @version 1.3.6
4+
* @version 1.3.7
55
* @note This file is part of the qlibs++ distribution.
66
* @brief Global inclusion header
77
**/
@@ -41,8 +41,8 @@ This file is part of the QuarkTS++ OS distribution.
4141
#ifndef QLIBS_CPP_H
4242
#define QLIBS_CPP_H
4343

44-
#define QLIBS_CPP_VERSION "1.3.6"
45-
#define QLIBS_CPP_VERNUM ( 136 )
44+
#define QLIBS_CPP_VERSION "1.3.7"
45+
#define QLIBS_CPP_VERNUM ( 137 )
4646
#define QLIBS_CPP_CAPTION "qLibs++ " QLIBS_CPP_VERSION
4747

4848
#include <include/qlibs_types.hpp>
@@ -62,7 +62,7 @@ This file is part of the QuarkTS++ OS distribution.
6262

6363
namespace qlibs {
6464
namespace build {
65-
constexpr const uint32_t number = 2388;
65+
constexpr const uint32_t number = 2397;
6666
constexpr const char* date = __DATE__;
6767
constexpr const char* time = __TIME__;
6868
constexpr const char* std = "c++11";
@@ -72,7 +72,7 @@ This file is part of the QuarkTS++ OS distribution.
7272
constexpr const uint8_t number = QLIBS_CPP_VERNUM;
7373
constexpr const uint8_t mayor = 1U;
7474
constexpr const uint8_t minor = 3U;
75-
constexpr const uint8_t rev = 6U;
75+
constexpr const uint8_t rev = 7U;
7676
}
7777
namespace product {
7878
constexpr const char* author = "J. Camilo Gomez C.";

0 commit comments

Comments
 (0)