#include "app/nv_storage.h"
#include "math/fast_math.h"
#include "PMSM_FOC_Core.h"
#include "smo_observer.h"

#define USE_ARCTAN 0
static smo_observer_t smo;
static void smo_observer(float uAlpha, float uBeta, float iAlpha, float iBeta);
#ifdef USE_ARCTAN
static void smo_arctan(void);
#else
static void smo_pll(void);
#endif
void smo_observer_init(float pll_bandwith, float lpf_wc, float Ksmo, float Ksta) {
	smo.ts = CONFIG_SENSORLESS_TS;
	smo.bandwith = pll_bandwith;
	smo.pll_kp = pll_bandwith * 2;
	smo.pll_ki = SQ(pll_bandwith);
	smo.pll_max_rad_pers = CONFIG_MAX_MOT_RPM/30.0f * M_PI * nv_get_motor_params()->poles;
	smo.lpf_wc = lpf_wc;
	smo.lpf_ceof = (lpf_wc*smo.ts);
	smo.Ksmo = Ksmo;
	smo.Ksta = Ksta;
	smo.motor_r = nv_get_motor_params()->r;
	smo.motor_ld = nv_get_motor_params()->ld;
	smo.motor_lq = nv_get_motor_params()->lq;
	smo.motor_poles = nv_get_motor_params()->poles;
	smo.dir_ccw = true;
	PLL_Reset(&smo.pll, 0);
	smo.pll.DT = smo.ts;
	smo.pll.kp = pll_bandwith * 2;
	smo.pll.ki = 0.25f * SQ(smo.pll.kp);
}	

float smo_observer_update(float uAlpha, float uBeta, float iAlpha, float iBeta) {
	smo_observer(uAlpha, uBeta, iAlpha, iBeta);
#ifdef USE_ARCTAN
	smo_arctan();
#else
	smo_pll();
#endif
	return pi_2_degree(smo.est_angle_out);
}

smo_observer_t *get_smo(void) {
	return &smo;
}

static __INLINE float line_func(float err, float max, float slide) {
	float err_abs = ABS(err);

	if (err_abs > max) {
		return (err>0)?slide:-slide;
	}else {
		return (err * slide)/max;
	}
}

