⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smcpos.c

📁 Source Code for Sensorless FOC for PMSM with PFC for dsPIC30F6010A
💻 C
字号:
/* SOFTWARE LICENSE AGREEMENT:
* Microchip Technology Incorporated ("Microchip") retains all ownership and
* intellectual property rights in the code accompanying this message and in all
* derivatives hereto.  You may use this code, and any derivatives created by
* any person or entity by or on your behalf, exclusively with Microchip,s
* proprietary products.  Your acceptance and/or use of this code constitutes
* agreement to the terms and conditions of this notice.
*
* CODE ACCOMPANYING THIS MESSAGE IS SUPPLIED BY MICROCHIP "AS IS".  NO
* WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
* TO, IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE APPLY TO THIS CODE, ITS INTERACTION WITH MICROCHIP,S
* PRODUCTS, COMBINATION WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.
*
* YOU ACKNOWLEDGE AND AGREE THAT, IN NO EVENT, SHALL MICROCHIP BE LIABLE, WHETHER
* IN CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE OR BREACH OF STATUTORY DUTY),
* STRICT LIABILITY, INDEMNITY, CONTRIBUTION, OR OTHERWISE, FOR ANY INDIRECT, SPECIAL,
* PUNITIVE, EXEMPLARY, INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, FOR COST OR EXPENSE OF
* ANY KIND WHATSOEVER RELATED TO THE CODE, HOWSOEVER CAUSED, EVEN IF MICROCHIP HAS BEEN
* ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE.  TO THE FULLEST EXTENT
* ALLOWABLE BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY RELATED TO
* THIS CODE, SHALL NOT EXCEED THE PRICE YOU PAID DIRECTLY TO MICROCHIP SPECIFICALLY TO
* HAVE THIS CODE DEVELOPED.
*
* You agree that you are solely responsible for testing the code and
* determining its suitability.  Microchip has no obligation to modify, test,
* certify, or support the code.
*/
#include "general.h"
#include "smcpos.h"

SFRAC16 __OffsetTheta;
SFRAC16 Op1, Op2, Op3, Res1, FilteredOmega;

