This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Scalar (V/f) Control of 3-Phase Induction Motor

Other Parts Discussed in Thread: MOTORWARE, CONTROLSUITE

Hi all :)

Is there an example lab project for Scalar (V/f) Control of 3-Phase Induction Motor running on the LaunchPad  (LAUNCH-F28027F), as I checked motorware and all examples labs are for FOC ?! I am connecting the LaunchPad to my hardware but I need to run Scalar (V/f) on it ?!

  • No, there isn't.
    You need to modify this example C:\ti\controlSUITE\development_kits\HVMotorCtrl+PfcKit_v2.1\HVACI_Scalar (from F28035 into F28027).
    It is not so difficult. I have did it, but sorry, I can't share.
    Good luck!

    Best regards,
    Maria
  • you can modify the ctrl.c/.h files in InstaSPIN_foc to run an induction motor in open loop. it is helpful to have this feature actually and we have it on the list to add this example. I've got updated CTRL files but haven't documented how to instrument them exactly.
  • Could you please give me more info about the required modifications ?! Or share me with the updated CTRL files if it's possible to compare them with the current foc examples ? Any further info would help as I currently need to run V/Hz on my hardware using your MCU ?!
  • in ctrl.c you will need to

    1. add these globals
    // the globals


    bool gFlag_Vdq_Open_Loop = true;
    _iq gAngle_Open_Loop = _IQ(0.0);
    _iq gAngle_Delta_Open_Loop = _IQ(1.0/USER_CTRL_FREQ_Hz);
    MATH_vec2 gVdq_Open_Loop = {_IQ(0.0), _IQ(0.0)};

    in ctrl.h

    1. add
    extern bool gFlag_Vdq_Open_Loop;
    extern _iq gAngle_Open_Loop;
    extern _iq gAngle_Delta_Open_Loop;
    extern MATH_vec2 gVdq_Open_Loop;

    2. add this function

    inline void CTRL_incrAngle(_iq *pAngle_pu, _iq angle_delta_pu)
    {
    uint32_t angleMask = ((uint32_t)0xFFFFFFFF >> (32 - GLOBAL_Q));
    _iq angleTmp_pu;
    _iq angleComp_pu;

    // increment the angle
    angleTmp_pu = *pAngle_pu + angle_delta_pu;

    // mask the angle for wrap around
    // note: must account for the sign of the angle
    angleComp_pu = _IQabs(angleTmp_pu) & angleMask;

    // account for sign
    if(angleTmp_pu < 0)
    {
    angleComp_pu = -angleComp_pu;
    }

    *pAngle_pu = angleComp_pu;

    return;
    }

    3. in this function
    inline void CTRL_runOnLine_User(CTRL_Handle handle,
    const HAL_AdcData_t *pAdcData,HAL_PwmData_t *pPwmData)

    at:
    _iq angleComp_pu;

    // compensate angle delay

    add this if/else statement:
    if(gFlag_Vdq_Open_Loop == true)
    {
    CTRL_incrAngle(&gAngle_Open_Loop, gAngle_Delta_Open_Loop);

    // compute the sin/cos phasor
    CTRL_computePhasor(gAngle_Open_Loop,&phasor);

    CTRL_setVdq_out_pu(handle, &gVdq_Open_Loop);
    }
    else
    {
    _iq angleComp_pu;

    // compensate angle delay




    Make sure your motor is already ID'd, these changes should just be used for run-time (like proj_lab03a).

    Then add these variables to your watch window:

    gAngle_Delta_Open_Loop
    gVdq_Open_Loop.value[1]

    Right after offset and Rs recalibration, the inverter will start rotating a voltage vector at 1 Hz with no voltage. Change the desired frequency with gAngle_Delta_Open_Loop variable. The scaling is:

    Frequency of 1 Hz, gAngle_Delta_Open_Loop = _IQ(1.0 / USER_CTRL_FREQ_Hz)
    Frequency of 10 Hz, gAngle_Delta_Open_Loop = _IQ(10.0 / USER_CTRL_FREQ_Hz)
    Frequency of 100 Hz, gAngle_Delta_Open_Loop = _IQ(100.0 / USER_CTRL_FREQ_Hz)
    Frequency of 1000 Hz, gAngle_Delta_Open_Loop = _IQ(1000.0 / USER_CTRL_FREQ_Hz)

    To reverse rotation just do a negative value on gAngle_Delta_Open_Loop variable.

    To change the amplitude of the voltage, then change the value of gVdq_Open_Loop.value[1]. Maximum value here is _IQ(1.333333).
  • Thank you so much Chris.

    For the voltage amplitude (gVdq_open_loop.value) here is it the rating voltage value or the current output voltage? as the current output voltage should be determined by the V/Hz algorithm according to the desired frequency as I understand from the V/Hz control?

    Thanks.
  • what I have given you is an open loop solution, meaning you set the frequency and peak amplitude of the output waveforms. There is no other logic being performed.
  • Thanks so much Chris for your help, I'll try it on my hardware.
  • Hi Chris,

    I tested the both modes on my inverter hardware and I noticed the following points:-

    1 - The required motor speed on the closed loop is more accurate than the open loop and I know that's what it should be but on the closed loop mode the motor speed can't reach more than 24 Hz which is almost the half of my motor rated frequency (50 Hz), but when I switch to open loop it reaches it and even for 60 Hz.
    I checked the motor no of poles and the ratings of the motor.

    2 - I also noticed that the currents in the motor phases for the closed loop mode is lower than the currents in the open loop mode, I am wondering if this could affect the output torque ?!

    Thanks for help.
  • I would guess you don't have the correct motor parameters identified which is affecting closed loop FOC control, specifically the feedback from FAST.
  • When I run it on closed loop, I made motor identification enabled and it passes identification without errors?!
  • "Motor Identified" without errors does NOT mean that the parameters are correct.  There is limited error reporting during the ID process. It only fails in the case of a gross error, usually with the flux measurement. 

    what are the USER_MOTOR values that you used after ID?

  • Rr_Ohm 9.078
    Rs_Ohm 16.7
    Lsd_H 0.002
    Lsq_H 0.002
    Flux_VpHz 3.075
    MagnCurr_A 0.336


    USER_MOTOR_RATED_FLUX (0.8165*220.0/60.0)
    USER_MOTOR_MAX_CURRENT (1.2)
    USER_MOTOR_RES_EST_CURRENT (0.2*USER_MOTOR_MAX_CURRENT)
    USER_MOTOR_FLUX_EST_FREQ_Hz (5.0)
  • Hmmm.

    It's hard to say, but the magnetizing current seems very low for this motor.  The MAX_CURRENT also seems quite low. Recall that the MAX_CURRENT is not the maximum continuous current, it is the peak current command from the speed controller. MAX_CURRENT needs to be much larger than your maximum continuous current.

    If you aren't hitting your rated speed both of these could be the issue.

    Magnetizing current being low means you aren't creating enough flux to create more torque.

    Max_Current being low limits the output command of the speed controller, limiting the Iq_Ref torque command.

  • In closed loop, I increased the magnetizing current to 50% of the maximum current as I think it should be between (33 to 60%) according to the motor characteristics, and that increased the torque with almost same torque as in open loop mode.  

    But still in closed loop the output motor frequency can't reach more that 24Hz but I can reach 60Hz (motor rating Hz) only in open loop mode.

  • there must still be a problem with either the motor parameters (likely Ls) or the MAX_MOTOR_CURRENT and MAGNETIZING_CURRENT

    Enabling PowerWarp will reduce the magnetizing current and should let you reach the 60 Hz w/o load. This will at least tell you if there is some other issue. But the torque will be reduced and will slow down under load to the same ~24 Hz.
  • I got some notices may help with understanding why I can't reach more than 24 Hz in closed loop but can reach 60 Hz on open loop:-

    - The speed for closed loop is accurate only on one direction up to 24Hz but the motor almost doesn't rotate on the reverse direction.
    - When I increase the DC bus voltage the speed reaches more than 24 Hz but my IGBT module is limited to 400V and the star connection for my motor is rated for 480V on 60 Hz.
  • if the motor doesn't run in reverse the first thing to check is the compiler version you are using. There is a nasty bug in compilers 6.2.0 to 6.2.2 which manifests itself in this way. Update your compiler.
  • Dear ChrisClearman,

    I'm also trying to test my motor control kit by V/f scalar control before using InstaSPIN with full vector control. I must to take this step in order to check my own hardware circuit and the signal conditioning circuit for current sensors and voltage sensors.

    I followed your solution, but based on the code frame of Lab11, by using directly the function CTRL_incrAngle() in the main_ISR() code as:

    //! mainISR() function
    interrupt void mainISR(void)
    {
    	// Declaration of local variables
    	_iq 		angle_pu;					//The angle of space vector
    	MATH_vec2 	Vab_pu;
    	MATH_vec2 	phasor;
    	uint32_t 	timer1Cnt;
    
      // ------------------------------- FRAMEWORK ----------------------------------------
      // read the timer 1 value and update the CPU usage module
      timer1Cnt = HAL_readTimerCnt(halHandle,1);
      CPU_USAGE_updateCnts(cpu_usageHandle,timer1Cnt);
    
      // acknowledge the ADC interrupt
      HAL_acqAdcInt(halHandle,ADC_IntNumber_1);
    
    // =============================== LEVEL 1 ======================================
    //	  Checks target independent modules, duty cycle waveforms and PWM update
    //	  Keep the motors disconnected at this level!
    // ==============================================================================
    #if (BUILDLEVEL==LEVEL1)
      gFlag_Vdq_Open_Loop = true;
    
      if(gFlag_Vdq_Open_Loop == true)
      {
     	 CTRL_incrAngle(&gAngle_Open_Loop, gAngle_Delta_Open_Loop);
    
     	// get an electrical angle for testing in BUILD_LEVEL_1 from the CTRL module
     	 angle_pu = gAngle_Open_Loop;
      }
    
      // Set the amplitude of the voltage.
      // Notice that, by changing the value of gVdq_Open_Loop.value[1] we will change
      // the amplitude of the voltage vector. The maximum value here is _IQ(1.333333).
      gVdq_out_pu.value[0] = _IQ(0.5); //gVdq_Open_Loop.value[0];
      gVdq_out_pu.value[1] = _IQ(0.5); //gVdq_Open_Loop.value[1];
    
      // compute the sine and cosine phasor values which are part of the inverse
      // Park transform calculations. Once these values are computed,
      // they are copied into the IPARK module, which then uses them to
      // transform the voltages from DQ to Alpha/Beta reference frames.
      phasor.value[0] = _IQcosPU(angle_pu);
      phasor.value[1] = _IQsinPU(angle_pu);
    
      // set the phasor in the inverse Park transform
      IPARK_setPhasor(iparkHandle,&phasor);
    
      // Run the inverse Park module.  This converts the voltage vector from
      // synchronous frame values to stationary frame values.
      IPARK_run(iparkHandle,&gVdq_out_pu,&Vab_pu);
    
      // Now run the space vector generator (SVGEN) module.
      // There is no need to do an inverse CLARKE transform, as this is
      // handled in the SVGEN_run function.
      SVGEN_run(svgenHandle,&Vab_pu,&(gPwmData.Tabc));
    
      // write to the PWM compare registers, and then we are done!
      HAL_writePwmData(halHandle,&gPwmData);
    
    #ifdef DEBUG
      // ------------------------------------------------------------------------------
      //    Connect inputs of the PWMDAC module
      // ------------------------------------------------------------------------------
      gDacData.value[0] = Vab_pu.value[0];
      gDacData.value[1] = Vab_pu.value[1];
      gDacData.value[2] = gPwmData.Tabc.value[2];
      gDacData.value[3] = gPwmData.Tabc.value[1]-gPwmData.Tabc.value[2];
    
      // write the data to DAC module
      HAL_writeDacData(halHandle, &gDacData);
    
      // ------------------------------------------------------------------------------
      //    Connect inputs of the DATALOG module
      // ------------------------------------------------------------------------------
    /*  DlogCh1 = (int16)_IQtoIQ15(svgen1.Ta);
      DlogCh2 = (int16)_IQtoIQ15(svgen1.Tb);
      DlogCh3 = (int16)_IQtoIQ15(svgen1.Tc);
      DlogCh4 = (int16)_IQtoIQ15(svgen1.Tb-svgen1.Tc);*/
    #endif // DEBUG
    
    #endif // (BUILDLEVEL==LEVEL1)
    
      // ------------------------------- FRAMEWORK ----------------------------------------
      // read the timer 1 value and update the CPU usage module
      timer1Cnt = HAL_readTimerCnt(halHandle,1);
      CPU_USAGE_updateCnts(cpu_usageHandle,timer1Cnt);
    
      // run the CPU usage module
      CPU_USAGE_run(cpu_usageHandle);
    
      return;
    }

    But when I run this code, the frequency is not true, for example: 

    when I want to run  @50Hz: gAngle_Delta_Open_Loop = _IQ(50.0/USER_CTRL_FREQ_Hz);

    but the result of the signal SVgen when checked by PWMDAC module is not 50Hz, it is very low.

    Beside the phasor of Vab_pu.value[0] and Vab_pu.value[1] or (Valpha & Vbeta) is not 90 degrees, it follow exactly the same phase. Could you please point out where I was wrong?

    Many thank you!

  • I've never tried this with lab11. Lab 11 doesn't use the CTRL module, so if you are going to re-use the updated CTRL module I suggested then you should use one of the previous labs which uses the CTRL module.

  • thank you for your answer.

    it was really helpful.

    a have another question.

    what about using proj_lab_01 in motorware18? is this usfull for Scalar (V/f) Control of 3-Phase PMSM or ACIM Motor?

  • lab01 is fully open loop control. if that is what you are interested in it will work