//******************************************************************************
//
//		IPID.cpp - differential PID equation
//		Ivo Carvalho 29/4/2011
//
//******************************************************************************


#include "IPID.h"

//OBJECTLOADREGISTER(IPID,"$Id: IPID.cpp,v 1.0 29/4/2011 14:22:36 ivoc Exp $")
// if cycle time is supplied
IPID::IPID(float set_Kp_constant, float set_Ki_constant, float set_Kd_constant, float set_T_constant, float set_upper_limit, float set_lower_limit){
	
	this->Kp_constant = set_Kp_constant;
	this->Ki_constant = set_Ki_constant;
	this->Kd_constant = set_Kd_constant;
	this->T_constant = set_T_constant;
	this->P_realtime_constant = this->Kp_constant;
	this->I_realtime_constant = this->Ki_constant * this->T_constant;
	this->D_realtime_constant = this->Kd_constant / this->T_constant;
	this->upper_limit = set_upper_limit;
	this->lower_limit = set_lower_limit;
	this->old_output = 0;
	this->old_PV = 0;
	this->old_old_PV = 0;
	this->old_error = 0;
	this->old_old_error = 0;
}
// create without cycle time, just with the constants used in realtime
IPID::IPID(float set_P_realtime_constant, float set_I_realtime_constant, float set_D_realtime_constant, float set_upper_limit, float set_lower_limit){
	
	this->P_realtime_constant = set_P_realtime_constant;
	this->I_realtime_constant = set_I_realtime_constant;
	this->D_realtime_constant = set_D_realtime_constant;
	this->T_constant = 0;	//undefined
	this->Kp_constant = 0;
	this->Ki_constant = 0;
	this->Kd_constant = 0;
	this->upper_limit = set_upper_limit;
	this->lower_limit = set_lower_limit;
	this->old_output = 0;
	this->old_PV = 0;
	this->old_old_PV = 0;
	this->old_error = 0;
	this->old_old_error = 0;
}

// ********* Destructor ********************************************
IPID::~IPID(){
	
}

bool IPID::LoadOldOutputWithinLimits(float old_output_to_load){
	
	if (old_output_to_load > upper_limit) old_output_to_load = upper_limit;
	if (old_output_to_load < lower_limit) old_output_to_load = lower_limit;
	this->old_output = old_output_to_load;
	this->old_PV = 0;
	this->old_old_PV = 0;
	this->old_error = 0;
	this->old_old_error = 0;
	return True;
}

bool IPID::SetPIDConstants(float set_Kp_constant, float set_Ki_constant, float set_Kd_constant, float set_T_constant){
	
	this->Kp_constant = set_Kp_constant;
	this->Ki_constant = set_Ki_constant;
	this->Kd_constant = set_Kd_constant;
	this->T_constant = set_T_constant;
	this->P_realtime_constant = this->Kp_constant;
	this->I_realtime_constant = this->Ki_constant * this->T_constant;
	this->D_realtime_constant = this->Kd_constant / this->T_constant;
	return True;
}

bool IPID::SetRealtimePIDConstants(float set_P_realtime_constant, float set_I_realtime_constant, float set_D_realtime_constant){
	
	this->P_realtime_constant = set_P_realtime_constant;
	this->I_realtime_constant = set_I_realtime_constant;
	this->D_realtime_constant = set_D_realtime_constant;
	if (this->T_constant > 0){
		this->Kp_constant = this->P_realtime_constant;
		this->Ki_constant = this->I_realtime_constant / this->T_constant;
		this->Kd_constant = this->D_realtime_constant * this->T_constant;
	}
	return True;
}

bool IPID::SetLimits(float set_upper_limit, float set_lower_limit){

	this->upper_limit = set_upper_limit;
	this->lower_limit = set_lower_limit;
	return True;
}

float IPID::CalculatePID(float process_variable, float setpoint){
	this->error = setpoint - process_variable;
	
	this->old_output = this->old_output - this->P_realtime_constant * (process_variable - this->old_PV) + this->I_realtime_constant * this->error - this->D_realtime_constant * (process_variable - 2 * this->old_PV + process_variable - this->old_old_PV);
	
	this->old_old_PV = this->old_PV;
	this->old_PV = process_variable;

	if(this->old_output > this->upper_limit) this->old_output = this->upper_limit;
	if(this->old_output < this->lower_limit) this->old_output = this->lower_limit;
	
	return this->old_output;
}

float IPID::CalculatePI(float process_variable, float setpoint){
	this->error = setpoint - process_variable;
	
	this->old_output = this->old_output - this->P_realtime_constant * (process_variable - this->old_PV) + this->I_realtime_constant * this->error;
	
	this->old_old_PV = this->old_PV;
	this->old_PV = process_variable;

	if(this->old_output > this->upper_limit) this->old_output = this->upper_limit;
	if(this->old_output < this->lower_limit) this->old_output = this->lower_limit;
	
	return this->old_output;
}

float IPID::CalculateP(float process_variable, float setpoint){
	this->error = setpoint - process_variable;
	
	this->old_output = this->old_output - this->P_realtime_constant * (process_variable - this->old_PV);
	
	this->old_old_PV = this->old_PV;
	this->old_PV = process_variable;

	if(this->old_output > this->upper_limit) this->old_output = this->upper_limit;
	if(this->old_output < this->lower_limit) this->old_output = this->lower_limit;
	
	return this->old_output;
}

float IPID::CalculatePID_types(float process_variable, float setpoint, float type){
	this->error = setpoint - process_variable;
		
	if(type==1)//Type A
		this->old_output = this->old_output + this->Kp_constant*1000 * (this->error - this->old_error) + this->Ki_constant*1000 * this->error + this->Kd_constant*1000 * (this->error - 2 * this->old_error + this->old_old_error);
	if(type==2)//Type B
		this->old_output = this->old_output + this->Kp_constant*1000 * (this->error - this->old_error) + this->Ki_constant*1000 * this->error - this->Kd_constant*1000 * (process_variable - 2 * this->old_PV + this->old_old_PV);
	if(type==3)//Type C
		this->old_output = this->old_output - this->Kp_constant*1000 * (process_variable - this->old_PV) + this->Ki_constant*1000 * this->error - this->Kd_constant*1000 * (process_variable - 2 * this->old_PV + this->old_old_PV);
	
	this->old_old_PV = this->old_PV;
	this->old_PV = process_variable;
	this->old_old_error = this->old_error;
	this->old_error = this->error;

	//if(this->old_output > this->upper_limit) this->old_output = this->upper_limit;
	//if(this->old_output < this->lower_limit) this->old_output = this->lower_limit;
	
	if(this->old_output > this->upper_limit) return this->upper_limit;
	if(this->old_output < this->lower_limit) return this->lower_limit;
	
	return this->old_output;
}

float IPID::ReturnErrorInPercentage(float process_variable, float setpoint){
	this->error = setpoint - process_variable;
	
	if (this->error < 0) this->error = 0 - this->error;
	
	return ((100 * error)/(this->upper_limit - this->lower_limit)) ;
}
