flxwkn.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403
  1. /************************************************************************
  2. Project: Welling Motor Control Paltform
  3. Filename: flxwkn.c
  4. Partner Filename: flxwkn.h
  5. Description: Flux weakening control for PMSM
  6. Complier: IAR Embedded Workbench for ARM 7.80.4
  7. CPU TYPE : GD32F3x0
  8. *************************************************************************
  9. Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
  10. All rights reserved.
  11. *************************************************************************
  12. *************************************************************************
  13. Revising History (ECL of this file):
  14. ************************************************************************/
  15. /************************************************************************
  16. Beginning of File, do not put anything above here except notes
  17. Compiler Directives:
  18. ************************************************************************/
  19. #ifndef _FLXWKN_C_
  20. #define _FLXWKN_C_
  21. #endif
  22. /************************************************************************
  23. Include File
  24. ************************************************************************/
  25. #include "flxwkn.h"
  26. #include "mathtool.h"
  27. #define abs(A) (((A) < 0) ? - (A) : (A))
  28. /************************************************************************
  29. Private Variables:
  30. ************************************************************************/
  31. UWORD flx_pvt_uwVdcMinTmpPu = 0; // Q14, Temporary minimum value of Vdc in one cycle(50Hz)
  32. UWORD flx_pvt_uwVdcMinPu = 0; // Q14, Minimum value of Vdc in one cycle(50Hz)
  33. UWORD flx_pvt_uwVdcMaxTmpPu = 0; // Q14, Temporary maximum value of Vdc in one cycle(50Hz)
  34. UWORD flx_pvt_uwVdcMaxPu = 0; // Q14, Maxmium value of Vdc in one cycle(50Hz)
  35. UWORD flx_pvt_uwVdcAvgPu = 0; // Q14, Average value of Vdc in one cycle(50Hz)
  36. LPF_OUT flx_pvt_stVdcAvgLpf; // Q14, Average value of Vdc after LPF
  37. UWORD flx_pvt_uwVdcPeriodCt = 0; // Count Vdc period
  38. UWORD flx_pvt_swErrZ1Pu = 0; // Q14
  39. SWORD flx_pvt_swUqErrZ1 = 0; // Q14
  40. /************************************************************************
  41. Constant Table:
  42. ************************************************************************/
  43. /************************************************************************
  44. Exported Functions:
  45. ************************************************************************/
  46. /************************************************************************
  47. Function:
  48. Description:
  49. Call by:
  50. Input Variables:
  51. Output/Return Variables:
  52. Subroutine Call:
  53. Reference:
  54. ************************************************************************/
  55. void flx_voInit(void)
  56. {
  57. flx_pvt_uwVdcMinTmpPu = 0xFFFF; // Q14, Temporary minimum value of Vdc in one cycle(50Hz)
  58. flx_pvt_uwVdcMinPu = 0; // Q14, Minimum value of Vdc in one cycle(50Hz)
  59. flx_pvt_uwVdcMaxTmpPu = 0; // Q14, Temporary maximum value of Vdc in one cycle(50Hz)
  60. flx_pvt_uwVdcMaxPu = 0; // Q14, Maximum value of Vdc in one cycle(50Hz)
  61. flx_pvt_uwVdcAvgPu = 0; // Q14, Average value of Vdc in one cycle(50Hz)
  62. flx_pvt_stVdcAvgLpf.slY.sl = 0; // Q30, Average value of Vdc after LPF
  63. flx_pvt_uwVdcPeriodCt = 0; // Q0,Count Vdc period
  64. flx_pvt_swErrZ1Pu = 0; // Q14
  65. flx_stCtrlOut.slIdSumPu = 0; // Q31
  66. flx_stCtrlOut.swIqLimPu = 0; // Q14, Iq limit value used for speed loop out
  67. flx_stCtrlOut.swIdRefPu = 0; // Q14, Id reference value used for current loop regulation
  68. flx_stCtrlOut.slIdMinEstPu = 0; // Q30, Id min Estimate
  69. flx_pvt_swUqErrZ1 = 0; // Q14
  70. }
  71. /************************************************************************
  72. Function:
  73. Description:
  74. Call by:
  75. Input Variables:
  76. Output/Return Variables:
  77. Subroutine Call:
  78. Reference:
  79. ************************************************************************/
  80. void flx_voCoef(FW_CTRL_COEFIN *in, FW_CTRL_COEF *out)
  81. {
  82. ULONG ulLpfTm; // unit: us
  83. SLONG slKp, slKi, slCurErr;
  84. UWORD uwCrossFreq;
  85. if (in->uwPWMDutyMax < 2)
  86. {
  87. in->uwPWMDutyMax = 2;
  88. }
  89. else if (in->uwPWMDutyMax > 1000)
  90. {
  91. in->uwPWMDutyMax = 1000;
  92. }
  93. else
  94. {}
  95. if (in->uwIBaseAp > 32767)
  96. {
  97. in->uwIBaseAp = 32767;
  98. }
  99. else if (in->uwIBaseAp < 1)
  100. {
  101. in->uwIBaseAp = 1;
  102. }
  103. else
  104. {}
  105. if (in->uwFwCurLimAp > ((SWORD)32767))
  106. {
  107. in->uwFwCurLimAp = (SWORD)32767;
  108. }
  109. else
  110. {}
  111. if (in->swIdMaxAp > ((SWORD)in->uwIBaseAp))
  112. {
  113. in->swIdMaxAp = (SWORD)in->uwIBaseAp;
  114. }
  115. else if (in->swIdMaxAp < (-(SWORD)in->uwIBaseAp))
  116. {
  117. in->swIdMaxAp = (-(SWORD)in->uwIBaseAp);
  118. }
  119. else
  120. {}
  121. if (in->swIdMinAp > ((SWORD)in->uwFwCurLimAp))
  122. {
  123. in->swIdMinAp = (SWORD)in->uwFwCurLimAp;
  124. }
  125. else if (in->swIdMinAp < (-(SWORD)in->uwFwCurLimAp))
  126. {
  127. in->swIdMinAp = (-(SWORD)in->uwFwCurLimAp);
  128. }
  129. else
  130. {}
  131. if (in->swIdPIOutMinAp <= abs(in->swIdMinAp))
  132. {
  133. in->swIdPIOutMinAp = abs(in->swIdMinAp) + 1;
  134. }
  135. else if (in->swIdPIOutMinAp > ((SWORD)in->uwIBaseAp))
  136. {
  137. in->swIdPIOutMinAp = (SWORD)in->uwIBaseAp;
  138. }
  139. else
  140. {}
  141. if (in->uwVdcMinCalcTmMs > 2000)
  142. {
  143. in->uwVdcMinCalcTmMs = 2000;
  144. }
  145. else
  146. {}
  147. if (in->uwVdcLpfFreqHz < 1)
  148. {
  149. in->uwVdcLpfFreqHz = 1;
  150. }
  151. else
  152. {}
  153. if (in->uwFreqTbcHz > 32767)
  154. {
  155. in->uwFreqTbcHz = 32767;
  156. }
  157. else if (in->uwFreqTbcHz < 1)
  158. {
  159. in->uwFreqTbcHz = 1;
  160. }
  161. else
  162. {}
  163. if (in->uwCharCurDampRatio > 16)
  164. {
  165. in->uwCharCurDampRatio = 16;
  166. }
  167. else
  168. {}
  169. if (in->uwCharCurCrossFreqHz > 32)
  170. {
  171. in->uwCharCurCrossFreqHz = 32;
  172. }
  173. else
  174. {}
  175. if (in->uwUbVt < 2)
  176. {
  177. in->uwUbVt = 2;
  178. }
  179. else
  180. {}
  181. if (in->uwUbVt < 1)
  182. {
  183. in->uwUbVt = 1;
  184. }
  185. else if (in->uwUbVt > 4096)
  186. {
  187. in->uwUbVt = 4096;
  188. }
  189. else
  190. {}
  191. if (in->uwFBaseHz < 1)
  192. {
  193. in->uwFBaseHz = 1;
  194. }
  195. else
  196. {}
  197. out->uwVdcRatioPu =
  198. ((ULONG)in->uwPWMDutyMax * 5000 / 1000 * in->uwPWMDutyMax / 1000); // Q14,6640 = Q14((2/pi)*(2/pi)) 5461 3640 =Q14((sqrt(2)/3)*(sqrt(2)/3))
  199. out->slIdMaxPu = (((SLONG)in->swIdMaxAp << 14) / in->uwIBaseAp) << 16; // Q30=Q14+Q16
  200. out->slIdMinPu = (((SLONG)in->swIdMinAp << 14) / in->uwIBaseAp) << 16; // Q30=Q14+Q16
  201. // out->slIdMinLimPu = out->slIdMinPu / 100 * in->uwIdMinLimRatio; // Q30
  202. // out->slIdPIOutMinPu = -((((SLONG)in->swIdPIOutMinAp << 14) / in->uwIBaseAp) << 16); // Q30=Q14+Q16
  203. out->slIdPIOutMinPu = out->slIdMinPu;
  204. out->uwFwCurLimPu = (UWORD)(((SLONG)in->uwFwCurLimAp << 14) / in->uwIBaseAp); // Q14
  205. out->swIqLimMaxPu =
  206. mth_slSqrt(((SLONG)out->uwFwCurLimPu * out->uwFwCurLimPu) - (((SLONG)out->slIdMaxPu >> 16) * ((SLONG)out->slIdMaxPu >> 16))); // Q14=sqrt(Q28)
  207. out->uwIdRegKpPu = in->uwIdRegKpPu; // Q16
  208. out->uwIdRegKitPu = in->uwIdRegKiPu; // Q16
  209. // slCurErr = mth_slSqrt(((SLONG)out->uwFwCurLimPu * out->uwFwCurLimPu) - (out->slIdMinPu >> 16) * (out->slIdMinPu >> 16)) << 16; // Q30
  210. // out->uwIqRegKpPu = slCurErr / ((-out->slIdPIOutMinPu + out->slIdMinPu) >> 14); // Q14=Q30-Q16
  211. // if (out->uwIqRegKpPu >= 32767)
  212. // {
  213. // out->uwIqRegKpPu = 32767;
  214. // }
  215. out->uwVdcMinCalcTm = (UWORD)((ULONG)in->uwVdcMinCalcTmMs * in->uwFreqTbcHz / 1000); // Q0
  216. ulLpfTm = 1000000 / in->uwVdcLpfFreqHz;
  217. mth_voLPFilterCoef(ulLpfTm, in->uwFreqTbcHz, &out->uwVdcAvgLpfCoef);
  218. // out->uwRsPu = (UWORD)(((ULONG)in->uwRsOhm << 15) / ((ULONG)in->uwUbVt * 100000 / in->uwIBaseAp)); // Q15, Phase resistance
  219. // uwCrossFreq = (UWORD)(((ULONG)in->uwCharCurCrossFreqHz << 15) / in->uwFBaseHz); // Q15
  220. // slKp = (ULONG)(in->uwCharCurDampRatio << 12) * uwCrossFreq * 2; // Q12+Q15=Q27
  221. // out->uwKpPu = slKp >> 11; // Q27-Q11=Q16
  222. // slKi = (ULONG)uwCrossFreq * uwCrossFreq; // Q15+Q15=Q30
  223. // out->slKitPu = ((SLONG)(slKi >> 6) * (2 * 102944 * in->uwFBaseHz / in->uwFreqTbcHz >> 7) >> 7); // Q30-Q6+(Q15-Q7)-Q7=Q25,pi(Q15)=102944
  224. }
  225. /************************************************************************
  226. Function:
  227. Description:
  228. Call by:
  229. Input Variables:
  230. Output/Return Variables:
  231. Subroutine Call:
  232. Reference:
  233. ************************************************************************/
  234. // Q14
  235. void flx_voCtrl(FW_CTRL_IN *in, FW_CTRL_COEF *coef, FW_CTRL_OUT *out)
  236. { // Q14
  237. SWORD swErrDltPu; // Q14
  238. SLONG slIdpPu; // Q31
  239. SLONG slIdiPu; // Q31
  240. SLONG slIdSumPu; // Q31
  241. SWORD swUqErr, swUqDeltaErr;
  242. SLONG slIdMinPPu, slIdMinIPu, slErrPu;
  243. SWORD swErrPu;
  244. SWORD swVdc2Pu; // Q14
  245. SWORD swUalpha2Pu; // Q14
  246. SWORD swUbeta2Pu;
  247. /* Get minimum value of Vdc in one cycle(50Hz) */
  248. flx_pvt_uwVdcPeriodCt++;
  249. if (flx_pvt_uwVdcPeriodCt <= 1)
  250. {
  251. flx_pvt_uwVdcAvgPu = in->uwVdcPu;
  252. flx_pvt_stVdcAvgLpf.slY.sl = in->uwVdcPu << 16;
  253. out->slIdMinEstPu = coef->slIdMinPu; // Q30, Id min Estimate
  254. }
  255. else if (flx_pvt_uwVdcPeriodCt < (coef->uwVdcMinCalcTm + 1))
  256. {
  257. if (flx_pvt_uwVdcMinTmpPu > in->uwVdcPu)
  258. {
  259. flx_pvt_uwVdcMinTmpPu = in->uwVdcPu; // Q14
  260. }
  261. if (flx_pvt_uwVdcMaxTmpPu < in->uwVdcPu)
  262. {
  263. flx_pvt_uwVdcMaxTmpPu = in->uwVdcPu; // Q14
  264. }
  265. }
  266. else
  267. {
  268. flx_pvt_uwVdcPeriodCt = 1;
  269. flx_pvt_uwVdcMinPu = flx_pvt_uwVdcMinTmpPu; // Q14
  270. flx_pvt_uwVdcMinTmpPu = in->uwVdcPu; // Q14
  271. flx_pvt_uwVdcMaxPu = flx_pvt_uwVdcMaxTmpPu; // Q14
  272. flx_pvt_uwVdcMaxTmpPu = in->uwVdcPu; // Q14
  273. flx_pvt_uwVdcAvgPu = (flx_pvt_uwVdcMinPu + flx_pvt_uwVdcMaxPu) >> 1;
  274. }
  275. /* Vdc LPF */
  276. flx_pvt_stVdcAvgLpf.uwKx = coef->uwVdcAvgLpfCoef; // Q15
  277. mth_voLPFilter(flx_pvt_uwVdcAvgPu, &flx_pvt_stVdcAvgLpf);
  278. /* Output voltage PI contorl */
  279. swVdc2Pu =
  280. (SWORD)(((SLONG)flx_pvt_stVdcAvgLpf.slY.sw.hi * (SLONG)flx_pvt_stVdcAvgLpf.slY.sw.hi >> 14) * (SLONG)coef->uwVdcRatioPu >> 14); // Q14=Q14+Q14-Q14+Q14-Q14
  281. swUalpha2Pu = (SWORD)((SLONG)in->swUalphaPu * (SLONG)in->swUalphaPu >> 14); // Q14
  282. swUbeta2Pu = (SWORD)((SLONG)in->swUbetaPu * (SLONG)in->swUbetaPu >> 14); // Q14
  283. slErrPu = (SLONG)swVdc2Pu - (SLONG)swUalpha2Pu - (SLONG)swUbeta2Pu; // Q14
  284. if (slErrPu > 32767)
  285. {
  286. slErrPu = 32767;
  287. }
  288. else if (slErrPu < -32768)
  289. {
  290. slErrPu = -32768;
  291. }
  292. else
  293. {}
  294. swErrPu = slErrPu;
  295. swErrDltPu = (SWORD)((SLONG)swErrPu - (SLONG)flx_pvt_swErrZ1Pu); // Q14
  296. flx_pvt_swErrZ1Pu = swErrPu; // Q14
  297. slIdpPu = (SLONG)swErrDltPu * (SLONG)coef->uwIdRegKpPu; // Q30=Q14+Q16
  298. slIdiPu = (SLONG)swErrPu * (SLONG)coef->uwIdRegKitPu; // Q30=Q14+Q16
  299. slIdSumPu = out->slIdSumPu + slIdpPu + slIdiPu; // Q30
  300. /* Limit Id PI output */
  301. if (slIdSumPu > coef->slIdMaxPu)
  302. {
  303. slIdSumPu = coef->slIdMaxPu; // Q30
  304. }
  305. else if (slIdSumPu < coef->slIdPIOutMinPu)
  306. {
  307. slIdSumPu = coef->slIdPIOutMinPu; // Q30
  308. }
  309. else
  310. {}
  311. out->slIdSumPu = slIdSumPu; // Q30
  312. /* Id limit*/
  313. if (out->slIdSumPu < out->slIdMinEstPu)
  314. {
  315. out->swIdRefPu = out->slIdMinEstPu >> 16; // Q30, Id min Estimate
  316. }
  317. else
  318. {
  319. out->swIdRefPu = out->slIdSumPu >> 16; // Q14=Q30-Q16
  320. }
  321. /* Id PI output less than minimum value */
  322. if (out->slIdSumPu < out->slIdMinEstPu)
  323. {
  324. out->swIqLimPu = mth_slSqrt(((SLONG)coef->uwFwCurLimPu * coef->uwFwCurLimPu) - ((SLONG)out->swIdRefPu * out->swIdRefPu)); // Q14=sqrt(Q28)
  325. // out->swIqLimPu = (SWORD)mth_slSqrt(((SLONG)coef->uwFwCurLimPu * coef->uwFwCurLimPu) - (out->swIdRefPu * out->swIdRefPu)) +
  326. // ((((out->slIdSumPu - out->slIdMinEstPu) >> 16) * coef->uwIqRegKpPu) >> 14); // Q14
  327. // swUqErr = -in->swUqRefPu + (in->swIqRefPu * coef->uwRsPu >> 15); // Q14
  328. // swUqDeltaErr = swUqErr - flx_pvt_swUqErrZ1;
  329. // flx_pvt_swUqErrZ1 = swUqErr; // Q14
  330. // slIdMinPPu = swUqDeltaErr * coef->uwKpPu; // Q14+16=30
  331. // slIdMinIPu = swUqErr * coef->slKitPu >> 9; // Q14+25-9=30
  332. // out->slIdMinEstPu = out->slIdMinEstPu + slIdMinPPu + slIdMinIPu; // Q30
  333. //
  334. // if (out->slIdMinEstPu < coef->slIdMinPu)
  335. // {
  336. // out->slIdMinEstPu = coef->slIdMinPu;
  337. // }
  338. // else if (out->slIdMinEstPu > coef->slIdMinLimPu)
  339. // {
  340. // out->slIdMinEstPu = coef->slIdMinLimPu;
  341. // }
  342. // else
  343. // {}
  344. }
  345. else if (out->slIdSumPu >= coef->slIdMaxPu)
  346. {
  347. out->swIqLimPu = coef->swIqLimMaxPu;
  348. }
  349. else
  350. {
  351. out->swIqLimPu = mth_slSqrt(((SLONG)coef->uwFwCurLimPu * coef->uwFwCurLimPu) - ((SLONG)out->swIdRefPu * out->swIdRefPu)); // Q14=sqrt(Q28)
  352. }
  353. /* Iq limit */
  354. if (out->swIqLimPu < 0)
  355. {
  356. out->swIqLimPu = 0; // Q14
  357. }
  358. }
  359. /************************************************************************
  360. Local Functions: N/A
  361. ************************************************************************/
  362. /************************************************************************
  363. Copyright (c) 2018 Welling Motor Technology(Shanghai) Co. Ltd.
  364. All rights reserved.
  365. ************************************************************************/
  366. #ifdef _FLXWKN_C_
  367. #undef _FLXWKN_C_
  368. #endif
  369. /************************************************************************
  370. End of this File (EOF)!
  371. Do not put anything after this part!
  372. ************************************************************************/