No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.
 
 
 
 
 
 

532 líneas
18 KiB

  1. #include "plsr_profile.h"
  2. #include <math.h>
  3. #include <string.h>
  4. /* 正弦表:256 项,sin(pi*i/256) 的 Q16 表示。 */
  5. static const uint16_t PlsrProfileSineTable[256] =
  6. {
  7. 0, 804, 1608, 2412, 3216, 4019, 4821, 5623,
  8. 6424, 7224, 8022, 8820, 9616, 10411, 11204, 11996,
  9. 12785, 13573, 14359, 15143, 15924, 16703, 17479, 18253,
  10. 19024, 19792, 20557, 21320, 22078, 22834, 23586, 24335,
  11. 25080, 25821, 26558, 27291, 28020, 28745, 29466, 30182,
  12. 30893, 31600, 32303, 33000, 33692, 34380, 35062, 35738,
  13. 36410, 37076, 37736, 38391, 39040, 39683, 40320, 40951,
  14. 41576, 42194, 42806, 43412, 44011, 44604, 45190, 45769,
  15. 46341, 46906, 47464, 48015, 48559, 49095, 49624, 50146,
  16. 50660, 51166, 51665, 52156, 52639, 53114, 53581, 54040,
  17. 54491, 54934, 55368, 55794, 56212, 56621, 57022, 57414,
  18. 57798, 58172, 58538, 58896, 59244, 59583, 59914, 60235,
  19. 60547, 60851, 61145, 61429, 61705, 61971, 62228, 62476,
  20. 62714, 62943, 63162, 63372, 63572, 63763, 63944, 64115,
  21. 64277, 64429, 64571, 64704, 64827, 64940, 65043, 65137,
  22. 65220, 65294, 65358, 65413, 65457, 65492, 65516, 65531,
  23. 65535, 65531, 65516, 65492, 65457, 65413, 65358, 65294,
  24. 65220, 65137, 65043, 64940, 64827, 64704, 64571, 64429,
  25. 64277, 64115, 63944, 63763, 63572, 63372, 63162, 62943,
  26. 62714, 62476, 62228, 61971, 61705, 61429, 61145, 60851,
  27. 60547, 60235, 59914, 59583, 59244, 58896, 58538, 58172,
  28. 57798, 57414, 57022, 56621, 56212, 55794, 55368, 54934,
  29. 54491, 54040, 53581, 53114, 52639, 52156, 51665, 51166,
  30. 50660, 50146, 49624, 49095, 48559, 48015, 47464, 46906,
  31. 46341, 45769, 45190, 44604, 44011, 43412, 42806, 42194,
  32. 41576, 40951, 40320, 39683, 39040, 38391, 37736, 37076,
  33. 36410, 35738, 35062, 34380, 33692, 33000, 32303, 31600,
  34. 30893, 30182, 29466, 28745, 28020, 27291, 26558, 25821,
  35. 25080, 24335, 23586, 22834, 22078, 21320, 20557, 19792,
  36. 19024, 18253, 17479, 16703, 15924, 15143, 14359, 13573,
  37. 12785, 11996, 11204, 10411, 9616, 8820, 8022, 7224,
  38. 6424, 5623, 4821, 4019, 3216, 2412, 1608, 804,
  39. };
  40. static uint64_t PlsrProfileHzToQ32(uint32_t hz)
  41. {
  42. return (uint64_t)hz << 32U;
  43. }
  44. /* 每刷新步的斜率增量(Q32.32),支持 0.1ms 刷新(1000/refreshHz 可能 < 1)。 */
  45. static uint64_t PlsrProfileSlopePerStepQ32(uint32_t slopeHzPerMs,
  46. uint32_t refreshHz)
  47. {
  48. return PlsrProfileHzToQ32(slopeHzPerMs) * UINT64_C(1000)
  49. / (uint64_t)refreshHz;
  50. }
  51. /* 从当前频率减速到目标频率所需的脉冲数(Q32.32 精度)。 */
  52. static uint64_t PlsrProfileDecelPulsesQ32(uint32_t frequencyHz,
  53. uint32_t targetHz,
  54. uint32_t slopeHzPerMs)
  55. {
  56. uint64_t numerator;
  57. uint64_t denominator;
  58. if (frequencyHz <= targetHz)
  59. {
  60. return 0UL;
  61. }
  62. numerator = (uint64_t)frequencyHz * (uint64_t)frequencyHz
  63. - (uint64_t)targetHz * (uint64_t)targetHz;
  64. denominator = 2000UL * (uint64_t)slopeHzPerMs;
  65. if (denominator == 0UL)
  66. {
  67. return 0UL;
  68. }
  69. return (numerator / denominator) * PLSR_PROFILE_Q32_ONE
  70. + ((numerator % denominator) * PLSR_PROFILE_Q32_ONE)
  71. / denominator;
  72. }
  73. /* 直线增量初始化。 */
  74. static void PlsrProfileInitLinearDelta(PLSR_PROFILE_STATE *state,
  75. uint32_t slopeHzPerMs,
  76. uint32_t refreshHz)
  77. {
  78. state->deltaPerStepQ32 = PlsrProfileSlopePerStepQ32(slopeHzPerMs,
  79. refreshHz);
  80. state->jerkPerStepQ32 = 0UL;
  81. state->curveStep = 0U;
  82. state->curveStepLimit = 0U;
  83. state->sPhase = 0U;
  84. }
  85. /* S 形/正弦增量初始化:增量先升后降(S形)或正弦半波。 */
  86. static void PlsrProfileInitCurveDelta(PLSR_PROFILE_STATE *state,
  87. uint32_t frequencyGapHz,
  88. uint32_t slopeHzPerMs,
  89. uint32_t refreshHz,
  90. uint8_t curveMode)
  91. {
  92. uint64_t linearPerStep = PlsrProfileSlopePerStepQ32(slopeHzPerMs,
  93. refreshHz);
  94. uint64_t integerPerStepHz;
  95. uint64_t rampSteps;
  96. uint64_t jerkQ32;
  97. integerPerStepHz = ((uint64_t)slopeHzPerMs * UINT64_C(1000))
  98. / (uint64_t)refreshHz;
  99. if (integerPerStepHz == 0UL)
  100. {
  101. integerPerStepHz = 1UL;
  102. }
  103. rampSteps = ((uint64_t)frequencyGapHz + integerPerStepHz - 1UL)
  104. / integerPerStepHz;
  105. if (curveMode == PLSR_PROFILE_CURVE_SINE)
  106. {
  107. /* 正弦:时间同直线,峰值增量 = 直线增量 * pi/2(面积匹配)。 */
  108. state->deltaPerStepQ32 = 0UL;
  109. state->jerkPerStepQ32 = 0UL;
  110. state->curveStep = 0U;
  111. state->curveStepLimit = (uint32_t)rampSteps;
  112. state->sPhase = 0U;
  113. return;
  114. }
  115. /* S 形:增量 0→峰值→0,总时间 2 倍直线时间。 */
  116. jerkQ32 = linearPerStep / rampSteps;
  117. state->deltaPerStepQ32 = 0UL;
  118. state->jerkPerStepQ32 = jerkQ32;
  119. state->curveStep = 0U;
  120. state->curveStepLimit = (uint32_t)(rampSteps * 2UL);
  121. state->sPhase = 0U;
  122. }
  123. /* 进入加速段(直线或曲线)。 */
  124. static void PlsrProfileBeginAccel(PLSR_PROFILE_STATE *state)
  125. {
  126. uint32_t gapHz;
  127. if (state->targetFrequencyHz <= state->frequencyQ32 >> 32U)
  128. {
  129. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  130. return;
  131. }
  132. if (state->curveMode == PLSR_PROFILE_CURVE_LINEAR)
  133. {
  134. PlsrProfileInitLinearDelta(state,
  135. state->accelSlopeHzPerMs,
  136. state->refreshHz);
  137. }
  138. else
  139. {
  140. gapHz = state->targetFrequencyHz
  141. - (uint32_t)(state->frequencyQ32 >> 32U);
  142. PlsrProfileInitCurveDelta(state,
  143. gapHz,
  144. state->accelSlopeHzPerMs,
  145. state->refreshHz,
  146. state->curveMode);
  147. }
  148. state->phase = PLSR_PROFILE_PHASE_ACCEL;
  149. }
  150. /* 进入减速段:减速到 decelTargetHz(默认=终止速度,降频时=新目标)。 */
  151. static void PlsrProfileBeginDecel(PLSR_PROFILE_STATE *state)
  152. {
  153. uint32_t gapHz;
  154. if (state->frequencyQ32 >> 32U <= state->decelTargetHz)
  155. {
  156. state->frequencyQ32 = PlsrProfileHzToQ32(state->decelTargetHz);
  157. if (state->decelTargetHz == state->stopFrequencyHz)
  158. {
  159. state->phase = PLSR_PROFILE_PHASE_DONE;
  160. }
  161. else
  162. {
  163. /* 降频到新目标:转匀速继续。 */
  164. state->targetFrequencyHz = state->decelTargetHz;
  165. state->decelTargetHz = state->stopFrequencyHz;
  166. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  167. }
  168. return;
  169. }
  170. if (state->curveMode == PLSR_PROFILE_CURVE_LINEAR)
  171. {
  172. PlsrProfileInitLinearDelta(state,
  173. state->decelSlopeHzPerMs,
  174. state->refreshHz);
  175. }
  176. else
  177. {
  178. gapHz = (uint32_t)(state->frequencyQ32 >> 32U)
  179. - state->decelTargetHz;
  180. PlsrProfileInitCurveDelta(state,
  181. gapHz,
  182. state->decelSlopeHzPerMs,
  183. state->refreshHz,
  184. state->curveMode);
  185. }
  186. state->phase = PLSR_PROFILE_PHASE_DECEL;
  187. }
  188. /* 曲线模式下推进增量(S形三角增量 / 正弦查表)。 */
  189. static uint64_t PlsrProfileAdvanceDelta(PLSR_PROFILE_STATE *state,
  190. uint64_t linearPerStepQ32)
  191. {
  192. uint64_t delta;
  193. if (state->curveMode == PLSR_PROFILE_CURVE_SINE)
  194. {
  195. uint32_t index = ((uint32_t)state->curveStep * 256U)
  196. / (uint32_t)state->curveStepLimit;
  197. if (index > 255U)
  198. {
  199. index = 255U;
  200. }
  201. delta = ((uint64_t)PlsrProfileSineTable[index]
  202. * linearPerStepQ32) / 65536UL;
  203. }
  204. else
  205. {
  206. if (state->sPhase == 0U)
  207. {
  208. state->deltaPerStepQ32 += state->jerkPerStepQ32;
  209. if ((state->curveStepLimit != 0U)
  210. && (state->curveStep >= state->curveStepLimit / 2U))
  211. {
  212. state->sPhase = 1U;
  213. }
  214. }
  215. else
  216. {
  217. if (state->deltaPerStepQ32 > state->jerkPerStepQ32)
  218. {
  219. state->deltaPerStepQ32 -= state->jerkPerStepQ32;
  220. }
  221. else
  222. {
  223. state->deltaPerStepQ32 = 0UL;
  224. }
  225. }
  226. delta = state->deltaPerStepQ32;
  227. }
  228. state->curveStep++;
  229. return delta;
  230. }
  231. PLSR_RESULT PlsrProfileStart(PLSR_PROFILE_STATE *state,
  232. const PLSR_PROFILE_REQUEST *request,
  233. int64_t pulses,
  234. uint32_t refreshHz)
  235. {
  236. uint32_t startHz;
  237. if ((state == NULL) || (request == NULL))
  238. {
  239. return PLSR_RESULT_INVALID_ARGUMENT;
  240. }
  241. if ((pulses <= 0) || (refreshHz == 0UL)
  242. || (request->targetFrequencyHz == 0UL))
  243. {
  244. return PLSR_RESULT_INVALID_ARGUMENT;
  245. }
  246. state->refreshHz = refreshHz;
  247. state->totalPulses = pulses;
  248. state->targetFrequencyHz = request->targetFrequencyHz;
  249. if (request->targetFrequencyHz > request->maxFrequencyHz)
  250. {
  251. state->targetFrequencyHz = request->maxFrequencyHz;
  252. }
  253. state->startFrequencyHz = request->startFrequencyHz;
  254. state->stopFrequencyHz = request->stopFrequencyHz;
  255. state->decelTargetHz = request->stopFrequencyHz;
  256. state->accelSlopeHzPerMs = request->accelSlopeHzPerMs;
  257. state->decelSlopeHzPerMs = request->decelSlopeHzPerMs;
  258. state->curveMode = request->curveMode;
  259. startHz = request->startFrequencyHz;
  260. if (startHz > state->targetFrequencyHz)
  261. {
  262. startHz = state->targetFrequencyHz;
  263. }
  264. state->frequencyQ32 = PlsrProfileHzToQ32(startHz);
  265. state->emittedPulsesQ32 = 0UL;
  266. state->phase = PLSR_PROFILE_PHASE_ACCEL;
  267. state->started = 1U;
  268. if (startHz >= state->targetFrequencyHz)
  269. {
  270. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  271. }
  272. else if (request->accelSlopeHzPerMs == 0UL)
  273. {
  274. state->frequencyQ32 = PlsrProfileHzToQ32(state->targetFrequencyHz);
  275. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  276. }
  277. else
  278. {
  279. PlsrProfileBeginAccel(state);
  280. }
  281. return PLSR_RESULT_OK;
  282. }
  283. PLSR_RESULT PlsrProfileStep(PLSR_PROFILE_STATE *state,
  284. uint32_t *frequencyHz,
  285. uint8_t *completed)
  286. {
  287. uint64_t emittedThisStep;
  288. uint64_t remainingQ32;
  289. uint64_t decelNeeded;
  290. uint64_t linearPerStepQ32;
  291. uint64_t deltaQ32;
  292. uint32_t currentHz;
  293. if ((state == NULL) || (frequencyHz == NULL) || (completed == NULL))
  294. {
  295. return PLSR_RESULT_INVALID_ARGUMENT;
  296. }
  297. *completed = 0U;
  298. if (state->phase == PLSR_PROFILE_PHASE_DONE)
  299. {
  300. *frequencyHz = 0U;
  301. *completed = 1U;
  302. return PLSR_RESULT_OK;
  303. }
  304. linearPerStepQ32 = PlsrProfileSlopePerStepQ32(
  305. (state->phase == PLSR_PROFILE_PHASE_ACCEL)
  306. ? state->accelSlopeHzPerMs
  307. : state->decelSlopeHzPerMs,
  308. state->refreshHz);
  309. switch (state->phase)
  310. {
  311. case PLSR_PROFILE_PHASE_ACCEL:
  312. deltaQ32 = PlsrProfileAdvanceDelta(state, linearPerStepQ32);
  313. state->frequencyQ32 += deltaQ32;
  314. if ((state->frequencyQ32
  315. >= PlsrProfileHzToQ32(state->targetFrequencyHz))
  316. || ((state->curveMode != PLSR_PROFILE_CURVE_LINEAR)
  317. && (state->curveStep >= state->curveStepLimit)))
  318. {
  319. state->frequencyQ32 =
  320. PlsrProfileHzToQ32(state->targetFrequencyHz);
  321. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  322. }
  323. break;
  324. case PLSR_PROFILE_PHASE_CRUISE:
  325. /* 剩余脉冲不足以按当前频率完成减速时开始减速(Q32 精度)。 */
  326. remainingQ32 = PlsrProfileHzToQ32(
  327. (uint32_t)state->totalPulses)
  328. - state->emittedPulsesQ32;
  329. decelNeeded = PlsrProfileDecelPulsesQ32(
  330. (uint32_t)(state->frequencyQ32 >> 32U),
  331. state->stopFrequencyHz,
  332. state->decelSlopeHzPerMs);
  333. if (remainingQ32 <= decelNeeded)
  334. {
  335. PlsrProfileBeginDecel(state);
  336. }
  337. break;
  338. case PLSR_PROFILE_PHASE_DECEL:
  339. deltaQ32 = PlsrProfileAdvanceDelta(state, linearPerStepQ32);
  340. state->frequencyQ32 -= deltaQ32;
  341. if (state->frequencyQ32
  342. <= PlsrProfileHzToQ32(state->decelTargetHz))
  343. {
  344. state->frequencyQ32 =
  345. PlsrProfileHzToQ32(state->decelTargetHz);
  346. if (state->decelTargetHz == state->stopFrequencyHz)
  347. {
  348. state->phase = PLSR_PROFILE_PHASE_DONE;
  349. }
  350. else
  351. {
  352. /* 降频到新目标:转匀速继续。 */
  353. state->targetFrequencyHz = state->decelTargetHz;
  354. state->decelTargetHz = state->stopFrequencyHz;
  355. state->phase = PLSR_PROFILE_PHASE_CRUISE;
  356. }
  357. }
  358. break;
  359. default:
  360. break;
  361. }
  362. /* 发射本步脉冲:频率(Hz) / 刷新率。 */
  363. currentHz = (uint32_t)(state->frequencyQ32 >> 32U);
  364. emittedThisStep = state->frequencyQ32 / (uint64_t)state->refreshHz;
  365. if ((state->emittedPulsesQ32 + emittedThisStep)
  366. >= PlsrProfileHzToQ32((uint32_t)state->totalPulses))
  367. {
  368. state->emittedPulsesQ32 =
  369. PlsrProfileHzToQ32((uint32_t)state->totalPulses);
  370. state->phase = PLSR_PROFILE_PHASE_DONE;
  371. }
  372. else
  373. {
  374. state->emittedPulsesQ32 += emittedThisStep;
  375. }
  376. *frequencyHz = currentHz;
  377. if (state->phase == PLSR_PROFILE_PHASE_DONE)
  378. {
  379. *completed = 1U;
  380. *frequencyHz = 0U;
  381. }
  382. return PLSR_RESULT_OK;
  383. }
  384. PLSR_RESULT PlsrProfileRetarget(PLSR_PROFILE_STATE *state,
  385. uint32_t newTargetFrequencyHz)
  386. {
  387. uint32_t currentHz;
  388. if (state == NULL)
  389. {
  390. return PLSR_RESULT_INVALID_ARGUMENT;
  391. }
  392. if (newTargetFrequencyHz == 0UL)
  393. {
  394. return PLSR_RESULT_INVALID_ARGUMENT;
  395. }
  396. currentHz = (uint32_t)(state->frequencyQ32 >> 32U);
  397. if (newTargetFrequencyHz == state->targetFrequencyHz)
  398. {
  399. return PLSR_RESULT_OK;
  400. }
  401. state->targetFrequencyHz = newTargetFrequencyHz;
  402. if (newTargetFrequencyHz > currentHz)
  403. {
  404. /* 升频:加速/匀速 → 加速;减速中 → 取消减速转加速。 */
  405. if ((state->phase == PLSR_PROFILE_PHASE_DECEL)
  406. || (state->phase == PLSR_PROFILE_PHASE_CRUISE)
  407. || (state->phase == PLSR_PROFILE_PHASE_DONE))
  408. {
  409. PlsrProfileBeginAccel(state);
  410. }
  411. }
  412. else
  413. {
  414. /* 降频:先减速到新目标,再转匀速继续(最终仍减速到终止速度)。 */
  415. if ((state->phase == PLSR_PROFILE_PHASE_ACCEL)
  416. || (state->phase == PLSR_PROFILE_PHASE_CRUISE))
  417. {
  418. state->decelTargetHz = newTargetFrequencyHz;
  419. PlsrProfileBeginDecel(state);
  420. }
  421. }
  422. return PLSR_RESULT_OK;
  423. }
  424. PLSR_RESULT PlsrProfilePlan(const PLSR_PROFILE_REQUEST *request,
  425. int64_t pulses,
  426. PLSR_PROFILE_PLAN *plan)
  427. {
  428. double target;
  429. double start;
  430. double stop;
  431. double accelSlope;
  432. double decelSlope;
  433. double accelTime;
  434. double decelTime;
  435. double accelPulses;
  436. double decelPulses;
  437. double cruisePulses;
  438. double cruiseTime;
  439. double peak;
  440. if ((request == NULL) || (plan == NULL) || (pulses <= 0))
  441. {
  442. return PLSR_RESULT_INVALID_ARGUMENT;
  443. }
  444. (void)memset(plan, 0, sizeof(*plan));
  445. target = (double)request->targetFrequencyHz;
  446. if (target > (double)request->maxFrequencyHz)
  447. {
  448. target = (double)request->maxFrequencyHz;
  449. }
  450. start = (double)request->startFrequencyHz;
  451. if (start > target)
  452. {
  453. start = target;
  454. }
  455. stop = (double)request->stopFrequencyHz;
  456. accelSlope = (double)request->accelSlopeHzPerMs;
  457. decelSlope = (double)request->decelSlopeHzPerMs;
  458. accelTime = (target > start) ? (target - start) / accelSlope : 0.0;
  459. decelTime = (target > stop) ? (target - stop) / decelSlope : 0.0;
  460. accelPulses = (start + target) * accelTime / 2000.0;
  461. decelPulses = (target + stop) * decelTime / 2000.0;
  462. if ((accelPulses + decelPulses) >= (double)pulses)
  463. {
  464. /* 三角曲线:求峰值频率。 */
  465. double sum = (double)pulses * 1000.0
  466. + start * start / (2.0 * accelSlope)
  467. + stop * stop / (2.0 * decelSlope);
  468. double denom = 1.0 / (2.0 * accelSlope)
  469. + 1.0 / (2.0 * decelSlope);
  470. peak = (denom > 0.0) ? sqrt(sum / denom) : target;
  471. accelTime = (peak > start) ? (peak - start) / accelSlope : 0.0;
  472. decelTime = (peak > stop) ? (peak - stop) / decelSlope : 0.0;
  473. accelPulses = (start + peak) * accelTime / 2000.0;
  474. decelPulses = (peak + stop) * decelTime / 2000.0;
  475. plan->peakFrequencyHz = (uint32_t)peak;
  476. plan->triangular = 1U;
  477. }
  478. else
  479. {
  480. cruisePulses = (double)pulses - accelPulses - decelPulses;
  481. cruiseTime = (target > 0.0) ? cruisePulses * 1000.0 / target : 0.0;
  482. plan->cruiseTimeMs = (uint32_t)cruiseTime;
  483. plan->peakFrequencyHz = (uint32_t)target;
  484. plan->triangular = 0U;
  485. }
  486. plan->accelTimeMs = (uint32_t)accelTime;
  487. plan->decelTimeMs = (uint32_t)decelTime;
  488. plan->totalTimeMs = plan->accelTimeMs + plan->cruiseTimeMs
  489. + plan->decelTimeMs;
  490. plan->totalPulses = pulses;
  491. return PLSR_RESULT_OK;
  492. }