void SMC_Position_Estimation (SMC *s)
{
//	long result;
//	int acc_copy;
	register int resultA asm("A");
	asm("PUSH CORCON");
	CORCONbits.SATA = 1;
	CORCONbits.SATB = 1;
	CORCONbits.ACCSAT = 1;
	// Sliding mode current observer

	// 
	//
	//	s->EstIalpha = s->Fsmopos * s->EstIalpha +
	//				   s->Gsmopos * (s->Valpha - s->Ealpha - s->Zalpha)
	//
	//

	Op1 = s->Fsmopos;
	Op2 = s->EstIalpha;

	asm("MOV _Op1, W4");
	asm("MOV _Op2, W5");
	asm("MPY W4*W5, A");

	Op1 = s->Valpha;
	Op2 = s->Ealpha;
	Op3 = s->Zalpha;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W2");
	asm("LAC W1, B");
	asm("ADD W2, #0, B");
	asm("NEG B");
	asm("ADD W0, #0, B");
	asm("SAC.R B, #0, W4");
	
	Op1 = s->Gsmopos;

	asm("MOV _Op1, W5");
	asm("MPY W4*W5, B");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");
	
	s->EstIalpha = Res1;

	// 
	//
	//	s->EstIbeta = s->Fsmopos * s->EstIbeta +
	//				  s->Gsmopos * (s->Vbeta - s->Ebeta - s->Zbeta)
	//
	//

	Op1 = s->Fsmopos;
	Op2 = s->EstIbeta;

	asm("MOV _Op1, W4");
	asm("MOV _Op2, W5");
	asm("MPY W4*W5, A");

	Op1 = s->Vbeta;
	Op2 = s->Ebeta;
	Op3 = s->Zbeta;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W2");
	asm("LAC W1, B");
	asm("ADD W2, #0, B");
	asm("NEG B");
	asm("ADD W0, #0, B");
	asm("SAC.R B, #0, W4");
	
	Op1 = s->Gsmopos;

	asm("MOV _Op1, W5");
	asm("MPY W4*W5, B");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");
	
	s->EstIbeta = Res1;

	// Current errors
	// s->IalphaError = s->EstIalpha - s->Ialpha;
	Op1 = s->EstIalpha;
	Op2 = s->Ialpha;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->IalphaError = Res1;

	// s->IbetaError = s->EstIbeta - s->Ibeta;

	Op1 = s->EstIbeta;
	Op2 = s->Ibeta;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->IbetaError = Res1;

	// Sliding control calculator

	if (s->IalphaError > 0)
		s->Zalpha = s->Kslide;
	else if (s->IalphaError == 0)
		s->Zalpha = 0;
	else
		s->Zalpha = -s->Kslide;

	if (s->IbetaError > 0)
		s->Zbeta = s->Kslide;
	else if (s->IbetaError == 0)
		s->Zbeta = 0;
	else
		s->Zbeta = -s->Kslide;

	// Sliding control filter -> back EMF calculator
	// s->Ealpha = s->Ealpha + s->Kslf * (s->Zalpha-s->Ealpha)
	Op1 = s->Zalpha;
	Op2 = s->Ealpha;
	Op3 = s->Kslf;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W5");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W4");
	asm("MPY W4*W5, A");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->Ealpha = Res1;

	// s->Ebeta = s->Ebeta + s->Kslf * (s->Zbeta-s->Ebeta)
	Op1 = s->Zbeta;
	Op2 = s->Ebeta;
	Op3 = s->Kslf;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W5");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W4");
	asm("MPY W4*W5, A");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->Ebeta = Res1;

	// New filter used to calculate Position	
	// s->EalphaFinal = s->EalphaFinal + s->KslfFinal * (s->Ealpha-s->EalphaFinal)

	Op1 = s->Ealpha;
	Op2 = s->EalphaFinal;
	Op3 = s->KslfFinal;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W5");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W4");
	asm("MPY W4*W5, A");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->EalphaFinal = Res1;

	// s->EbetaFinal = s->EbetaFinal + s->KslfFinal * (s->Ebeta-s->EbetaFinal)

	Op1 = s->Ebeta;
	Op2 = s->EbetaFinal;
	Op3 = s->KslfFinal;

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W5");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W4");
	asm("MPY W4*W5, A");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	s->EbetaFinal = Res1;

	asm("POP CORCON");

	// Rotor angle calculator -> Theta = atan(Ebeta,-Ealpha)
	s->Theta = cordic(s->EbetaFinal,-s->EalphaFinal);
	
	AccumTheta += s->Theta - PrevTheta;
	PrevTheta = s->Theta;
	
	AccumThetaCnt++;
       if (AccumThetaCnt == diIrpPerCalc)

       {

              resultA = __builtin_mpy(AccumTheta,Q15((float)(SPEED_CONSTANT/2.0)),0,0,0,0,0,0);

              asm("SAC.R A, #0, W0");

              asm("MOV W0, _Res1");

              s->Omega = Res1;

          //    s->Omega *= 2;

              AccumThetaCnt = 0;

              AccumTheta = 0;

       }

    //                               Q15(Omega) * PWM Frequency * 60
    // Speed RPMs = -----------------------------------------------------------
    //               Q15(Speed Constant) * Cycler per Speed Calc * Motor Poles
    // For example:
    //    Omega = .5
    //    PWM Frequency = 8,000
    //    Speed Constant = 1.5625
    //    Cycles per Speed Calc = 8
    //    Motor Poles (pole pairs * 2) = 4
    // Then:
    //    Speed in RPMs is 4,800 RPMs

	// FilteredOmega = FilteredOmega + FilterCoeff * (s->Omega-FilteredOmega)

	asm("PUSH CORCON");
	CORCONbits.SATA = 1;
	CORCONbits.SATB = 1;
	CORCONbits.ACCSAT = 1;

	Op1 = s->Omega;
	Op2 = FilteredOmega;
	Op3 = Q15(0.01);

	asm("MOV _Op1, W0");
	asm("MOV _Op2, W1");
	asm("MOV _Op3, W5");
	asm("LAC W0, A");
	asm("LAC W1, B");
	asm("SUB A");
	asm("SAC.R A, #0, W4");
	asm("MPY W4*W5, A");
	asm("ADD A");
	asm("SAC.R A, #0, W0");
	asm("MOV W0, _Res1");

	FilteredOmega = Res1;

	asm("POP CORCON");

	if (FilteredOmega < Q15(OMEGA0))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC0,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT0;
		__OffsetTheta += CONSTANT0;
	}
	else if (FilteredOmega < Q15(OMEGA1))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC1,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT1;
		__OffsetTheta += CONSTANT1;
	}
	else if (FilteredOmega < Q15(OMEGA2))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC2,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT2;
		__OffsetTheta += CONSTANT2;
	}
	else if (FilteredOmega < Q15(OMEGA3))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC3,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT3;
		__OffsetTheta += CONSTANT3;
	}
	else if (FilteredOmega < Q15(OMEGA4))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC4,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT4;
		__OffsetTheta += CONSTANT4;
	}
	else if (FilteredOmega < Q15(OMEGA5))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC5,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT5;
		__OffsetTheta += CONSTANT5;
	}
	else if (FilteredOmega < Q15(OMEGA6))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC6,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT6;
		__OffsetTheta += CONSTANT6;
	}
	else if (FilteredOmega < Q15(OMEGA7))
	{
		resultA = __builtin_mpy(FilteredOmega,SLOPEFRAC7,0,0,0,0,0,0);
		asm("SAC.R A, #0, W0");
		asm("MOV W0, _Res1");
		__OffsetTheta = Res1;
		__OffsetTheta += FilteredOmega * SLOPEINT7;
		__OffsetTheta += CONSTANT7;
	}
	else
		__OffsetTheta = DEFAULTCONSTANT;

	s->Theta = s->Theta + __OffsetTheta;

	return;
}

