{ public: PID(double kp, double ki, double kd, double uMin, double uMax) : kp_{kp}, ki_{ki}, kd_{kd}, uMin_{uMin}, uMax_{uMax} {} double calcular(double ref, double y, double dt ) { double e = ref - y; integral_ += e * dt; double d = (e - ePrev_) / dt; ePrev_ = e; double u = kp_*e + ki_*integral_ + kd_*d; if (u > uMax_ || u < uMin_) integral_ -= e * dt; // anti-windup return std::clamp(u, uMin_, uMax_); } private: double kp_, ki_, kd_, uMin_, uMax_; double integral_ = 0.0, ePrev_ = 0.0; }; Validación: error en régimen permanente, sobreimpulso y tiempo de establecimiento. Fundamentos de Programación con C++ // Modelo: A dh/dt = Qin - Cd a sqrt(2 g h) class ModeloTanque { public: ModeloTanque(double A, double a, double cd) : A_{A}, a_{a}, cd_{cd} {} double paso(double qIn, double dt) { // Euler double qOut = cd_*a_*std::sqrt(2*9.81* h_); h_ = std::max(0.0, h_ + dt*(qIn - qOut )/A_); return h_; } private: double A_, a_, cd_, h_ = 0.0; }; int main() { ModeloTanque tanque{1.0, 0.01, 0.62}; PID pid{2.0, 0.5, 0.1, 0.0, 0.05}; LogCSV log{"simulacion.csv"}; const double ref = 1.2, dt = 0.1; // [m], [s ] double h = 0.0; for (int k = 0; k < 3000; ++k) { double q = pid.calcular(ref, h, dt); h = tanque.paso(q, dt); log.escribir({h, {}, "m"}); } } Abraham Zamudio Chauca 31 / 34