#include "teta_calc.h"
#include "params.h"
#include "pid_reg3.h"
#include "IQmathLib.h"
#include "vector.h"
#include "my_filter.h"

#define CONST_IQ_2PI  105414357 
#define PI 3.1415926535897932384626433832795

PIDREG3 pidTetta = PIDREG3_DEFAULTS;

#define MAX_Ud_Pid_Out	(167772 * 100)	//419430 ~ 0.5	//251658 ~ 0.3 //209715 ~ 0.25	//167772   ~ 0.2Hz	//100663	//0.12Hz
// 184549 ~ 2.2

#define MAX_Ud_Pid_Out_Id  176160   //0.2 ~ 167772 //0.21 ~ 176160
									//0.15 ~ 125829
#define BPSI_START 0.17	//0.15

void init_tetta_pid()
{
    pidTetta.Ref = 0;
	pidTetta.Fdb = 0;
    pidTetta.Kp = _IQ(0.1);	//_IQ(0.15);
    pidTetta.Ki = _IQ(0.0003);	//_IQ(0.00003)
	pidTetta.Kc = _IQ(0.5);
    pidTetta.OutMax = MAX_Ud_Pid_Out;
    pidTetta.OutMin = -MAX_Ud_Pid_Out;
	pidTetta.Up = 0;
	pidTetta.Ui = 0;
}

void reset_tetta_pid()
{
	pidTetta.Up = 0;
	pidTetta.Up1 = 0;
	pidTetta.Ui = 0;
	pidTetta.Out = 0;
}


//#pragma CODE_SECTION(calc_tetta,".fast_run");
void calc_tetta(_iq Frot, int direction, _iq Ud, int direct_zadan, _iq *tetta_out, _iq *Fsl_out, _iq *Fstator_out, int mode, int reset) //
{
    static _iq tetta = 0, Fsl_start = 0, bpsi_start = _IQ(BPSI_START / NORMA_FROTOR);// , bpsi_start_on_go = _IQ(0.1 / NORMA_FROTOR);
    static _iq hz_to_angle = _IQ(2.0 * PI * NORMA_FROTOR / FREQ_PWM / 2.0);
	static int flag_start = 0;	
	static int koeff_zad_int = 30; //1000;
	static long stop_frot = 27962;	//2 rpm	// 10000;
//	static _iq prev_Fsl = 0;
	static int flag_reverse = 0;
//	static int flag_out_of_reverse = 0;
	static int prev_direction = 0;
	static _iq koeffKpRmp = _IQ(0.0003750);
	static _iq koeffKiRmp = _IQ(0.00005);
	static _iq lowSpeedKp = _IQ(0.1);
	static _iq lowSpeedKi = _IQ(0.0003);
	static _iq highSpeedKp = _IQ(0.01);
	static _iq highSpeedKi = _IQ(0.011);	//_IQ(0.02);

    _iq Fstat, Fsl;
    int reverse_Ud = 1;

	if(reset == 1)
	{
		flag_start = 1;  //Won`t work, if machine will stop without changing mode
		Fsl_start = 0;
		flag_reverse = 0;
//		flag_out_of_reverse = 0;
	}
	if (_IQabs(Frot) < 768955) {	//55 rpm
		pidTetta.Kp = zad_intensiv_q(koeffKpRmp, koeffKpRmp, pidTetta.Kp, lowSpeedKp);
		pidTetta.Ki = zad_intensiv_q(koeffKiRmp, koeffKiRmp, pidTetta.Ki, lowSpeedKi);
	}
	else if ((_IQabs(Frot) < 1118481)) {	//80 rpm
		pidTetta.Kp = zad_intensiv_q(koeffKpRmp, koeffKpRmp, pidTetta.Kp, highSpeedKp);
		pidTetta.Ki = zad_intensiv_q(koeffKiRmp, koeffKiRmp, pidTetta.Ki, highSpeedKi);
	}
	//прюмое направление direction == 1
	//direction == 0 - двигатель стоит
//    if(((Frot >= 0) && (direct_zadan == 1) && (direction >= 0)) ||
//    	((direct_zadan == -1) && (direction >= 0) && (Frot >= stop_frot)))
	//27962 ~ 2 rpm
//	if(((direct_zadan == 1) && (direction == 0)) || (direction > 0))
//	{
//        Ud = -Ud;
//    }


	if(Frot >= 27962) {
		reverse_Ud = -1;
		flag_reverse = (Frot >= 27962 && direct_zadan == -1) ? 1 : 0;
		prev_direction = 1;
	}
	else if (Frot <= -27962) {
		reverse_Ud = 1;
		flag_reverse = (Frot <= -27962 && direct_zadan == 1) ? 1 : 0;
		prev_direction = -1;
	}
	if(_IQabs(Frot) < 27962) {
		if (flag_reverse == 1) {
			if (prev_direction == 1) {
				reverse_Ud = -1;
			} else {
				reverse_Ud = 1;
			}
		} else
//			if (flag_start)
		{
			if (direct_zadan == 1) {
				reverse_Ud = -1;
			} else {
				reverse_Ud = 1;
			}
		}
	}
	Ud = Ud * reverse_Ud;

	pidTetta.Ref = Ud * 100;		//Ref -заданое
    pidTetta.calc(&pidTetta);
   	Fsl = pidTetta.Out / 100;

	if(flag_start)	//
    {
        if(_IQabs(Frot) < stop_frot)
        {
			Fsl_start = bpsi_start * direct_zadan; //Если двигатель стоит, прибавл-ем скольжение.
        }
        else
        {
        	if(Fsl_start == 0)
        	{
				Fsl_start = bpsi_start * direct_zadan;	//direction;
        	}
        	flag_start = 0;
        }

    }
	else
	{
		//Когда переходим через ноль, нужно добавить скольжение, т.к. регуляторы сами не поддерживают правильное состояние.
		if(_IQabs(Frot) < (stop_frot))
		{
//			if((direct_zadan == 1) && (Fsl + Fsl_start < bpsi_start))
//			{
//				Fsl_start += (koeff_zad_int << 2);
////				Fsl_start += koeff_zad_int;
//			}
//			if((direct_zadan == -1) && (Fsl + Fsl_start > -bpsi_start))
//			{
//				Fsl_start -= (koeff_zad_int << 2);
////				Fsl_start -= koeff_zad_int;
//			}
		}
		else
		{
			if(_IQabs(Fsl_start) > koeff_zad_int)
			{
				if(Fsl_start > 0)
				{
					Fsl_start -= koeff_zad_int;
				}
				if(Fsl_start < 0)
				{
					Fsl_start += koeff_zad_int;
				}
			}
			else
			{
				Fsl_start = 0;
			}
		}

	}
	Fsl += Fsl_start;
    Fstat = Frot * POLUS + Fsl;
	tetta += _IQmpy(Fstat, hz_to_angle);


	if (tetta > CONST_IQ_2PI)
	{
		tetta -= CONST_IQ_2PI;
	}
	
	if (tetta < 0)
	{
		tetta += CONST_IQ_2PI;
	}
	*tetta_out = tetta;
	*Fsl_out = Fsl;
//	prev_Fsl = Fsl;
	*Fstator_out = Fstat;


}

