@@ -19,26 +19,26 @@ Licensed under Apache2 license (see LICENSE file in main directory)
19
19
#include " exampleDir.h"
20
20
21
21
// a damped oscillator has two states, position and velocity
22
- const size_t STATE_DIM = ct::core::SecondOrderSystem::STATE_DIM; // = 2
23
- const size_t CONTROL_DIM = ct::core::SecondOrderSystem::CONTROL_DIM; // = 1
24
- const size_t OUTPUT_DIM = STATE_DIM ; // we measure the full state
25
- const size_t DIST_DIM = CONTROL_DIM ; // we consider an input disturbance
22
+ const size_t state_dim = ct::core::SecondOrderSystem::STATE_DIM; // = 2
23
+ const size_t control_dim = ct::core::SecondOrderSystem::CONTROL_DIM; // = 1
24
+ const size_t output_dim = state_dim ; // we measure the full state
25
+ const size_t dist_dim = control_dim ; // we consider an input disturbance
26
26
27
27
28
28
/* !
29
29
* \brief An example controller, in which we artifically add a time-varying disturbance.
30
30
* @note this is only required for this simulated example. Not required for proper simulator/hardware setups.
31
31
*/
32
- class CustomController : public ct ::core::Controller<STATE_DIM, CONTROL_DIM >
32
+ class CustomController : public ct ::core::Controller<state_dim, control_dim >
33
33
{
34
34
public:
35
35
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
36
36
37
- static const size_t STATE_DIM = 2 ;
38
- static const size_t CONTROL_DIM = 1 ;
37
+ static const size_t state_dim = 2 ;
38
+ static const size_t control_dim = 1 ;
39
39
40
40
// ! default constructor
41
- CustomController (const ct::core::ControlVector<CONTROL_DIM >& uff_max, // feedforward control amplitude
41
+ CustomController (const ct::core::ControlVector<control_dim >& uff_max, // feedforward control amplitude
42
42
const double & uff_frequency, // frequency of the feedforward control osciallation
43
43
const double & kp, // P gain
44
44
const double & kd, // D gain
@@ -58,25 +58,25 @@ class CustomController : public ct::core::Controller<STATE_DIM, CONTROL_DIM>
58
58
CustomController* clone () const override { return new CustomController (*this ); }
59
59
60
60
// ! override the compute control method with a custom control law which includes a disturbance
61
- void computeControl (const ct::core::StateVector<STATE_DIM >& state,
61
+ void computeControl (const ct::core::StateVector<state_dim >& state,
62
62
const double & t,
63
- ct::core::ControlVector<CONTROL_DIM >& controlAction) override
63
+ ct::core::ControlVector<control_dim >& controlAction) override
64
64
{
65
65
controlAction = uff_max_ * std::sin (t * uff_frequency_); // apply feedforward control
66
66
controlAction += getSimulatedDisturbance (t); // apply simulated disturbance
67
67
controlAction (0 ) += -kp_ * state (0 ) - kd_ * state (1 ); // add feedback control
68
68
}
69
69
70
70
// ! simulate the disturbance allow to reconstruct it from outside
71
- ct::core::ControlVector<CONTROL_DIM > getSimulatedDisturbance (const double & t)
71
+ ct::core::ControlVector<control_dim > getSimulatedDisturbance (const double & t)
72
72
{
73
- ct::core::ControlVector<CONTROL_DIM > dist_in;
73
+ ct::core::ControlVector<control_dim > dist_in;
74
74
dist_in (0 ) = d_ * std::cos (t * t * d_freq_);
75
75
return dist_in;
76
76
}
77
77
78
78
private:
79
- ct::core::ControlVector<CONTROL_DIM > uff_max_; // ! feedforward control action
79
+ ct::core::ControlVector<control_dim > uff_max_; // ! feedforward control action
80
80
double uff_frequency_; // frequency of feedforward oscillation
81
81
double kp_; // ! P gain
82
82
double kd_; // ! D gain
@@ -90,21 +90,21 @@ class CustomController : public ct::core::Controller<STATE_DIM, CONTROL_DIM>
90
90
* for dynamics prediction and computing derivatives.
91
91
* @note this system is not used for simulation, but for filtering.
92
92
*/
93
- template <size_t STATE_DIM , size_t DIST_DIM , size_t CONTROL_DIM , typename SCALAR = double >
94
- class CustomDisturbedSystem : public ct ::optcon::DisturbedSystem<STATE_DIM, DIST_DIM, CONTROL_DIM , SCALAR>
93
+ template <size_t state_dim , size_t dist_dim , size_t control_dim , typename SCALAR = double >
94
+ class CustomDisturbedSystem : public ct ::optcon::DisturbedSystem<state_dim, dist_dim, control_dim , SCALAR>
95
95
{
96
96
public:
97
97
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
98
98
99
99
// ! constructor
100
- CustomDisturbedSystem (std::shared_ptr<ct::core::ControlledSystem<STATE_DIM, CONTROL_DIM , SCALAR>> sys)
101
- : ct::optcon::DisturbedSystem<STATE_DIM, DIST_DIM, CONTROL_DIM , SCALAR>(sys->getController ()), system_(sys)
100
+ CustomDisturbedSystem (std::shared_ptr<ct::core::ControlledSystem<state_dim, control_dim , SCALAR>> sys)
101
+ : ct::optcon::DisturbedSystem<state_dim, dist_dim, control_dim , SCALAR>(sys->getController ()), system_(sys)
102
102
{
103
103
}
104
104
105
105
// ! copy constructor
106
106
CustomDisturbedSystem (const CustomDisturbedSystem& other)
107
- : ct::optcon::DisturbedSystem<STATE_DIM, DIST_DIM, CONTROL_DIM , SCALAR>(*this ), system_(other.system_->clone ())
107
+ : ct::optcon::DisturbedSystem<state_dim, dist_dim, control_dim , SCALAR>(*this ), system_(other.system_->clone ())
108
108
{
109
109
}
110
110
@@ -114,27 +114,27 @@ class CustomDisturbedSystem : public ct::optcon::DisturbedSystem<STATE_DIM, DIST
114
114
/* !
115
115
* Override the computeControlledDynamics() with a custom update rule.
116
116
*/
117
- void computeControlledDynamics (const ct::core::StateVector<STATE_DIM + DIST_DIM , SCALAR>& state,
117
+ void computeControlledDynamics (const ct::core::StateVector<state_dim + dist_dim , SCALAR>& state,
118
118
const SCALAR& t,
119
- const ct::core::ControlVector<CONTROL_DIM , SCALAR>& control,
120
- ct::core::StateVector<STATE_DIM + DIST_DIM , SCALAR>& derivative) override
119
+ const ct::core::ControlVector<control_dim , SCALAR>& control,
120
+ ct::core::StateVector<state_dim + dist_dim , SCALAR>& derivative) override
121
121
{
122
122
derivative.setZero ();
123
- ct::core::StateVector<STATE_DIM , SCALAR> tempDerivative;
123
+ ct::core::StateVector<state_dim , SCALAR> tempDerivative;
124
124
125
125
// the control consists of actual commanded control plus the estimated input disturbance,
126
126
// which is the augmented part of the state vector
127
- ct::core::ControlVector<CONTROL_DIM , SCALAR> disturbed_control = control + state.template tail <DIST_DIM >();
127
+ ct::core::ControlVector<control_dim , SCALAR> disturbed_control = control + state.template tail <dist_dim >();
128
128
129
129
// the dynamics of the augmented system
130
- system_->computeControlledDynamics (state.head (STATE_DIM ), t, disturbed_control, tempDerivative);
131
- derivative.template head <STATE_DIM >() = tempDerivative;
130
+ system_->computeControlledDynamics (state.head (state_dim ), t, disturbed_control, tempDerivative);
131
+ derivative.template head <state_dim >() = tempDerivative;
132
132
}
133
133
134
134
135
135
private:
136
136
// the nominal system (the one we are trying to control)
137
- std::shared_ptr<ct::core::ControlledSystem<STATE_DIM, CONTROL_DIM , SCALAR>> system_;
137
+ std::shared_ptr<ct::core::ControlledSystem<state_dim, control_dim , SCALAR>> system_;
138
138
};
139
139
140
140
@@ -149,7 +149,7 @@ int main(int argc, char** argv)
149
149
ct::core::loadScalar (configFile, " experiment_settings.nSteps" , nSteps);
150
150
151
151
// state vector (initial state)
152
- ct::core::StateVector<STATE_DIM > x;
152
+ ct::core::StateVector<state_dim > x;
153
153
ct::core::loadMatrix (configFile, " x0" , x);
154
154
155
155
// create an oscillator with resonance-frequency w_n
@@ -160,7 +160,7 @@ int main(int argc, char** argv)
160
160
// create our controller: a PD controller which also "simulates" a time-varying disturbance
161
161
double kp = 10.0 ;
162
162
double kd = 1.0 ;
163
- ct::core::ControlVector<CONTROL_DIM > uff_magnitude;
163
+ ct::core::ControlVector<control_dim > uff_magnitude;
164
164
double uff_frequency, disturbance_max, disturbance_freq;
165
165
ct::core::loadMatrix (configFile, " experiment_settings.uff_magnitude" , uff_magnitude);
166
166
ct::core::loadScalar (configFile, " experiment_settings.uff_frequency" , uff_frequency);
@@ -174,24 +174,23 @@ int main(int argc, char** argv)
174
174
oscillator->setController (disturbed_controller);
175
175
176
176
// create an integrator for "simulating" the measured data
177
- ct::core::Integrator<STATE_DIM > integrator (oscillator, ct::core::IntegrationType::EULERCT);
177
+ ct::core::Integrator<state_dim > integrator (oscillator, ct::core::IntegrationType::EULERCT);
178
178
179
- ct::core::StateVectorArray<STATE_DIM > states; // recorded sim states
180
- ct::core::ControlVectorArray<DIST_DIM > disturbance; // recorded disturbance
179
+ ct::core::StateVectorArray<state_dim > states; // recorded sim states
180
+ ct::core::ControlVectorArray<dist_dim > disturbance; // recorded disturbance
181
181
ct::core::tpl::TimeArray<double > times; // recorded times
182
182
183
183
// read process noise parameters from file
184
- ct::core::StateMatrix<STATE_DIM > process_var;
184
+ ct::core::StateMatrix<state_dim > process_var;
185
185
ct::core::loadMatrix (configFile, " process_noise.process_var" , process_var);
186
186
187
187
// process noise (scaled with dt)
188
188
ct::core::GaussianNoise position_process_noise (0.0 , dt * process_var (0 , 0 ));
189
189
ct::core::GaussianNoise velocity_process_noise (0.0 , dt * process_var (1 , 1 ));
190
190
191
191
// simulate the disturbed system to generate data
192
- ct::core::Time t0 = 0.0 ;
193
192
states.push_back (x);
194
- for (size_t i = 0 ; i < nSteps; i++)
193
+ for (int i = 0 ; i < nSteps; i++)
195
194
{
196
195
// integrate system
197
196
integrator.integrate_n_steps (x, i * dt, 1 , dt);
@@ -216,85 +215,87 @@ int main(int argc, char** argv)
216
215
std::shared_ptr<CustomController> controller_nominal (
217
216
new CustomController (uff_magnitude, uff_frequency, kp, kd, 0.0 , 0.0 ));
218
217
219
- std::shared_ptr<CustomDisturbedSystem<STATE_DIM, DIST_DIM, CONTROL_DIM >> customdisturbedSystem (
220
- new CustomDisturbedSystem<STATE_DIM, DIST_DIM, CONTROL_DIM >(oscillator_obs));
218
+ std::shared_ptr<CustomDisturbedSystem<state_dim, dist_dim, control_dim >> customdisturbedSystem (
219
+ new CustomDisturbedSystem<state_dim, dist_dim, control_dim >(oscillator_obs));
221
220
222
221
// Observation matrix for the state
223
- ct::core::OutputStateMatrix<OUTPUT_DIM, STATE_DIM > C;
222
+ ct::core::OutputStateMatrix<output_dim, state_dim > C;
224
223
C.setIdentity ();
225
224
226
225
// Observation matrix for the disturbance (assuming the disturbance does not enter the output equation)
227
- ct::core::OutputStateMatrix<OUTPUT_DIM, DIST_DIM > Cd;
226
+ ct::core::OutputStateMatrix<output_dim, dist_dim > Cd;
228
227
Cd.setZero ();
229
228
230
229
// Total observation matrix, state and disturbance combined
231
- ct::core::OutputStateMatrix<OUTPUT_DIM, STATE_DIM + DIST_DIM , double > Caug;
230
+ ct::core::OutputStateMatrix<output_dim, state_dim + dist_dim , double > Caug;
232
231
Caug << C, Cd;
233
232
234
233
// Kalman filter weighting matrices Q, dFdv and R
235
- ct::core::StateMatrix<STATE_DIM + DIST_DIM > Qaug, dFdv;
236
- ct::core::OutputMatrix<OUTPUT_DIM > R;
234
+ ct::core::StateMatrix<state_dim + dist_dim > Qaug, dFdv;
235
+ ct::core::OutputMatrix<output_dim > R;
237
236
ct::core::loadMatrix (configFile, " kalman_weights.Qaug" , Qaug);
238
237
ct::core::loadMatrix (configFile, " kalman_weights.R" , R);
239
238
240
239
dFdv.setIdentity (); // todo tune me
241
240
242
241
// create a sensitivity approximator to obtain discrete-time dynamics matrices
243
- std::shared_ptr<ct::core::SystemLinearizer<STATE_DIM + DIST_DIM, CONTROL_DIM>> linearizer (
244
- new ct::core::SystemLinearizer<STATE_DIM + DIST_DIM, CONTROL_DIM>(customdisturbedSystem));
245
- ct::core::SensitivityApproximation<STATE_DIM + DIST_DIM, CONTROL_DIM> sensApprox (dt, linearizer);
242
+ std::shared_ptr<ct::core::SystemLinearizer<state_dim + dist_dim, control_dim>> linearizer (
243
+ new ct::core::SystemLinearizer<state_dim + dist_dim, control_dim>(customdisturbedSystem));
244
+ ct::core::SensitivityApproximation<state_dim + dist_dim, control_dim> sensApprox (dt, linearizer);
245
+
246
+ // set up the system model
247
+ std::shared_ptr<ct::optcon::CTSystemModel<state_dim + dist_dim, control_dim>> sysModel (
248
+ new ct::optcon::CTSystemModel<state_dim + dist_dim, control_dim>(customdisturbedSystem, sensApprox, dFdv));
249
+
250
+ // set up the measurement model
251
+ std::shared_ptr<ct::optcon::LinearMeasurementModel<output_dim, state_dim + dist_dim>> measModel (
252
+ new ct::optcon::LTIMeasurementModel<output_dim, state_dim + dist_dim>(Caug));
246
253
247
254
// load measurement noise data from file
248
- ct::core::StateMatrix<STATE_DIM > meas_var;
255
+ ct::core::StateMatrix<state_dim > meas_var;
249
256
ct::core::loadMatrix (configFile, " measurement_noise.measurement_var" , meas_var);
250
257
ct::core::GaussianNoise position_measurement_noise (0.0 , meas_var (0 , 0 ));
251
258
ct::core::GaussianNoise velocity_measurement_noise (0.0 , meas_var (1 , 1 ));
252
259
253
260
// generate initial state for the estimator (with noise, disturbance assumed to be zero at beginning)
254
- ct::core::StateVector<STATE_DIM + DIST_DIM > x0aug;
261
+ ct::core::StateVector<state_dim + dist_dim > x0aug;
255
262
x0aug << states[0 ], 0.0 ;
256
263
position_measurement_noise.noisify (x0aug (0 ));
257
264
velocity_measurement_noise.noisify (x0aug (1 ));
258
265
259
- // create instance of the extended Kalman Filter
260
- // initialize it estimated starting covariance equal to Qaug
261
- ct::optcon::ExtendedKalmanFilter<STATE_DIM + DIST_DIM> ekf (x0aug, Qaug);
262
-
263
- // create instance of the disturbance observer
264
- ct::optcon::DisturbanceObserver<OUTPUT_DIM, STATE_DIM, DIST_DIM, CONTROL_DIM,
265
- ct::optcon::ExtendedKalmanFilter<STATE_DIM + DIST_DIM>>
266
- disturbanceObserver (customdisturbedSystem, sensApprox, Caug, ekf, Qaug, R, dFdv);
267
-
268
-
269
266
// data containers for logging data while estimating
270
- ct::core::StateVectorArray<STATE_DIM + DIST_DIM > states_est (states.size ());
271
- ct::core::OutputVectorArray<OUTPUT_DIM > output_meas (states.size ());
272
- ct::core::StateMatrixArray<STATE_DIM + DIST_DIM > cov_est (states.size ());
267
+ ct::core::StateVectorArray<state_dim + dist_dim > states_est (states.size ());
268
+ ct::core::OutputVectorArray<output_dim > output_meas (states.size ());
269
+ ct::core::StateMatrixArray<state_dim + dist_dim > cov_est (states.size ());
273
270
states_est[0 ] = x0aug;
274
271
output_meas[0 ] = states[0 ];
275
- cov_est[0 ] = disturbanceObserver.getCovarianceMatrix ();
272
+ cov_est[0 ] = Qaug;
273
+
274
+
275
+ // set up Extended Kalman Filter
276
+ ct::optcon::ExtendedKalmanFilter<state_dim + dist_dim, control_dim, output_dim> ekf (sysModel, measModel, Qaug, R, x0aug, Qaug);
276
277
277
278
278
279
// run the filter over the simulated data
279
280
for (size_t i = 1 ; i < states.size (); ++i)
280
281
{
281
282
// compute an observation
282
- ct::core::OutputVector<OUTPUT_DIM > y = C * states[i] + Cd * disturbance[i - 1 ];
283
+ ct::core::OutputVector<output_dim > y = C * states[i] + Cd * disturbance[i - 1 ];
283
284
position_measurement_noise.noisify (y (0 )); // Position noise.
284
285
velocity_measurement_noise.noisify (y (1 )); // Velocity noise.
285
286
output_meas[i] = y;
286
287
287
288
// this is the control input that we would have "measured"
288
- ct::core::ControlVector<CONTROL_DIM > nominal_control;
289
- controller_nominal->computeControl (states_est[i - 1 ].template head <STATE_DIM >(), dt * (i - 1 ), nominal_control);
289
+ ct::core::ControlVector<control_dim > nominal_control;
290
+ controller_nominal->computeControl (states_est[i - 1 ].template head <state_dim >(), dt * (i - 1 ), nominal_control);
290
291
291
292
// Kalman filter prediction step
292
- disturbanceObserver .predict (nominal_control, dt, dt * i);
293
+ ekf .predict (nominal_control, dt, dt * i);
293
294
294
295
// Kalman filter estimation step (state + disturbance)
295
- states_est[i] = disturbanceObserver .update (y, dt, dt * i);
296
+ states_est[i] = ekf .update (y, dt, dt * i);
296
297
297
- cov_est[i] = disturbanceObserver .getCovarianceMatrix ();
298
+ cov_est[i] = ekf .getCovarianceMatrix ();
298
299
}
299
300
300
301
0 commit comments