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.

Direct Torque Control - Speed Estimator - Flux Estimator - Stellaris LM4F120

Other Parts Discussed in Thread: TMS320F28069

Hi,

We are implementing a DTC for an induction motor. We have designed and implemented 3 phase inverter and also current sensors. Rigth now we are testing an speed estimator based in a stator and rotor flux estimators. Stator and flux estimators have been made based on stator currents measuring.

It seems that ADC is working well, because although in the Watch-Expression pane, signal doesn't looks like before ADC, we sent it to MATLAB and plot it here and waveform is very closer to original signal, both shape and values.

However, program doesn't estimate speed well. We believe that stator flux estimator is well because we can see rho angle changing convering the six D-Q sectors when load increases on motor shaft.

So, we believe that problem is on rotor flux estimator. However we need to clarify whether discrete forms in all estimators were implemented rigth on C language. It is, we used 4 positions FIFO included into sample sequencer 1 of both ADC0 and ADC1. Then we took k-1 and k-2 instant values to perform flux and speed estimators.

Could you please be so kind to help us diagnosing the problem? Could be due to all calcuations are performing into while loop and would be better include those into interrupts?

Enclosed you can find a .docx document with a brief explanation about Speed and Flux estimators we are using for. Also the full program code in which all equations are described in detail.

We are using Stellaris Launchpad LM4F120 Board.

Thanks in advance for your help.

Sincerely,

Diego Mora

6014.FLUX ESTIMATOR.docx

#include <math.h>
#include "inc/hw_memmap.h"			
#include "inc/hw_types.h"			// Defines and macros for System Control API of driverLib
#include "driverlib/gpio.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/debug.h"
#include "driverlib/adc.h"			//ADC
#include "driverlib/fpu.h"			//floating point unit
#include "utils/uartstdio.h"

#ifndef M_PI
#define M_PI                    3.14159265358979323846
#endif

#define   UART0          		UART0_BASE

int alpha;

float VdcAtemp,VdcBtemp,VdcAtemp0,VdcBtemp0,VdcAactual,VdcBactual;		//temporaries to convert from long to float
float VdcA_k_menos_1,VdcB_k_menos_1,VdcA_k_menos_2,VdcB_k_menos_2;		//current sensor voltages at instants k-1 and k-2
float iSA_k_menos_1_rms,iSB_k_menos_1_rms,iSA_k_menos_2_rms,iSB_k_menos_2_rms,iSA,iSB;//stator current values at instants k-1 and k-2
float iSD_k_menos_1,iSQ_k_menos_1,iSD_k_menos_2,iSQ_k_menos_2,iSD,iSQ; 
float Ud=108.5;								//DC bus inverter voltage
float T,Rs=17.49;							//T=Sample time, Rs=Stator resistance
float Real_Comp,Im_Comp;					//Real & Imaginary components for second member in 2.15 and 2.16 equations
float FlujoSD,FlujoSQ,FlujoRD,FlujoRQ,FlujoSD_k_menos_1=0,FlujoSQ_k_menos_1=0,FlujoRD_k_menos_1=0,FlujoRQ_k_menos_1=0;
float Flujo,rho, ang_grad,ang;

/*Speed estimator parameters*/
float Lm=1.1204;							//Magnetizing inductance in Henrys =Xm/2*pi*60Hz
float Rr=2.87;								//Rotor Resistance
float Ls=0.0519,Ls_1;						//Stator Self Inductance in Henrys
float Lr=0.0519;							//Rotor Self Inductance in Henrys
float Ls_t;									//Stator Transient Inductance in Henrys.
float Tr;									//Rotor time constant
float Lr1;									//Leakage Rotor Inductance in Henrys
float FlujoR_2;								//Rotor flux^2
float wr,wr_rpm;							//Rotor speed

//Driver Library Error Routine
#ifdef DEBUG
void__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

int SA,SB,SC, Sa, Sb, Sc;

