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