TETTA_CALC tetta_calc = TETTA_CALC_DEF;

void init_tetta_calc_struct()
{
    tetta_calc.Imds = 0;
    tetta_calc.tetta = 0;
    tetta_calc.k_r = _IQ(0.015);
    tetta_calc.k_t = _IQ(0.0045);	//_IQ(0.0045);
    tetta_calc.hz_to_angle = _IQ(2.0 * PI * NORMA_FROTOR / FREQ_PWM / 2.);
}

void calc_tetta_Id(_iq Frot, _iq Id, _iq Iq, _iq *tetta_out, _iq *Fsl_out, _iq *Fstator_out, int reset) {

    _iq Fsl, Fst;
    if (reset) {
        tetta_calc.Imds = 0;
    }

    tetta_calc.Imds = tetta_calc.Imds + _IQmpy(tetta_calc.k_r, (Id - tetta_calc.Imds));
    Fsl = _IQmpy(tetta_calc.k_t, Iq);
    if (tetta_calc.Imds != 0) {
        Fsl = _IQdiv(Fsl, tetta_calc.Imds);
    } else {
        Fsl = 0;
    }
    // Fsl = _IQ(0.2 / NORMA_FROTOR);
    if (Fsl > MAX_Ud_Pid_Out_Id) { Fsl = MAX_Ud_Pid_Out_Id;}
    if (Fsl < -MAX_Ud_Pid_Out_Id) { Fsl = -MAX_Ud_Pid_Out_Id;}

    Fst = Frot * POLUS + Fsl;
    tetta_calc.tetta += _IQmpy(Fst, tetta_calc.hz_to_angle);

    if (tetta_calc.tetta > CONST_IQ_2PI)
    {
        tetta_calc.tetta -= CONST_IQ_2PI;
    }

    if (tetta_calc.tetta < 0)
    {
        tetta_calc.tetta += CONST_IQ_2PI;
    }
    *Fsl_out = Fsl;
    *tetta_out = tetta_calc.tetta;
    *Fstator_out = Fst;


}

#define LEVEL_REDUCE_UD	838860	//150V

void correct_tetta_calc_Kt(void) {
	static _iq coeff_add_Kt = _IQ(0.00005);
	static _iq max_Kt = _IQ(0.0069);
	static _iq min_Kt = _IQ(0.0029);

	if (tetta_calc.Imds  > LEVEL_REDUCE_UD) {
		tetta_calc.k_t -= coeff_add_Kt;
	}
	if (tetta_calc.Imds < -LEVEL_REDUCE_UD) {
		tetta_calc.k_t += coeff_add_Kt;
	}
	if (tetta_calc.k_t > max_Kt) {tetta_calc.k_t = max_Kt; }
	if (tetta_calc.k_t < min_Kt) {tetta_calc.k_t = min_Kt; }
}


