// SPDX-License-Identifier: GPL-2.0-or-later1/*2* pid.c PID controller for testing cooling devices3*4* Copyright (C) 2012 Intel Corporation. All rights reserved.5*6* Author Name Jacob Pan <[email protected]>7*/89#include <unistd.h>10#include <stdio.h>11#include <stdlib.h>12#include <string.h>13#include <stdint.h>14#include <sys/types.h>15#include <dirent.h>16#include <libintl.h>17#include <ctype.h>18#include <assert.h>19#include <time.h>20#include <limits.h>21#include <math.h>22#include <sys/stat.h>23#include <syslog.h>2425#include "tmon.h"2627/**************************************************************************28* PID (Proportional-Integral-Derivative) controller is commonly used in29* linear control system, consider the process.30* G(s) = U(s)/E(s)31* kp = proportional gain32* ki = integral gain33* kd = derivative gain34* Ts35* We use type C Alan Bradley equation which takes set point off the36* output dependency in P and D term.37*38* y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]39* - 2*x[k-1]+x[k-2])/Ts40*41*42***********************************************************************/43struct pid_params p_param;44/* cached data from previous loop */45static double xk_1, xk_2; /* input temperature x[k-#] */4647/*48* TODO: make PID parameters tuned automatically,49* 1. use CPU burn to produce open loop unit step response50* 2. calculate PID based on Ziegler-Nichols rule51*52* add a flag for tuning PID53*/54int init_thermal_controller(void)55{5657/* init pid params */58p_param.ts = ticktime;59/* TODO: get it from TUI tuning tab */60p_param.kp = .36;61p_param.ki = 5.0;62p_param.kd = 0.19;6364p_param.t_target = target_temp_user;6566return 0;67}6869void controller_reset(void)70{71/* TODO: relax control data when not over thermal limit */72syslog(LOG_DEBUG, "TC inactive, relax p-state\n");73p_param.y_k = 0.0;74xk_1 = 0.0;75xk_2 = 0.0;76set_ctrl_state(0);77}7879/* To be called at time interval Ts. Type C PID controller.80* y[k] = y[k-1] - kp*(x[k] - x[k-1]) + Ki*Ts*e[k] - Kd*(x[k]81* - 2*x[k-1]+x[k-2])/Ts82* TODO: add low pass filter for D term83*/84#define GUARD_BAND (2)85void controller_handler(const double xk, double *yk)86{87double ek;88double p_term, i_term, d_term;8990ek = p_param.t_target - xk; /* error */91if (ek >= 3.0) {92syslog(LOG_DEBUG, "PID: %3.1f Below set point %3.1f, stop\n",93xk, p_param.t_target);94controller_reset();95*yk = 0.0;96return;97}98/* compute intermediate PID terms */99p_term = -p_param.kp * (xk - xk_1);100i_term = p_param.kp * p_param.ki * p_param.ts * ek;101d_term = -p_param.kp * p_param.kd * (xk - 2 * xk_1 + xk_2) / p_param.ts;102/* compute output */103*yk += p_term + i_term + d_term;104/* update sample data */105xk_1 = xk;106xk_2 = xk_1;107108/* clamp output adjustment range */109if (*yk < -LIMIT_HIGH)110*yk = -LIMIT_HIGH;111else if (*yk > -LIMIT_LOW)112*yk = -LIMIT_LOW;113114p_param.y_k = *yk;115116set_ctrl_state(lround(fabs(p_param.y_k)));117118}119120121