123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383 |
- /************************************************************************
- Project: Welling Motor Control Paltform
- Filename: obs.c
- Partner Filename: obs.h
- Description: The position and speed observer for PMSM
- Complier: IAR Embedded Workbench for ARM 7.80, IAR Systems.
- CPU TYPE : GD32F3x0
- *************************************************************************
- Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
- All rights reserved.
- *************************************************************************
- *************************************************************************
- Revising History (ECL of this file):
- ************************************************************************/
- /************************************************************************
- Beginning of File, do not put anything above here except notes
- Compiler Directives:
- *************************************************************************/
- #ifndef _OBS_C_
- #define _OBS_C_
- #endif
- /************************************************************************
- Included File:
- *************************************************************************/
- #include "syspar.h"
- #include "user.h"
- /************************************************************************
- Private Variables
- *************************************************************************/
- SWORD obs_pvt_swEMFAlphaCompPu = 0; // Q14, Output stationary alfa-axis EMF value
- SWORD obs_pvt_swEMFBetaCompPu = 0; // Q14, Output stationary beta-axis EMF value
- SLONG obs_pvt_slDeltaErrPu = 0; // Q15, Last delta value for PLL PI control
- /************************************************************************
- Constant Table (N/A)
- *************************************************************************/
- /************************************************************************
- Exported Functions:
- *************************************************************************/
- /***************************************************************
- Function: obs_voObsInit;
- Description: observer output initialization
- Call by:
- Input Variables: N/A
- Output/Return Variables: N/A
- Subroutine Call: N/A;
- Reference: N/A
- ****************************************************************/
- void obs_voObsInit(void)
- {
- obs_stObsOutPu.slFluxAlphaPu = 0; // Q26
- obs_stObsOutPu.slFluxBetaPu = 0; // Q26
- obs_stObsOutPu.swElecFreqPu = 0; // Q15
- obs_stObsOutPu.slElecFreqPu = 0; // Q29
- obs_stObsOutPu.uwElecThetaPu = 0; // Q15
- obs_stObsOutPu.slElecThetaPu = 0; // Q29
- obs_stObsOutPu.swActiveFluxPu = 0; // Q10
- obs_stObsOutPu.swFluxAlphaPu = 0; // Q10
- obs_stObsOutPu.swFluxBetaPu = 0; // Q10
- obs_stFluxAlphaPIOut.slURefPu = 0; // Q28
- obs_stFluxAlphaPIOut.swURefPu = 0; // Q14
- obs_stFluxAlphaPIOut.swErrZ1Pu = 0; // Q10
- obs_stFluxBetaPIOut.slURefPu = 0; // Q28
- obs_stFluxBetaPIOut.swURefPu = 0; // Q14
- obs_stFluxBetaPIOut.swErrZ1Pu = 0; // Q10
- obs_pvt_swEMFAlphaCompPu = 0;
- obs_pvt_swEMFBetaCompPu = 0;
- obs_pvt_slDeltaErrPu = 0;
- }
- /***************************************************************
- Function: obs_voObsCoef;
- Description: Coefficient calculation for "asr_voSpdPI"
- Call by: functions in main loop;
- Input Variables: ASR_SPDPI_COFIN
- Output/Return Variables: ASR_SPDPI_COF
- Subroutine Call: N/A;
- Reference: N/A
- ****************************************************************/
- void obs_voObsCoef(OBS_COF_IN *in, OBS_COF *out)
- {
- UWORD uwWebRadps;
- UWORD uwMvcPu;
- ULONG ulDamper;
- UWORD uwDamper;
- ULONG ulKp;
- ULONG ulKi;
- UWORD uwDampingRatio;
- UWORD uwCrossFreq;
- if (in->uwRbOm < 10)
- {
- in->uwRbOm = 10;
- }
- if (in->uwLbHm < 10)
- {
- in->uwLbHm = 10;
- }
- if (in->uwFluxbWb < 10)
- {
- in->uwFluxbWb = 10;
- }
- if (in->uwFbHz < 10)
- {
- in->uwFbHz = 10;
- }
- else if (in->uwFbHz > 10000)
- {
- in->uwFbHz = 10000;
- }
- if (in->uwFreqTbcHz < 10)
- {
- in->uwFreqTbcHz = 10;
- }
- if (in->uwSpdPllMcoef > 100)
- {
- in->uwSpdPllMcoef = 100;
- }
- if ((in->uwFluxWb >> 5) > in->uwFluxbWb)
- {
- in->uwFluxWb = (in->uwFluxbWb << 5);
- }
- if (in->uwRsOm > in->uwRbOm)
- {
- in->uwRsOm = in->uwRbOm;
- }
- if ((in->uwLqHm >> 5) > in->uwLbHm)
- {
- in->uwLqHm = (in->uwLbHm << 5);
- }
- if ((in->uwLdHm >> 5) > in->uwLbHm)
- {
- in->uwLdHm = (in->uwLbHm << 5);
- }
- if (in->uwFbHz > ((ULONG)in->uwFreqTbcHz * 0x2AAA >> 15))
- {
- in->uwFbHz = (ULONG)in->uwFreqTbcHz * 0x2AAA >> 15;
- }
- uwWebRadps = (ULONG)2 * 31416 * in->uwFbHz / 10000; // unit: rad/s, Electrical radian frequency base
- if (in->uwFluxDampingRatio < 1)
- {
- in->uwFluxDampingRatio = 1;
- }
- else if (in->uwFluxDampingRatio > 100)
- {
- in->uwFluxDampingRatio = 100;
- }
- if (in->uwFluxCrossFreqHz < 1)
- {
- in->uwFluxCrossFreqHz = 1;
- }
- else if (in->uwFluxCrossFreqHz > 100)
- {
- in->uwFluxCrossFreqHz = 100;
- }
- out->uwFluxPPu = ((ULONG)in->uwFluxWb << 10) / in->uwFluxbWb; // Q10
- out->uwRsPu = ((ULONG)in->uwRsOm << 15) / in->uwRbOm; // Q15
- out->uwLqPu = ((ULONG)in->uwLqHm << 10) / in->uwLbHm; // Q10
- out->uwLdPu = ((ULONG)in->uwLdHm << 10) / in->uwLbHm; // Q10
- out->uwCurTsPu = ((ULONG)205887 * in->uwFbHz) / in->uwFreqTbcHz; // Q15, Q15(2pi)-->205887
- out->uwCurTs = ((ULONG)in->uwFbHz << 10) / in->uwFreqTbcHz; // Q10, TBC time
- /************************Speed PLL Coefficient*****************************/
- uwMvcPu = ((ULONG)in->uwSpdPllWvcHz << 10) / in->uwFbHz; // Q10
- /* PLL Kp=M*w/sqrt(1+M^2) */
- ulDamper = (1 + in->uwSpdPllMcoef * in->uwSpdPllMcoef) << 8; // Q8
- uwDamper = mth_slSqrt(ulDamper); // Q4
- out->uwSpdPllKpPu = ((ULONG)in->uwSpdPllMcoef * uwMvcPu / uwDamper) << 8; // Q10-Q4+Q8=Q14
- /* PLL Ki=w^2*T_cnt_ctrl/sqrt(1+M^2) */
- out->uwSpdPllKiPu = ((((ULONG)uwMvcPu * out->uwCurTsPu) / uwDamper) * uwMvcPu) >> 17; // Q10+Q15-Q4+Q10-Q17=Q14
- /**************************Flux PI Coefficient*****************************/
- /* Flux PI regulator Kp=2*k*w */
- uwDampingRatio = ((ULONG)in->uwFluxDampingRatio << 12) / 10; // Q12
- uwCrossFreq = ((ULONG)2 * 31416 * in->uwFluxCrossFreqHz / 10000) << 8; // Q8
- ulKp = (ULONG)uwDampingRatio * uwCrossFreq * 2; // Q12+Q8=Q20
- out->uwFluxKpPu = ulKp / uwWebRadps >> 2; // Q20-Q2=Q18
- /* Flux PI regulator Ki=w^2 */
- ulKi = (ULONG)uwCrossFreq * uwCrossFreq; // Q8+Q8=Q16
- out->uwFluxKitPu = (ulKi / uwWebRadps * out->uwCurTsPu / uwWebRadps) >> 3; // Q16+Q15-Q3=Q28
- }
- /***************************************************************
- Function: obs_voObsCalc
- Description: speed and position caculate
- Call by: tbc_it
- Input Variables:
- Output/Return Variables:
- Subroutine Call:
- Reference: N/A
- ****************************************************************/
- void obs_voObsCalc(OBS_IN *in, OBS_COF *coef, OBS_OUT *out)
- {
- SWORD swEMFAlphaPu, swEMFBetaPu;
- SWORD swRtFluxAlphaPu, swRtFluxBetaPu;
- SINCOS sincosTmp; //, sincosTmp1;
- SLONG slDeltaTmpPu, slDeltaErrTmpPu;
- SLONG slKpTmpPu, slKitTmpPu;
- SLONG slSpdRefPu;
- SLONG slPreRtPosPu, slActRtPosPu;
- UWORD uwPreRtPosPu;
- SWORD swFluxDPu, swFluxQPu;
- SWORD swMaxVsPu;
- /*****************************Current Model*****************************/
- /* Predict the rotor Angle according to last rotor angle and speed */
- slPreRtPosPu = out->slElecThetaPu + ((out->slElecFreqPu >> 10) * coef->uwCurTs); // Q29-Q10+Q10=Q29
- if (slPreRtPosPu >= 0x20000000) // Q29
- {
- slPreRtPosPu -= 0x20000000;
- }
- else if (slPreRtPosPu < 0)
- {
- slPreRtPosPu += 0x20000000;
- }
- uwPreRtPosPu = (UWORD)(slPreRtPosPu >> 14); // Q29-Q14=Q15
- mth_voSinCos(uwPreRtPosPu, &sincosTmp);
- /* Current Park (I_alpha I_beta -> Id Iq) */
- obs_stParkInPu.swAlphaPu = in->swIalphaPu; // Q14
- obs_stParkInPu.swBetaPu = in->swIbetaPu; // Q14
- obs_stParkInPu.uwThetaPu = uwPreRtPosPu; // Q15
- crd_voPark(&obs_stParkInPu, &obs_stFluxParkPu);
- /* Flux_D = Ld*id+Flux_PM; Flux_Q = Lq*iq */
- swFluxDPu = coef->uwFluxPPu + (((SLONG)obs_stFluxParkPu.swDPu * coef->uwLdPu) >> 14); // Q14+Q10-Q14=Q10
- swFluxQPu = ((SLONG)obs_stFluxParkPu.swQPu * coef->uwLqPu) >> 14; // Q14+Q10-Q14=Q10
- /* Flux IPark (Fluxd Fluxq -> Fluxalpha Fluxbeta) */
- obs_stIParkInPu.swDPu = swFluxDPu; // Q10
- obs_stIParkInPu.swQPu = swFluxQPu; // Q10
- obs_stIParkInPu.uwThetaPu = uwPreRtPosPu; // Q15
- crd_voIPark(&obs_stIParkInPu, &obs_stFluxIParkPu);
- /*****************************Voltage Model*****************************/
- swEMFAlphaPu = in->swUalphaPu - (in->swIalphaPu * coef->uwRsPu >> 15); // Q14+Q15-Q15=Q14
- swEMFBetaPu = in->swUbetaPu - (in->swIbetaPu * coef->uwRsPu >> 15); // Q14+Q15-Q15=Q14
- obs_pvt_swEMFAlphaCompPu = swEMFAlphaPu + obs_stFluxAlphaPIOut.swURefPu; // Q14
- obs_pvt_swEMFBetaCompPu = swEMFBetaPu + obs_stFluxBetaPIOut.swURefPu; // Q14
- out->slFluxAlphaPu = out->slFluxAlphaPu + ((SLONG)obs_pvt_swEMFAlphaCompPu * coef->uwCurTsPu >> 3); // Q14+Q15-Q3=Q26
- out->slFluxBetaPu = out->slFluxBetaPu + ((SLONG)obs_pvt_swEMFBetaCompPu * coef->uwCurTsPu >> 3); // Q14+Q15-Q3=Q26
- out->swFluxAlphaPu = out->slFluxAlphaPu >> 16; // Q26-Q16=Q10
- out->swFluxBetaPu = out->slFluxBetaPu >> 16; // Q26-Q16=Q10
- swMaxVsPu = ((SLONG)in->uwVdcPu * 0x5555) >> 15; // Q14+Q15-Q15=Q14
- /* Flux alpha PI regulator */
- obs_stFluxAlphaPIIn.swRefPu = obs_stFluxIParkPu.swAlphaPu; // Q10
- obs_stFluxAlphaPIIn.swFdbPu = out->swFluxAlphaPu; // Q10
- obs_stFluxAlphaPIIn.swUmaxPu = swMaxVsPu; // Q14
- obs_stFluxAlphaPIIn.swUminPu = -swMaxVsPu; // Q14
- obs_stFluxAlphaPICoef.uwFluxKpPu = coef->uwFluxKpPu; // Q18
- obs_stFluxAlphaPICoef.uwFluxKitPu = coef->uwFluxKitPu; // Q28
- obs_voFluxPI(&obs_stFluxAlphaPIIn, &obs_stFluxAlphaPICoef, &obs_stFluxAlphaPIOut);
- /* Flux beta PI regulator */
- obs_stFluxBetaPIIn.swRefPu = obs_stFluxIParkPu.swBetaPu; // Q10
- obs_stFluxBetaPIIn.swFdbPu = out->swFluxBetaPu; // Q10
- obs_stFluxBetaPIIn.swUmaxPu = swMaxVsPu; // Q14
- obs_stFluxBetaPIIn.swUminPu = -swMaxVsPu; // Q14
- obs_stFluxBetaPICoef.uwFluxKpPu = coef->uwFluxKpPu; // Q18
- obs_stFluxBetaPICoef.uwFluxKitPu = coef->uwFluxKitPu; // Q28
- obs_voFluxPI(&obs_stFluxBetaPIIn, &obs_stFluxBetaPICoef, &obs_stFluxBetaPIOut);
- /* Stator Flux -> Rotor Flux */
- swRtFluxAlphaPu = out->swFluxAlphaPu - (((SLONG)in->swIalphaPu * coef->uwLqPu) >> 14); // Q14+Q10-Q14=Q10
- swRtFluxBetaPu = out->swFluxBetaPu - (((SLONG)in->swIbetaPu * coef->uwLqPu) >> 14); // Q14+Q10-Q14=Q10
- /* PLL to trace the latest speed */
- slDeltaTmpPu = (((SLONG)swRtFluxBetaPu * sincosTmp.swCosPu) - ((SLONG)swRtFluxAlphaPu * sincosTmp.swSinPu)) >> 10; // Q10+Q15-Q10=Q15
- slDeltaErrTmpPu = slDeltaTmpPu - obs_pvt_slDeltaErrPu; // Q15
- obs_pvt_slDeltaErrPu = slDeltaTmpPu; // Q15
- slKpTmpPu = slDeltaErrTmpPu * coef->uwSpdPllKpPu; // Q15+Q14=Q29
- slKitTmpPu = slDeltaTmpPu * coef->uwSpdPllKiPu; // Q15+Q14=Q29
- slSpdRefPu = slKpTmpPu + slKitTmpPu + out->slElecFreqPu; // Q29
- /* Limit the speed value to avoid overflow */
- if (slSpdRefPu >= 0x20000000)
- {
- slSpdRefPu = 0x20000000 - 1; // Q29
- }
- else if (slSpdRefPu <= -0x20000000)
- {
- slSpdRefPu = -0x20000000; // Q29
- }
- out->slElecFreqPu = slSpdRefPu; // Q29
- out->swElecFreqPu = out->slElecFreqPu >> 14; // Q29-Q14=Q15
- /* Electrical speed to Electrical position */
- // slActRtPosPu = out->slElecThetaPu + ((((slSpdRefPu + out->slElecFreqPu) >> 1) >> 10) * coef->uwCurTs); //Q29+Q10-Q10=Q29
- slActRtPosPu = out->slElecThetaPu + (((SLONG)out->swElecFreqPu * coef->uwCurTs) << 4);
- if (slActRtPosPu >= 0x20000000)
- {
- slActRtPosPu -= 0x20000000; // Q15+Q14=Q29
- }
- else if (slActRtPosPu < 0)
- {
- slActRtPosPu += 0x20000000; // Q15+Q14=Q29
- }
- out->slElecThetaPu = slActRtPosPu; // Q29
- out->uwElecThetaPu = out->slElecThetaPu >> 14; // Q29-Q14=Q15
- // mth_voSinCos(out->uwElecThetaPu, &sincosTmp1);
- // slActiveFluxPu = (SLONG)swRtFluxAlphaPu * sincosTmp1.swCosPu + (SLONG)swRtFluxBetaPu * sincosTmp1.swSinPu; //Q10+Q15=Q25
- // out->swActiveFluxPu = slActiveFluxPu >> 15; //Q25-Q15=Q10
- // //Q29-Q14=Q15
- }
- /***************************************************************
- Function: obs_voFluxPI;
- Description: Flux PI regulator;
- Call by: functions in TBC;
- Input Variables: ACR_CURPI_IN,ACR_CURPI_COF
- Output/Return Variables: ACR_CURPI_OUT
- Subroutine Call: N/A;
- Reference: N/A
- ****************************************************************/
- void obs_voFluxPI(OBS_FLUXPI_IN *in, OBS_FLUXPI_COF *coef, OBS_FLUXPI_OUT *out)
- {
- SWORD tmp_swErrPu, tmp_swDeltaErrPu;
- SLONG tmp_slUpPu, tmp_slUiPu, tmp_slURefPu;
- SLONG tmp_slUmaxPu, tmp_slUminPu;
- /* U(k) = U(k-1) + Kp * (Err(k) - Err(k-1)) + Kit * Err(k) */
- tmp_swErrPu = in->swRefPu - in->swFdbPu; // Q10
- tmp_swDeltaErrPu = tmp_swErrPu - out->swErrZ1Pu; // Q10
- tmp_slUpPu = (SLONG)tmp_swDeltaErrPu * coef->uwFluxKpPu; // Q10+Q18=Q28
- tmp_slUiPu = ((SLONG)tmp_swErrPu * coef->uwFluxKitPu) >> 10; // Q10+Q28-Q10=Q28
- tmp_slURefPu = out->slURefPu + tmp_slUpPu + tmp_slUiPu; // Q28
- tmp_slUmaxPu = (SLONG)in->swUmaxPu << 14; // Q14+Q14=Q28
- tmp_slUminPu = (SLONG)in->swUminPu << 14; // Q14+Q14=Q28
- if (tmp_slURefPu > tmp_slUmaxPu)
- {
- tmp_slURefPu = tmp_slUmaxPu;
- }
- else if (tmp_slURefPu < tmp_slUminPu)
- {
- tmp_slURefPu = tmp_slUminPu;
- }
- else
- {}
- out->swURefPu = tmp_slURefPu >> 14; // Q28-Q14=Q14
- out->slURefPu = tmp_slURefPu; // Q28
- out->swErrZ1Pu = tmp_swErrPu; // Q10
- }
- /************************************************************************
- Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
- All rights reserved.
- *************************************************************************/
- #ifdef _OBS_C_
- #undef _OBS_C_
- #endif
- /*************************************************************************
- End of this File (EOF):
- !!!!!!Do not put anything after this part!!!!!!!!!!!
- *************************************************************************/
|