#pragma once #include #include #include #include #ifndef CONTROL_H #define CONTROL_H #define CT_ASSERT(x) (assert(x)) #define CT_SMALL_TOL 1e-6 #define CT_ASSERT_SMALL(x) (assert(std::abs(x) < CT_SMALL_TOL)) namespace ct { using complex = std::complex; namespace math { template struct Poly { arma::Col coeffs; Poly(size_t n_elem) : coeffs(n_elem) {}; Poly(arma::Col c) : coeffs(c) {} int degree() const { return coeffs.n_elem - 1; } void add_root(T r) { (*this) = (*this) * Poly({1, -r}); } arma::Col roots() const { return arma::roots(coeffs); } template T& operator () (IndexT idx) { return coeffs(idx); }; template T operator () (IndexT idx) const { return coeffs(idx); }; }; template Poly operator * (const Poly& p, const Poly& q) { arma::Col coeffs = arma::conv(p.coeffs, q.coeffs); return Poly(coeffs); } template Poly operator * (R scalar, const Poly& p) { Poly q(p.coeffs * scalar); return q; } template Poly operator + (const Poly& p, const Poly& q) { const Poly& big = (p.degree() > q.degree()) ? p : q; const Poly& small = (p.degree() > q.degree()) ? q : p; Poly s(big.degree() + 1); for (int i = 0; i <= small.degree(); i++) s(i) = big(i) + small(i); for (int i = small.degree() + 1; i <= big.degree(); i++) s(i) = big(i); return s; } } struct TransferFn { complex gain; math::Poly num; math::Poly den; TransferFn(complex gain); inline void add_pole(complex p) { den.add_root(p); } inline void add_zero(complex z) { num.add_root(z); }; bool is_proper() const; bool is_strictly_proper() const; }; TransferFn feedback(const TransferFn& tf, double k = -1); struct LocusSeries { size_t n_samples; double start, end; arma::vec in; arma::cx_mat out; LocusSeries() = delete; LocusSeries(double start, double end, size_t n_samples); }; void rlocus(const TransferFn& tf, LocusSeries& ls); struct SSModel { size_t n_in, n_out, n_states; arma::cx_mat A, B, C, D; SSModel() = delete; SSModel(size_t n_in, size_t n_out, size_t n_states); }; SSModel ctrb_form(const TransferFn& tf); // SSModel obsv_form(const TransferFn& tf); // SSModel eigm_form(const TransferFn& tf); struct TimeSeries { size_t n_samples; double start, end, dt; arma::vec time; arma::cx_mat in, out; arma::cx_mat state; TimeSeries() = delete; TimeSeries(double start, double end, size_t n_samples); }; void response(const SSModel& ss, TimeSeries& ts); void step(const SSModel& ss, TimeSeries& ts); } #endif // CONTROL_H // vim:ts=2 sw=2 noet: