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
#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]); } }