SFRAC16 FracDiv(SFRAC16 num, SFRAC16 den)
{
	SFRAC16 FracDivResult;
	__asm__ volatile("repeat #17\n\t"
                     "divf %1,%2\n\t"
                     "mov w0,%0" : /* output */ "=g"(FracDivResult)
                                 : /* input */ "r"(num),
                                               "e"(den)
                                 : /* clobber */ "w0");

	return FracDivResult;
}

void SMCInit(SMC *s)
{
	float TemporalFloat;
    //                R * Ts
    // Fsmopos = 1 - --------
    //                  L
    //            Ts
    // Gsmopos = ----
    //            L
    // Ts = Sampling Period. If sampling at PWM, Ts = 50 us
    // R = Phase Resistance. If not provided by motor datasheet,
    //     measure phase to phase resistance with multimeter, and
    //     divide over two to get phase resistance. If 4 Ohms are
    //     measured from phase to phase, then R = 2 Ohms
    // L = Phase inductance. If not provided by motor datasheet,
    //     measure phase to phase inductance with multimeter, and
    //     divide over two to get phase inductance. If 2 mH are
    //     measured from phase to phase, then L = 1 mH
    
    TemporalFloat = (float)(1 - PhaseRes * dLoopTimeInSec / PhaseInd);
	if (TemporalFloat < 0.0)
		s->Fsmopos = Q15(0.0);
	else
		s->Fsmopos = Q15(TemporalFloat);

	TemporalFloat = (float)(dLoopTimeInSec / PhaseInd);
	if (TemporalFloat > 1.0)
		s->Gsmopos = Q15(0.99999);
	else
		s->Gsmopos = Q15(TemporalFloat);

	s->Kslide = Q15(0.5);
	s->Kslf = Q15(0.037);
	s->KslfFinal = Q15(0.067);
	return;
}

unsigned int const Angles[15]={
	8192,	4836,	2555,
	1297,	651,	326,
	163,	81,		41,
	20,		10,		5,
	3,		1,		1};

int cordic(int x, int y)
{	
	unsigned char quadrant, step;
	int currangle, newx;

	if((x >= 0) && (y >= 0)) // Quadrant 0, 0 < angle < 90
		quadrant = 0;
	else if((x < 0) && (y >= 0)) // Quadrant 1, 90 < angle < 180
	{
		quadrant = 1;
		x = -x;
	}
	else if((x < 0) && (y < 0)) // Quadrant 2, 180 < angle < 270
	{
		quadrant = 2;
		x = -x;
		y = -y;
	}
	else if((x >= 0) && (y < 0)) // Quadrant 3, 270 < angle < 360
	{
		quadrant = 3;
		y = -y;
	}
	currangle = 0;

	for(step = 0; step < 10; step++)
	{
		if(y < 0)
		{	
			newx = x - (y >> step);
			y = (x >> step) + y;
			x = newx;
			currangle += Angles[step]; 
		}
		else
		{	
			newx = x + (y >> step);
			y = -(x >> step) + y;
			x = newx;
			currangle -= Angles[step]; 
		}
	}

	switch(quadrant)
	{
		case 0:	currangle = -currangle;
				break;

		case 1:	currangle = 32768 + currangle;
				break;

		case 2: currangle = 32768 - currangle;
				break;

		case 3: currangle = currangle;
				break;
	}
	
	return currangle;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -