Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.
 
 
 
 
 
 

430 рядки
14 KiB

  1. #include "plsr_profile.h"
  2. #include <stdio.h>
  3. #include <string.h>
  4. static int TestFailures;
  5. static int TestChecks;
  6. #define CHECK(condition) \
  7. do \
  8. { \
  9. TestChecks++; \
  10. if (!(condition)) \
  11. { \
  12. TestFailures++; \
  13. (void)printf("FAIL line %d: %s\n", __LINE__, #condition); \
  14. } \
  15. } while (0)
  16. /* 跑完一段曲线,返回实际脉冲数与峰值频率。 */
  17. static void RunProfile(const PLSR_PROFILE_REQUEST *request,
  18. int64_t pulses,
  19. uint32_t refreshHz,
  20. uint32_t retargetHz,
  21. uint32_t retargetAfterSteps,
  22. int64_t *actualPulses,
  23. uint32_t *peakHz,
  24. int64_t *steps)
  25. {
  26. PLSR_PROFILE_STATE state;
  27. uint32_t frequency = 0U;
  28. uint8_t completed = 0U;
  29. int64_t stepCount = 0;
  30. uint32_t peak = 0U;
  31. CHECK(PlsrProfileStart(&state, request, pulses, refreshHz)
  32. == PLSR_RESULT_OK);
  33. while ((completed == 0U) && (stepCount < 5000000))
  34. {
  35. (void)PlsrProfileStep(&state, &frequency, &completed);
  36. if (frequency > peak)
  37. {
  38. peak = frequency;
  39. }
  40. stepCount++;
  41. if ((retargetHz != 0U) && (stepCount == retargetAfterSteps))
  42. {
  43. CHECK(PlsrProfileRetarget(&state, retargetHz) == PLSR_RESULT_OK);
  44. }
  45. }
  46. CHECK(completed != 0U);
  47. *actualPulses = (int64_t)(state.emittedPulsesQ32 >> 32U);
  48. *peakHz = peak;
  49. *steps = stepCount;
  50. }
  51. static PLSR_PROFILE_REQUEST MakeRequest(uint32_t targetHz,
  52. uint32_t startHz,
  53. uint32_t stopHz,
  54. uint32_t accelSlope,
  55. uint32_t decelSlope,
  56. uint8_t curveMode)
  57. {
  58. PLSR_PROFILE_REQUEST request;
  59. (void)memset(&request, 0, sizeof(request));
  60. request.targetFrequencyHz = targetHz;
  61. request.startFrequencyHz = startHz;
  62. request.stopFrequencyHz = stopHz;
  63. request.maxFrequencyHz = 100000UL;
  64. request.accelSlopeHzPerMs = accelSlope;
  65. request.decelSlopeHzPerMs = decelSlope;
  66. request.curveMode = curveMode;
  67. return request;
  68. }
  69. static void TestTrapezoid(void)
  70. {
  71. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  72. int64_t pulses;
  73. uint32_t peak;
  74. int64_t steps;
  75. RunProfile(&request, 20000, 1000U, 0U, 0, &pulses, &peak, &steps);
  76. CHECK(pulses == 20000);
  77. CHECK(peak == 10000U);
  78. CHECK(steps > 2000);
  79. }
  80. static void TestTriangle(void)
  81. {
  82. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  83. int64_t pulses;
  84. uint32_t peak;
  85. int64_t steps;
  86. /* 脉冲太少:永远到不了目标频率,三角曲线。 */
  87. RunProfile(&request, 100, 1000U, 0U, 0, &pulses, &peak, &steps);
  88. CHECK(pulses == 100);
  89. CHECK(peak < 10000U);
  90. CHECK(peak > 0U);
  91. }
  92. static void TestStartStopSpeed(void)
  93. {
  94. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 1000U, 500U,
  95. 100U, 80U, 0U);
  96. int64_t pulses;
  97. uint32_t peak;
  98. int64_t steps;
  99. RunProfile(&request, 50000, 1000U, 0U, 0, &pulses, &peak, &steps);
  100. CHECK(pulses == 50000);
  101. CHECK(peak == 10000U);
  102. }
  103. static void TestSCurve(void)
  104. {
  105. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 1U);
  106. int64_t pulses;
  107. uint32_t peak;
  108. int64_t steps;
  109. RunProfile(&request, 20000, 1000U, 0U, 0, &pulses, &peak, &steps);
  110. CHECK(pulses == 20000);
  111. CHECK(peak == 10000U);
  112. CHECK(steps > 2000);
  113. }
  114. static void TestSine(void)
  115. {
  116. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 2U);
  117. int64_t pulses;
  118. uint32_t peak;
  119. int64_t steps;
  120. RunProfile(&request, 20000, 1000U, 0U, 0, &pulses, &peak, &steps);
  121. CHECK(pulses == 20000);
  122. CHECK(peak == 10000U);
  123. }
  124. static void TestRetargetUp(void)
  125. {
  126. PLSR_PROFILE_REQUEST request = MakeRequest(5000U, 0U, 0U, 100U, 100U, 0U);
  127. int64_t pulses;
  128. uint32_t peak;
  129. int64_t steps;
  130. /* 运行中升频到 10000:平滑过渡且总脉冲精确。 */
  131. RunProfile(&request, 30000, 1000U, 10000U, 500, &pulses, &peak, &steps);
  132. CHECK(pulses == 30000);
  133. CHECK(peak == 10000U);
  134. }
  135. static void TestRetargetDown(void)
  136. {
  137. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  138. int64_t pulses;
  139. uint32_t peak;
  140. int64_t steps;
  141. /* 运行中降频到 3000:先减速到新目标再匀速,总脉冲精确。 */
  142. RunProfile(&request, 30000, 1000U, 3000U, 500, &pulses, &peak, &steps);
  143. CHECK(pulses == 30000);
  144. CHECK(peak == 10000U);
  145. CHECK(steps > 600);
  146. }
  147. static void TestNoAccel(void)
  148. {
  149. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 0U, 0U, 0U);
  150. int64_t pulses;
  151. uint32_t peak;
  152. int64_t steps;
  153. RunProfile(&request, 5000, 1000U, 0U, 0, &pulses, &peak, &steps);
  154. CHECK(pulses == 5000);
  155. CHECK(peak == 10000U);
  156. CHECK(steps == 500);
  157. }
  158. static void TestSubMillisecondRefresh(void)
  159. {
  160. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  161. int64_t pulses;
  162. uint32_t peak;
  163. int64_t steps;
  164. /* 0.1ms 刷新:精度更高,步数是 1ms 的约 10 倍。 */
  165. RunProfile(&request, 20000, 10000U, 0U, 0, &pulses, &peak, &steps);
  166. CHECK(pulses == 20000);
  167. CHECK(peak == 10000U);
  168. CHECK(steps > 20000);
  169. }
  170. static void TestSinglePulse(void)
  171. {
  172. PLSR_PROFILE_REQUEST request = MakeRequest(1000U, 0U, 0U, 100U, 100U, 0U);
  173. int64_t pulses;
  174. uint32_t peak;
  175. int64_t steps;
  176. RunProfile(&request, 1, 1000U, 0U, 0, &pulses, &peak, &steps);
  177. CHECK(pulses == 1);
  178. CHECK(peak <= 1000U);
  179. }
  180. static void TestHighFrequency(void)
  181. {
  182. PLSR_PROFILE_REQUEST request = MakeRequest(100000U, 0U, 0U,
  183. 10000U, 10000U, 0U);
  184. int64_t pulses;
  185. uint32_t peak;
  186. int64_t steps;
  187. RunProfile(&request, 1000000, 1000U, 0U, 0, &pulses, &peak, &steps);
  188. CHECK(pulses == 1000000);
  189. CHECK(peak == 100000U);
  190. }
  191. static void TestArgumentValidation(void)
  192. {
  193. PLSR_PROFILE_STATE state;
  194. PLSR_PROFILE_REQUEST request = MakeRequest(1000U, 0U, 0U, 100U, 100U, 0U);
  195. uint32_t frequency;
  196. uint8_t completed;
  197. CHECK(PlsrProfileStart(NULL, &request, 100, 1000U)
  198. == PLSR_RESULT_INVALID_ARGUMENT);
  199. CHECK(PlsrProfileStart(&state, NULL, 100, 1000U)
  200. == PLSR_RESULT_INVALID_ARGUMENT);
  201. CHECK(PlsrProfileStart(&state, &request, 0, 1000U)
  202. == PLSR_RESULT_INVALID_ARGUMENT);
  203. CHECK(PlsrProfileStart(&state, &request, 100, 0U)
  204. == PLSR_RESULT_INVALID_ARGUMENT);
  205. request.targetFrequencyHz = 0U;
  206. CHECK(PlsrProfileStart(&state, &request, 100, 1000U)
  207. == PLSR_RESULT_INVALID_ARGUMENT);
  208. request.targetFrequencyHz = 1000U;
  209. CHECK(PlsrProfileStep(NULL, &frequency, &completed)
  210. == PLSR_RESULT_INVALID_ARGUMENT);
  211. CHECK(PlsrProfileStep(&state, NULL, &completed)
  212. == PLSR_RESULT_INVALID_ARGUMENT);
  213. CHECK(PlsrProfileStep(&state, &frequency, NULL)
  214. == PLSR_RESULT_INVALID_ARGUMENT);
  215. CHECK(PlsrProfileRetarget(NULL, 2000U) == PLSR_RESULT_INVALID_ARGUMENT);
  216. CHECK(PlsrProfileRetarget(&state, 0U) == PLSR_RESULT_INVALID_ARGUMENT);
  217. }
  218. static void TestSyncPulses(void)
  219. {
  220. /* 校准虚拟计数到硬件计数:模拟硬件滞后 38 个脉冲(预装载滞后),
  221. * 校准后 DONE 判定与硬件同步,段尾不再冻结频率补发。 */
  222. PLSR_PROFILE_REQUEST request = MakeRequest(1000U, 0U, 0U, 100U, 100U, 0U);
  223. PLSR_PROFILE_STATE state;
  224. uint32_t frequency;
  225. uint8_t completed;
  226. int i;
  227. CHECK(PlsrProfileStart(&state, &request, 500, 1000U) == PLSR_RESULT_OK);
  228. /* 自然推进 100 步:虚拟计数已超前(未校准)。 */
  229. for (i = 0; i < 100; i++)
  230. {
  231. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  232. == PLSR_RESULT_OK);
  233. }
  234. CHECK(completed == 0U);
  235. /* 校准到硬件计数(硬件只发了 400 个)——虚拟被拉回。 */
  236. PlsrProfileSyncPulses(&state, 400U);
  237. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  238. == PLSR_RESULT_OK);
  239. CHECK(completed == 0U); /* 400+本步增量 < 500,不提前 DONE */
  240. /* 校准到 499(还差 1 个):下一步 DONE。 */
  241. PlsrProfileSyncPulses(&state, 499U);
  242. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  243. == PLSR_RESULT_OK);
  244. CHECK(completed != 0U);
  245. CHECK(frequency == 0U);
  246. }
  247. static void TestInitialOutputFrequency(void)
  248. {
  249. PLSR_PROFILE_REQUEST request = MakeRequest(1000U, 0U, 0U,
  250. 10U, 10U, 0U);
  251. PLSR_PROFILE_STATE state;
  252. uint32_t frequency;
  253. uint8_t completed;
  254. CHECK(PlsrProfileStart(&state, &request, 500, 1000U)
  255. == PLSR_RESULT_OK);
  256. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  257. == PLSR_RESULT_OK);
  258. CHECK(frequency == 10U);
  259. /* 10Hz 以10Hz/ms连续加速,首脉冲末约141Hz,
  260. * 首周期等效频率约75Hz(约13.3ms),不再等100ms。 */
  261. CHECK(PlsrProfileGetInitialOutputFrequency(&state) == 75U);
  262. request.targetFrequencyHz = 20U;
  263. request.maxFrequencyHz = 20U;
  264. CHECK(PlsrProfileStart(&state, &request, 50, 1000U)
  265. == PLSR_RESULT_OK);
  266. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  267. == PLSR_RESULT_OK);
  268. CHECK(PlsrProfileGetInitialOutputFrequency(&state) == 19U);
  269. state.curveMode = PLSR_PROFILE_CURVE_S;
  270. CHECK(PlsrProfileGetInitialOutputFrequency(&state) == frequency);
  271. CHECK(PlsrProfileGetInitialOutputFrequency(NULL) == 0U);
  272. }
  273. static void TestBrakingOutputFrequency(void)
  274. {
  275. PLSR_PROFILE_REQUEST request = MakeRequest(2000U, 0U, 0U,
  276. 10U, 10U, 0U);
  277. PLSR_PROFILE_STATE state;
  278. CHECK(PlsrProfileStart(&state, &request, 1000, 1000U)
  279. == PLSR_RESULT_OK);
  280. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 201U) == 2000U);
  281. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, UINT64_MAX)
  282. == 2000U);
  283. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 5U) == 299U);
  284. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 4U) == 263U);
  285. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 3U) == 222U);
  286. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 2U) == 170U);
  287. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 1U) == 70U);
  288. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 0U) == 0U);
  289. CHECK(PlsrProfileGetBrakingOutputFrequency(NULL, 1U) == 0U);
  290. state.curveMode = PLSR_PROFILE_CURVE_S;
  291. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, 1U) == 2000U);
  292. /* 极端参数也不得让制动距离乘法溢出。 */
  293. state.curveMode = PLSR_PROFILE_CURVE_LINEAR;
  294. state.targetFrequencyHz = UINT32_MAX;
  295. state.stopFrequencyHz = 0U;
  296. state.decelSlopeHzPerMs = UINT32_MAX;
  297. CHECK(PlsrProfileGetBrakingOutputFrequency(&state, UINT64_MAX)
  298. == UINT32_MAX);
  299. }
  300. static void TestControlledStop(void)
  301. {
  302. PLSR_PROFILE_REQUEST request = MakeRequest(1000U, 1000U, 0U,
  303. 10U, 10U, 0U);
  304. PLSR_PROFILE_STATE state;
  305. uint32_t frequency = 0U;
  306. uint8_t completed = 0U;
  307. int step;
  308. CHECK(PlsrProfileStart(&state, &request, 10000, 1000U)
  309. == PLSR_RESULT_OK);
  310. CHECK(state.phase == PLSR_PROFILE_PHASE_CRUISE);
  311. CHECK(PlsrProfileRequestStop(&state) == PLSR_RESULT_OK);
  312. CHECK(state.phase == PLSR_PROFILE_PHASE_DECEL);
  313. for (step = 0; (step < 110) && (completed == 0U); step++)
  314. {
  315. CHECK(PlsrProfileStep(&state, &frequency, &completed)
  316. == PLSR_RESULT_OK);
  317. }
  318. CHECK(completed != 0U);
  319. CHECK(frequency == 0U);
  320. CHECK(state.phase == PLSR_PROFILE_PHASE_DONE);
  321. request.decelSlopeHzPerMs = 0U;
  322. CHECK(PlsrProfileStart(&state, &request, 10000, 1000U)
  323. == PLSR_RESULT_OK);
  324. CHECK(PlsrProfileRequestStop(&state) == PLSR_RESULT_OK);
  325. CHECK(state.phase == PLSR_PROFILE_PHASE_DONE);
  326. CHECK(PlsrProfileRequestStop(NULL) == PLSR_RESULT_INVALID_ARGUMENT);
  327. }
  328. static void TestPlan(void)
  329. {
  330. PLSR_PROFILE_REQUEST request = MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  331. PLSR_PROFILE_PLAN plan;
  332. PLSR_PROFILE_REQUEST triangleRequest =
  333. MakeRequest(10000U, 0U, 0U, 100U, 100U, 0U);
  334. CHECK(PlsrProfilePlan(&request, 20000, &plan) == PLSR_RESULT_OK);
  335. CHECK(plan.accelTimeMs == 100U);
  336. CHECK(plan.decelTimeMs == 100U);
  337. CHECK(plan.triangular == 0U);
  338. CHECK(plan.peakFrequencyHz == 10000U);
  339. CHECK(plan.cruiseTimeMs > 0U);
  340. CHECK(PlsrProfilePlan(&triangleRequest, 100, &plan) == PLSR_RESULT_OK);
  341. CHECK(plan.triangular != 0U);
  342. CHECK(plan.peakFrequencyHz < 10000U);
  343. CHECK(plan.accelTimeMs > 0U);
  344. CHECK(PlsrProfilePlan(NULL, 100, &plan) == PLSR_RESULT_INVALID_ARGUMENT);
  345. CHECK(PlsrProfilePlan(&request, 0, &plan) == PLSR_RESULT_INVALID_ARGUMENT);
  346. CHECK(PlsrProfilePlan(&request, 100, NULL) == PLSR_RESULT_INVALID_ARGUMENT);
  347. }
  348. int main(void)
  349. {
  350. TestTrapezoid();
  351. TestTriangle();
  352. TestStartStopSpeed();
  353. TestSCurve();
  354. TestSine();
  355. TestRetargetUp();
  356. TestRetargetDown();
  357. TestNoAccel();
  358. TestSubMillisecondRefresh();
  359. TestSinglePulse();
  360. TestHighFrequency();
  361. TestArgumentValidation();
  362. TestSyncPulses();
  363. TestInitialOutputFrequency();
  364. TestBrakingOutputFrequency();
  365. TestControlledStop();
  366. TestPlan();
  367. if (TestFailures != 0)
  368. {
  369. (void)printf("FAIL: %d of %d PLSR profile checks failed\n",
  370. TestFailures,
  371. TestChecks);
  372. return 1;
  373. }
  374. (void)printf("PASS: %d PLSR profile checks\n", TestChecks);
  375. return 0;
  376. }