This example shows how to use the Kalman Filter to simultaneously estimate the state and the disturbance acting on a simple linear oscillator system. The gist of the example is that the state is augmented with a disturbance and the system dynamics is augmented with the disturbance.
Using the parameters loaded from file, we can change initial state, apply additional feed-forward controls and vary both frequency and magnitude of the disturbance. Furthermore, it holds the Kalman Filter tuning parameters and noise parameters for simulation.
{
public:
EIGEN_MAKE_ALIGNED_OPERATOR_NEW
const double& uff_frequency,
const double& kp,
const double& kd,
const double& disturbance_max,
const double& disturbance_frequency
)
: uff_max_(uff_max),
uff_frequency_(uff_frequency),
kp_(kp),
kd_(kd),
d_(disturbance_max),
d_freq_(disturbance_frequency)
{
}
{
controlAction = uff_max_ * std::sin(t * uff_frequency_);
controlAction += getSimulatedDisturbance(t);
controlAction(0) += -kp_ * state(0) - kd_ * state(1);
}
{
dist_in(0) = d_ * std::cos(t * t * d_freq_);
return dist_in;
}
private:
double uff_frequency_;
double kp_;
double kd_;
double d_;
double d_freq_;
};
int main(
int argc,
char** argv)
{
std::string configFile = ct::optcon::exampleDir + "/kalmanDisturbanceFilterSettings.info";
int nSteps;
double kp = 10.0;
double kd = 1.0;
double uff_frequency, disturbance_max, disturbance_freq;
std::shared_ptr<CustomController> disturbed_controller(
new CustomController(uff_magnitude, uff_frequency, kp, kd, disturbance_max, disturbance_freq));
oscillator->setController(disturbed_controller);
states.push_back(x);
for (
int i = 0;
i < nSteps;
i++)
{
disturbance.push_back(disturbed_controller->getSimulatedDisturbance(dt *
i));
states.push_back(x);
times.push_back(i * dt);
}
std::shared_ptr<CustomController> controller_nominal(
std::shared_ptr<ct::optcon::InputDisturbedSystem<state_dim, control_dim>> inputDisturbedSystem(
C.setIdentity();
Cd.setZero();
Caug << C, Cd;
dFdv.setIdentity();
std::shared_ptr<ct::core::SystemLinearizer<state_dim + dist_dim, control_dim>>
linearizer(
std::shared_ptr<ct::core::SensitivityApproximation<state_dim + dist_dim, control_dim>> sensApprox(
std::shared_ptr<ct::optcon::CTSystemModel<state_dim + dist_dim, control_dim>> sysModel(
std::shared_ptr<ct::optcon::LinearMeasurementModel<output_dim, state_dim + dist_dim>> measModel(
x0aug << states[0], 0.0;
position_measurement_noise.
noisify(x0aug(0));
velocity_measurement_noise.
noisify(x0aug(1));
states_est[0] = x0aug;
output_meas[0] = states[0];
cov_est[0] = Qaug;
sysModel, measModel, Qaug, R, x0aug, Qaug);
for (
size_t i = 1;
i < states.size(); ++
i)
{
position_measurement_noise.
noisify(y(0));
velocity_measurement_noise.
noisify(y(1));
controller_nominal->computeControl(states_est[
i - 1].
template head<state_dim>(), dt * (
i - 1), nominal_control);
ekf.
predict(nominal_control, dt, dt *
i);
states_est[
i] = ekf.
update(y, dt, dt * i);
}
#ifdef PLOTTING_ENABLED
std::vector<double> time_plot;
std::vector<double> pos_est_plot, vel_est_plot, dist_est_plot;
std::vector<double> pos_plot, vel_plot, dist_plot;
std::vector<double> pos_meas_plot, vel_meas_plot;
std::vector<double> pos_var_plot_upper, pos_var_plot_lower, vel_var_plot_upper, vel_var_plot_lower,
dist_var_plot_upper, dist_var_plot_lower;
for (
size_t i = 0;
i < times.size();
i++)
{
time_plot.push_back(times[
i]);
pos_plot.push_back(states[i](0));
pos_meas_plot.push_back(output_meas[i](0));
pos_est_plot.push_back(states_est[i](0));
pos_var_plot_upper.push_back(pos_est_plot[i] + cov_est[i](0, 0));
pos_var_plot_lower.push_back(pos_est_plot[i] - cov_est[i](0, 0));
vel_plot.push_back(states[i](1));
vel_meas_plot.push_back(output_meas[i](1));
vel_est_plot.push_back(states_est[i](1));
vel_var_plot_upper.push_back(vel_est_plot[i] + cov_est[i](1, 1));
vel_var_plot_lower.push_back(vel_est_plot[i] - cov_est[i](1, 1));
dist_plot.push_back(disturbance[i](0));
dist_est_plot.push_back(states_est[i](2));
dist_var_plot_upper.push_back(dist_est_plot[i] + cov_est[i](2, 2));
dist_var_plot_lower.push_back(dist_est_plot[i] - cov_est[i](2, 2));
}
#else // print results to command line
for (
size_t i = 0;
i < times.size();
i++)
{
std::cout << std::fixed << std::setprecision(6) <<
"pos:\t" << states[
i][0] <<
"\t pos est:\t" << states_est[
i][0] <<
"\t dist:\t" << states_est[
i][2] << std::endl
<<
"vel: \t" << states[
i][1] <<
"\t vel est:\t" << states_est[
i][1] << std::endl
<< std::endl;
}
#endif
return 0;
}