static void smo_observer(float uAlpha, float uBeta, float iAlpha, float iBeta) {
	float est_ab = smo.est_rad_pers_filted * (smo.motor_ld - smo.motor_lq);

	/* est alpha back emf */
	float Ialpha_hat = smo.Ialpha_hat;
	float calc_alpha = (uAlpha - smo.Ialpha_hat*smo.motor_r - smo.est_eAlpha - est_ab * smo.IBeta_hat) / smo.motor_ld ;
	smo.Ialpha_hat += calc_alpha * smo.ts; //积分

	float err_iAlpha = smo.Ialpha_hat - iAlpha;
	
	smo.est_eAlpha = line_func(err_iAlpha, smo.Ksta, smo.Ksmo);//fclamp(err_iAlpha, -smo.Ksta, smo.Ksta) * smo.Ksmo;
#ifdef USE_ARCTAN
	smo.est_eAlpha_Filted = do_lpf(smo.est_eAlpha_Filted, smo.est_eAlpha, smo.lpf_ceof);
#else
	smo.est_eAlpha_Filted = smo.est_eAlpha;
#endif
	/* est beta back emf */
	float calc_beta = (uBeta - smo.IBeta_hat*smo.motor_r - smo.est_eBeta + est_ab * Ialpha_hat) / smo.motor_ld;
	smo.IBeta_hat += calc_beta * smo.ts; //积分
	
	float err_iBeta = smo.IBeta_hat - iBeta;
	
	smo.est_eBeta = line_func(err_iBeta, smo.Ksta, smo.Ksmo);//fclamp(err_iBeta, -smo.Ksta, smo.Ksta) * smo.Ksmo;
#ifdef USE_ARCTAN
	smo.est_eBeta_Filted = do_lpf(smo.est_eBeta_Filted, smo.est_eBeta, smo.lpf_ceof);
#else
	smo.est_eBeta_Filted = smo.est_eBeta;
#endif
}
#define angle_clamp(a) {while (a >= M_PI*2) a-=M_PI*2;while (a < 0) a +=M_PI*2;};
#ifdef USE_ARCTAN
static void smo_arctan(void) {
	float ealpha_in = -smo.est_eAlpha_Filted;
	float ebeta_in  =  smo.est_eBeta_Filted;

	float angle = fast_atan_2(ealpha_in, ebeta_in); //通过反正切获取电角度
	UTILS_NAN_ZERO(angle);
	angle_clamp(angle);
	float prev_angle = smo.est_angle;
	float comp_angle = 0.0f;
	if (smo.dir_ccw) {
		if ((prev_angle > angle) && (prev_angle > M_PI && angle < M_PI)) {//wrapper
			comp_angle = 2 * M_PI;
		}
	}else {
		if ((prev_angle < angle) && (prev_angle < M_PI && angle > M_PI)) {//wrapper
			comp_angle = -2 * M_PI;
		}
	}
	smo.est_angle = angle;
	smo.est_rad_pers = PLL_run(&smo.pll, angle, comp_angle);
	if (smo.est_rad_pers > smo.pll_max_rad_pers) {
		smo.est_rad_pers = smo.pll_max_rad_pers;
		smo.pll.out = smo.est_rad_pers;
	}
	smo.est_rad_pers_filted = smo.est_rad_pers;
	/*低通滤波有相位滞后，需要补偿，同时电流和电压滞后一个控制周期，需要通过当前的电角速度对计算的角度进行补偿 */
	smo.est_angle_out = smo.est_angle + fast_atan_2(smo.est_rad_pers_filted, smo.lpf_wc) + smo.est_rad_pers_filted * smo.ts;
	angle_clamp(smo.est_angle_out);
	smo.est_rpm = (30.0f * smo.est_rad_pers_filted/M_PI/smo.motor_poles);
	if (smo.est_rpm > CONFIG_MAX_MOT_RPM) {
		smo.est_rpm = CONFIG_MAX_MOT_RPM;
	}else if (smo.est_rpm < 0) {
		smo.est_rpm = 0;
	}
}
#else
static void smo_pll(void) {
	float eab_sqr = sqrtf(SQ(smo.est_eAlpha_Filted) + SQ(smo.est_eBeta_Filted) + (1e-10f));
	float ealpha_in = -smo.est_eAlpha_Filted/eab_sqr;
	float ebeta_in  =  smo.est_eBeta_Filted/eab_sqr;
	float sin, cos;
	float angle_rad = pi_2_degree(smo.est_angle);
	
	arm_sin_cos_f32(angle_rad, &sin, &cos);
	float pi_err = cos * ealpha_in - sin * ebeta_in;
	float perr = pi_err * smo.pll_kp;
	if (smo.pll_integrator < smo.pll_max_rad_pers) {
		smo.pll_integrator += smo.ts * pi_err * smo.pll_ki; //更新pll的pi的积分xiang
	}
	smo.est_rad_pers = perr + smo.pll_integrator; //计算角速度
	smo.est_angle += smo.ts * smo.est_rad_pers; //角速度积分
	
	smo.est_rad_pers_filted = do_lpf(smo.est_rad_pers_filted, smo.est_rad_pers, smo.lpf_ceof); //对速度低通滤波
	angle_clamp(smo.est_angle);
	smo.est_rpm = (30.0f * smo.est_rad_pers_filted/M_PI/smo.motor_poles);
	if (smo.est_rpm > CONFIG_MAX_MOT_RPM) {
		smo.est_rpm = CONFIG_MAX_MOT_RPM;
	}else if (smo.est_rpm < 0) {
		smo.est_rpm = 0;
	}
	/* 电流和电压滞后一个控制周期，需要通过当前的电角速度对计算的角度进行补偿 */
	smo.est_angle_out = smo.est_angle + smo.est_rad_pers_filted * smo.ts;
	angle_clamp(smo.est_angle_out);
}
#endif

float smo_observer_angle(void) {
	return pi_2_degree(smo.est_angle_out);
}

//机械角度 rpm
float smo_observer_vel(void) {
	return smo.est_rpm;
}