int main(void)
{
	unsigned long VdcA[4];			//4 positions array SS1, FIFO=4 ADC.
	unsigned long VdcB[4];

	// System clock=40MHz, using PLL, and 5 divider with OSC_MAIN
	SysCtlClockSet(SYSCTL_SYSDIV_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);

	//UART Configuration
	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

	GPIOPinConfigure(GPIO_PA0_U0RX);
	GPIOPinConfigure(GPIO_PA1_U0TX);
	GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

	UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE));

	UARTEnable(UART0_BASE);
	UARTStdioInit(0);

	//Floating point unit enable
	FPULazyStackingEnable();
	FPUEnable();

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	GPIOPinTypeGPIOInput(GPIO_PORTE_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3);
	GPIOPadConfigSet(GPIO_PORTE_BASE, GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);	// Enable ADC0
	SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);	// Enable ADC1

	//ADC Sample Rate
	SysCtlADCSpeedSet(SYSCTL_ADCSPEED_1MSPS);	// 1.000.000 samples per second

	ADCHardwareOversampleConfigure(ADC0_BASE, 64);
	T=0.000001*64;								//T is sample rate multiplied by 64 
	ADCSequenceDisable(ADC0_BASE, 1);			//Disable ADC Sequencer 1
	ADCSequenceDisable(ADC1_BASE, 1);			//Disable ADC Sequencer 1

	//Configure ADC0 and ADC1
	ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
	ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
	
	//ADCSequenceStepConfigure(ADC#,Sequencer,Step #,converter source)
	ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH6);
	ADCSequenceStepConfigure(ADC0_BASE, 1, 1, ADC_CTL_CH6);
	ADCSequenceStepConfigure(ADC0_BASE, 1, 2, ADC_CTL_CH6);
	ADCSequenceStepConfigure(ADC0_BASE, 1, 3, ADC_CTL_CH6 | ADC_CTL_IE | ADC_CTL_END);

	ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH7);
	ADCSequenceStepConfigure(ADC1_BASE, 1, 1, ADC_CTL_CH7);
	ADCSequenceStepConfigure(ADC1_BASE, 1, 2, ADC_CTL_CH7);
	ADCSequenceStepConfigure(ADC1_BASE, 1, 3, ADC_CTL_CH7 | ADC_CTL_IE | ADC_CTL_END);

	//Enable Sample Sequencer 1
	ADCSequenceEnable(ADC0_BASE, 1);
	ADCSequenceEnable(ADC1_BASE, 1);

	while(1)
	{
		//Erase interruption flag before write on it
		ADCIntClear(ADC0_BASE, 1);
		ADCIntClear(ADC1_BASE, 1);

		ADCProcessorTrigger(ADC0_BASE, 1);		//Trigger software conversion
		ADCProcessorTrigger(ADC1_BASE, 1);
		// Wait until conversion complete
		while(!ADCIntStatus(ADC0_BASE, 1, false)&&!ADCIntStatus(ADC1_BASE, 1, false))
		{
		}

		/* Get conversion resuts into VdcA and VdcB respectively

		ADCSequenceDataGet(ADC0_BASE, 1, VdcA);
		ADCSequenceDataGet(ADC1_BASE, 1, VdcB);

		/**** Reads of this register return conversion result data in the order
		 *  sample 0, sample 1, and so on, until the FIFO is empty pag819 datasheet */

		/*Actual sample is VdcA[3]. Thus, for example VdcA(k-1)=VdcA[2], VdcA(k-2)=VdcA[1] */

		VdcAactual=VdcA[3];
		VdcBactual=VdcB[3];
		VdcAtemp=VdcA[2];
		VdcBtemp=VdcB[2];
		VdcAtemp0=VdcA[1];
		VdcBtemp0=VdcB[1];

		 /* mV per ADC code = (VREFP - VREFN) / 4096
		 * Value in ADC Register = 4095*Vin/3.3. But given current sensor characterization we have:   */
		 

		VdcAactual=(VdcAactual*(3.0/4095))-1.5;		//From current sensor characterization
		VdcBactual=(VdcBactual*(3.0/4095))-1.5;
		VdcA_k_menos_1=(VdcAtemp*(3.0/4095))-1.5;
		VdcB_k_menos_1=(VdcBtemp*(3.0/4095))-1.5;
		VdcA_k_menos_2=(VdcAtemp0*(3.0/4095))-1.5;
		VdcB_k_menos_2=(VdcBtemp0*(3.0/4095))-1.5;

		iSA=VdcAactual;
		iSB=VdcBactual;
		iSA_k_menos_1_rms=VdcA_k_menos_1;
		iSB_k_menos_1_rms=VdcB_k_menos_1;
		iSA_k_menos_2_rms=VdcA_k_menos_2;
		iSB_k_menos_2_rms=VdcB_k_menos_2;

		// Obtaining iSD and iSQ currents in every instant:
		iSD=iSA;
		iSQ=((1/(sqrt(3)))*(iSA+2*iSB));
		iSD_k_menos_1=iSA_k_menos_1_rms;
		iSQ_k_menos_1=((1/(sqrt(3)))*(iSA_k_menos_1_rms+2*iSB_k_menos_1_rms));
		iSD_k_menos_2=iSA_k_menos_2_rms;
		iSQ_k_menos_2=((1/(sqrt(3)))*(iSA_k_menos_2_rms+2*iSB_k_menos_2_rms));


		//The inverter switching states are read from pins E 1, 2 and 3
		//Those states are 3 square signals from other micro controller
		Sa = GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_1);
		Sb = GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_2);
		Sc = GPIOPinRead(GPIO_PORTE_BASE, GPIO_PIN_3);

		//Positions 0, 1 and 2 are divided by 2, 4 and 8 respectively to have 0 or 1 values
		SA=Sa/2.0;
		SB=Sb/4.0;
		SC=Sc/8.0;

		/*If else table is made to implement equations 2.15 and 2.16 */

		if		(SA==0 && SB==0 && SC==0) {Real_Comp=0;Im_Comp=0;					}
		else if	(SA==0 && SB==0 && SC==1) {Real_Comp=-0.5;Im_Comp=-((sqrt(3))/2);	}
		else if	(SA==0 && SB==1 && SC==0) {Real_Comp=-0.5;Im_Comp= ((sqrt(3))/2);	}
		else if	(SA==0 && SB==1 && SC==1) {Real_Comp=-1;Im_Comp=0;					}
		else if	(SA==1 && SB==0 && SC==0) {Real_Comp=1;Im_Comp=0;					}
		else if	(SA==1 && SB==0 && SC==1) {Real_Comp=0.5; Im_Comp=-((sqrt(3))/2);	}
		else if	(SA==1 && SB==1 && SC==0) {Real_Comp=0.5;  Im_Comp=((sqrt(3))/2);	}
		else 							  {Real_Comp=0;Im_Comp=0;					}

		//Stator Flux Estimator. Equations 2.15 and 2.16
		FlujoSD=((2/3)*Ud*T*Real_Comp)-Rs*T*iSD_k_menos_2+((2/3)*Ud*T*Real_Comp)-Rs*T*iSD_k_menos_1;
		FlujoSQ=((2/3)*Ud*T*Im_Comp)-Rs*T*iSQ_k_menos_2+  ((2/3)*Ud*T*Im_Comp)-Rs*T*iSQ_k_menos_1;

		Flujo=sqrt(powf(FlujoSD,2)+powf(FlujoSQ,2)); 							//Returns flux vector magnitude 

		//Following: Rho angle in rads, keeping in mind the sign for each quadrant
		if 		(FlujoSD>0 && FlujoSQ>0)		{rho=atanf(FlujoSQ/FlujoSD);		}
		else if	(FlujoSD<0 && FlujoSQ>0)		{rho=M_PI+atanf(FlujoSQ/FlujoSD);	}
		else if	(FlujoSD<0 && FlujoSQ<0)		{rho=M_PI+atanf(FlujoSQ/FlujoSD);	}
		else									{rho=2*M_PI+atanf(FlujoSQ/FlujoSD);	}

		ang=rho;
		ang_grad=ang*180/M_PI;

		if ((0<=ang)&&(M_PI/6>=ang)){alpha=1;}
		else if ((M_PI/6<ang)&&(M_PI/2>=ang)){alpha=2;}
		else if ((M_PI/2<ang)&&(5*M_PI/6>=ang)){alpha=3;}
		else if ((5*M_PI/6<ang)&&(7*M_PI/6>=ang)){alpha=4;}
		else if ((7*M_PI/6<ang)&&(3*M_PI/2>=ang)){alpha=5;}
		else if ((3*M_PI/2<ang)&&(11*M_PI/6>=ang)){alpha=6;}
		else {alpha=1;}

		/*Speed estimator , Equation 2.17 is implemented*/
		//For speed estimation, there are some things that must be performed before
		
		/*1. Stator transient inductance estimation*/
		//Some parameters are defined previously
		
		Ls_t=FlujoSQ/iSQ; 	//Equation 2.18. Transient stator inductance
		Ls_1=FlujoSQ/iSD;
		Lr1=(powf(Lm,2)/(Ls-Ls_t))-Lm; //Equation 2.20
		Lr=Lr1+Lm;
		Tr=Lr/Rr;

		FlujoRD=(Lr/Lm)*(FlujoSD-Ls_t*iSD);			//D-Q Rotor flux components
		FlujoRQ=(Lr/Lm)*(FlujoSQ-Ls_t*iSQ);

		FlujoSD_k_menos_1=((2/3)*Ud*T*Real_Comp)-Rs*T*iSD_k_menos_2;
		FlujoSQ_k_menos_1=((2/3)*Ud*T*Im_Comp)-Rs*T*iSQ_k_menos_2;

		//2. Rotor flux estimator
		FlujoRD_k_menos_1=(Lr/Lm)*(FlujoSD_k_menos_1-Ls_t*iSD_k_menos_1);
		FlujoRQ_k_menos_1=(Lr/Lm)*(FlujoSQ_k_menos_1-Ls_t*iSQ_k_menos_1);

		FlujoR_2=powf(FlujoRD_k_menos_1,2)+powf(FlujoRQ_k_menos_1,2);

		//3. Speed estimator. Equation 2.17

		wr=(FlujoRD_k_menos_1*FlujoRQ-FlujoRQ_k_menos_1*FlujoRD/FlujoR_2)-((Lm/(Tr*FlujoR_2))*(FlujoRD*iSQ-FlujoRQ*iSD));
		wr_rpm = (wr/(2*M_PI))*60;

		/*Finally: VdcA variable (corresponding to sample voltage of stator current iSA)  
		is sent to UART to graph*/
		UARTprintf(" %d", VdcA[0]);

	}

}


  • I wouldn't have thought these micros had the computational heft for DTC.  I shall be intrigued by your results.

    This question does seem, however, to be beyond the scope of this forum.  It almost seems like a please develop my product for me question.

    That said I am curious about your k-1 and k-2 usage.  In the usage I am use to seeing thos terms they are the result to the last successive control points not a set between control points.  I can imagine formulating it as you have but I'm unclear why you would.  I'm also unsure how it would affect the actual control.

     

    Robert

  • Indeed this type/topic post usually resides @ C2000 and/or InstaSpin forums. 

    Unknown is poster's intent by launching here...(or even - if arrival here was deliberate...)

    Few - this space - have the necessary motor interest/expertise to assist...

  • So, if it is not possibe with this microcontroller, which board do you suggest? TMS320F28069? I need a new one that don´t need the Boosterpacks, because as I told before I implemented it and also the current sensor system.

  • I was hoping you had measured the performance and determined it adequate.  I am heartily dissappointed.

    I do recomend that you measure your current performance.  That will let you know how close you are.  The code may not work but it's the best performance indicator you have.

    As far as a recommended micro.  I have no idea.  I've not done any FOC drives much less DTC although I have looked at the concepts. 

    I fear you are about to discover just how big your task is.

    Robert

    BTW I don't think any board actually requires boosterpacks.

  • @cb1 I was thinking about the prospect of anyone taking some stranger's mass of application code and wordage and debugging it for them. But particular forum is a good point too.

    Instaspin is probably a good pointer.  Particularly if the inverter hardware has not been motor tested yet which seems likely.  First get something to work then move to more sophisticated control.  Start with simple V/Hz control would be my plan.

     

    Robert

  • @Robert,

    Generally agree.  Poster appears to believe that "many/most" here will understand his requirement - I do not.  Still silent is why/how that post landed - this weakly motorized (i.e. sail only) shore.  (C2000 - InstaSpin far more the domain of most motor-centric MCUs & code issues...)