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