/* ** ****************************************************************************** * @file : MESChfi.c * @brief : HFI rotor position ****************************************************************************** * @attention * *

© Copyright (c) 2020 David Molony. * All rights reserved.

* * This software component is licensed under BSD 3-Clause license, * the "License"; You may not use this file except in compliance with the * License. You may obtain a copy of the License at: * opensource.org/licenses/BSD-3-Clause * ****************************************************************************** *In addition to the usual 3 BSD clauses, it is explicitly noted that you *do NOT have the right to take sections of this code for other projects *without attribution and credit to the source. Specifically, if you copy into *copyleft licenced code without attribution and retention of the permissive BSD *3 clause licence, you grant a perpetual licence to do the same regarding turning sections of your code *permissive, and lose any rights to use of this code previously granted or assumed. * *This code is intended to remain permissively licensed wherever it goes, *maintaining the freedom to distribute compiled binaries WITHOUT a requirement to supply source. * *This is to ensure this code can at any point be used commercially, on products that may require *such restriction to meet regulatory requirements, or to avoid damage to hardware, or to ensure *warranties can reasonably be honoured. ****************************************************************************** */ #include #include "MESChfi.h" static MESCiq_s Idq[2] = {{.d = 0.0f, .q = 0.0f}, {.d = 0.0f, .q = 0.0f}}; static volatile MESCiq_s dIdq = {.d = 0.0f, .q = 0.0f}; static volatile float magnitude45; static MESCiq_s intdidq; void MESChfi_Toggle(MESC_motor_typedef *_motor){ if(((_motor->FOC.Vdq.q-_motor->FOC.Idq_smoothed.q*_motor->m.R) > _motor->HFI.toggle_voltage) ||((_motor->FOC.Vdq.q-_motor->FOC.Idq_smoothed.q*_motor->m.R) < -_motor->HFI.toggle_voltage) ||(_motor->MotorSensorMode==MOTOR_SENSOR_MODE_HALL) ||((fabsf(_motor->FOC.eHz)>_motor->HFI.toggle_eHz))){ _motor->HFI.inject = 0; // _motor->FOC.Current_bandwidth = CURRENT_BANDWIDTH; } else if(((_motor->FOC.Vdq.q-_motor->FOC.Idq_smoothed.q*_motor->m.R) < (_motor->HFI.toggle_voltage-1.0f))//HFI hysteresis voltage hard coded as 1.0V &&((_motor->FOC.Vdq.q-_motor->FOC.Idq_smoothed.q*_motor->m.R) > -(_motor->HFI.toggle_voltage-1.0f)) &&(_motor->HFI.Type !=HFI_TYPE_NONE)){ _motor->HFI.int_err = _motor->FOC.PLL_int; _motor->HFI.inject = 1; // _motor->FOC.Current_bandwidth = CURRENT_BANDWIDTH*0.1f; } } void MESChfi_Run(MESC_motor_typedef *_motor){ if ((_motor->HFI.inject)&&(_motor->MotorState != MOTOR_STATE_TRACKING)) { int Idqreq_dir=0; if (_motor->HFI.inject_high_low_now == 0){//First we create the toggle _motor->HFI.inject_high_low_now = 1; Idq[0].d = _motor->FOC.Idq.d; Idq[0].q = _motor->FOC.Idq.q; }else{ _motor->HFI.inject_high_low_now = 0; Idq[1].d = _motor->FOC.Idq.d; Idq[1].q = _motor->FOC.Idq.q; } _motor->FOC.didq.d = (Idq[0].d - Idq[1].d); //Calculate the changing current levels _motor->FOC.didq.q = (Idq[0].q - Idq[1].q); switch(_motor->HFI.Type){ case HFI_TYPE_NONE: __NOP(); break; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// case HFI_TYPE_45: if(_motor->HFI.inject_high_low_now ==1){ _motor->HFI.Vd_injectionV = +_motor->meas.hfi_voltage; if(_motor->FOC.Idq_req.q>0.0f){ Idqreq_dir = 1; _motor->HFI.Vq_injectionV = +_motor->meas.hfi_voltage; }else{ _motor->HFI.Vq_injectionV = -_motor->meas.hfi_voltage; Idqreq_dir = -1; } }else{ _motor->HFI.Vd_injectionV = -_motor->meas.hfi_voltage; if(_motor->FOC.Idq_req.q>0.0f){ _motor->HFI.Vq_injectionV = -_motor->meas.hfi_voltage; }else{ _motor->HFI.Vq_injectionV = +_motor->meas.hfi_voltage; } } //Run the PLL magnitude45 = sqrtf(_motor->FOC.didq.d*_motor->FOC.didq.d+_motor->FOC.didq.q*_motor->FOC.didq.q); if(_motor->FOC.was_last_tracking==0){ float error; //Estimate the angle error, the gain to be determined in the HFI detection and setup based on the HFI current and the max iteration allowable error = _motor->HFI.Gain*(magnitude45-_motor->HFI.mod_didq); if(error>500.0f){error = 500.0f;} if(error<-500.0f){error = -500.0f;} _motor->HFI.int_err = _motor->HFI.int_err +0.05f*error; if(_motor->HFI.int_err>1000.0f){_motor->HFI.int_err = 1000.0f;} if(_motor->HFI.int_err<-1000.0f){_motor->HFI.int_err = -1000.0f;} _motor->FOC.FOCAngle = _motor->FOC.FOCAngle + (int)(error + _motor->HFI.int_err)*Idqreq_dir; }else{ _motor->FOC.FOCAngle += _motor->HFI.test_increment; _motor->HFI.accu += magnitude45; _motor->HFI.count += 1; } #if 0 //Sometimes for investigation we want to just lock the angle, this is an easy bodge _motor->FOC.FOCAngle = 62000; #endif break; ///////////////////////////////////////////////////////////////////////////////////////////////////////////// case HFI_TYPE_D: if(_motor->HFI.inject_high_low_now ==1){ _motor->HFI.Vd_injectionV = +_motor->meas.hfi_voltage; }else{ _motor->HFI.Vd_injectionV = -_motor->meas.hfi_voltage; } if(_motor->FOC.didq.q>1.0f){_motor->FOC.didq.q = 1.0f;} if(_motor->FOC.didq.q<-1.0f){_motor->FOC.didq.q = -1.0f;} intdidq.q = (intdidq.q + 0.1f*_motor->FOC.didq.q); if(intdidq.q>10){intdidq.q=10;} if(intdidq.q<-10){intdidq.q=-10;} _motor->FOC.FOCAngle += (int)(250.0f*_motor->FOC.IIR[1] + 10.50f*intdidq.q)*_motor->FOC.d_polarity; break; case HFI_TYPE_SPECIAL: __NOP(); if(_motor->HFI.inject_high_low_now ==1){ _motor->HFI.Vd_injectionV = _motor->HFI.special_injectionVd; _motor->HFI.Vq_injectionV = _motor->HFI.special_injectionVq; }else{ _motor->HFI.Vd_injectionV = -_motor->HFI.special_injectionVd; _motor->HFI.Vq_injectionV = -_motor->HFI.special_injectionVq; } break; } }else { _motor->HFI.Vd_injectionV = 0.0f; _motor->HFI.Vq_injectionV = 0.0f; } } void MESChfi_Slow(MESC_motor_typedef *_motor){ /////////////Set and reset the HFI//////////////////////// switch(_motor->HFI.Type){ case HFI_TYPE_45: MESChfi_Toggle(_motor); if(_motor->HFI.inject==1){ //static int no_q; if(_motor->FOC.was_last_tracking==1){ if(_motor->HFI.countdown>1){ _motor->HFI.mod_didq = _motor->HFI.accu / _motor->HFI.count; _motor->HFI.Gain = 5000.0f/_motor->HFI.mod_didq; _motor->FOC.was_last_tracking = 0; }else{ _motor->HFI.test_increment = 65536 * SLOW_LOOP_FREQUENCY / _motor->FOC.pwm_frequency; _motor->HFI.countdown++; } }else{ _motor->HFI.countdown = 0; _motor->HFI.count = 0; _motor->HFI.accu = 0.0f; } } break; case HFI_TYPE_D: MESChfi_Toggle(_motor); if(_motor->HFI.inject==1){ if(_motor->HFI.countdown==3){ _motor->FOC.Idq_req.d = HFI_TEST_CURRENT; _motor->FOC.Idq_req.q=0.0f;//Override the inputs to set Q current to zero }else if(_motor->HFI.countdown==2){ _motor->FOC.Ldq_now_dboost[0] = _motor->FOC.IIR[0]; //Find the effect of d-axis current _motor->FOC.Idq_req.d = 1.0f; _motor->FOC.Idq_req.q=0.0f; }else if(_motor->HFI.countdown == 1){ _motor->FOC.Idq_req.d = -HFI_TEST_CURRENT; _motor->FOC.Idq_req.q=0.0f; }else if(_motor->HFI.countdown == 0){ _motor->FOC.Ldq_now[0] = _motor->FOC.IIR[0];//_motor->HFI.Vd_injectionV; _motor->FOC.Idq_req.d = 0.0f; if(_motor->FOC.Ldq_now[0]>_motor->FOC.Ldq_now_dboost[0]){_motor->FOC.FOCAngle+=32768;} _motor->HFI.countdown = 200; } _motor->HFI.countdown--; } break; case HFI_TYPE_NONE: _motor->HFI.inject = 0; // _motor->FOC.Current_bandwidth = CURRENT_BANDWIDTH; break; case HFI_TYPE_SPECIAL: MESChfi_Toggle(_motor); break; } }