/*
 * pid.c
 *
 *  Created on: Jan 18, 2022
 *      Author: mcfly
 */

#include "pid.h"

void PID_Init(PIDController *pid) {
	//Clear controller values
	pid->integrator = 0.0f;
	pid->prevError  = 0.0f;

	pid->differentiator  = 0.0f;
	pid->prevMeasurement = 0.0f;

	pid->out = 0.0f;
}


float PID_Update(PIDController *pid, float setpoint, float measurement) {
	// PID = Kp + Ki * 1/s + Kd * s/(s*tau+1)

	// e = error tothe setpoint
	// p[n] = Kp * e[n]
	// i[n] = Ki*T/2 * (e[n]+e[n-1]) + i[n-1]
	// d[n] = 2*Kd/(2*tau+T) * (e[n]-e[n-1]) + (2*tau-T)/(2*tau+T) * d[n-1]
	// PID = p[n]+i[n]+d[n]


	//Error signal
	float error = setpoint - measurement;

	//Proportional
	float proportional = pid->Kp * error;

	//Integral
	pid->integrator += 0.5f * pid->Ki * pid->T * (error + pid->prevError);

	//Anti-wind-up via dynamic integrator clamping
	float limMinInt, limMaxInt;

	//Compute integrator limits
	if (pid->limMax > proportional) {
		limMaxInt = pid->limMax - proportional;
	} else {
		limMaxInt = 0.0f;
	}
	if (pid->limMin < proportional) {
		limMinInt = pid->limMin - proportional;
	} else {
		limMinInt = 0.0f;
	}

	//Clamp integrator
	if (pid->integrator > limMaxInt) {
		pid->integrator = limMaxInt;
	} else if (pid->integrator < limMinInt) {
		pid->integrator = limMinInt;
	}

	//Derivative (band-limited differentiator)
	pid->differentiator = (2.0f * pid->Kd * (measurement - pid->prevMeasurement)		//Note: derivative on measurement
						+ (2.0f * pid->tau - pid->T) * pid->differentiator)
						/ (2.0f * pid->tau + pid->T);

	//Compute output and apply limits
	pid->out = proportional + pid->integrator + pid->differentiator;
	if (pid->out > pid->limMax) {
		pid->out = pid->limMax;
	} else if (pid->out < pid->limMin) {
		pid->out = pid->limMin;
	}

	//Store error and measurement for later use
	pid->prevError		 = error;
	pid->prevMeasurement = measurement;

	//Return controller output
	return pid->out;

}
