calib_piecewise_linear.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. /**@Doxygen风格注释
  2. * @file calib_piecewise_linear.c
  3. * @brief 电容值到油水比例的标定模块(分段线性插值)
  4. * @details
  5. * 本模块用于将电容传感器测量的电容值(单位:pF)转换为对应的油水混合比例百分比(单位:%)。
  6. * 采用 **分段线性插值法** 实现高精度估算。
  7. *
  8. * @section 功能特性
  9. * - 固定11个标定点,百分比范围为90% ~ 100%,每隔1%一个点
  10. * - 每个百分比点对应一个电容值,按降序排列(电容越小表示油越多)
  11. * - 使用线性插值法对任意电容值进行估算
  12. * - 超出标定范围的电容值自动限幅到0%或100%
  13. * - 支持结构体打包,将 float 电容值转换为 uint32_t,用于Flash存储
  14. *
  15. * @section 数据结构
  16. * - @c CalibPoints_t : 存储11个电容标定点及magic码
  17. * - @c uint_CalibPoints_t : 与CalibPoints_t等价的整型形式(用于Flash存取)
  18. * - @c Calib_residual_oil_t : 存储余油电容/压力/高度标定(与主功能无直接关系)
  19. * - @c Calib_rod_t : 阀杆电压标定(与主功能无直接关系)
  20. *
  21. * @section 使用示例
  22. * @code
  23. * Load_Default_CalibPoints(); // 加载默认电容标定点
  24. * float cap = read_sensor_capacitance(); // 读取电容值
  25. * float percent = Estimate_Percentage_piecewise(cap); // 转换为油水百分比
  26. * @endcode
  27. *
  28. * @note
  29. * - 标定点对应的百分比是固定的,不在结构体中存储,而是以 const 数组形式保存在代码段
  30. * - 所有标定点应按 cap 值降序排列(从90%到100%)
  31. *
  32. * @author
  33. * 开发者:
  34. *
  35. * @date 2025年8月
  36. */
  37. #include "Callback.h"
  38. #include "calib_piecewise_linear.h"
  39. #include "FLASH.h"
  40. #include "main.h"
  41. #include <string.h>
  42. CalibPoints_t g_calibPoints; // 油水检测电容float
  43. Calib_residual_oil_t g_Calibresidualheight; // 余油检测电容值压力值高度值float
  44. OilType g_oil_type = OIL_95; // 油品
  45. Calib_rod_t g_Calibrodvol; // 阀杆电压值
  46. // ========================
  47. // 标定油水数据点(按百分比升序排列)
  48. // ========================
  49. const float calib_cap_values[CALIB_POINT_NUM] = { // 电容值(pf)
  50. 54.993f, 54.986f, 54.979f, 54.971f, 54.962f, 54.955f, 54.947f, 54.939f, 54.925f, 54.911f, 54.901f};
  51. const float calib_percent_values[CALIB_POINT_NUM] = { // 百分比%
  52. 90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, 96.0f, 97.0f, 98.0f, 99.0f, 100.0f};
  53. // 初始化默认值函数
  54. void Load_Default_CalibPoints(void)
  55. {
  56. for (int i = 0; i < CALIB_POINT_NUM; i++) {
  57. g_calibPoints.cap_values[i] = calib_cap_values[i];
  58. }
  59. }
  60. // ========================
  61. // 分段线性插值估算百分比(带限幅)
  62. // ========================
  63. float Estimate_Percentage_piecewise(float cap)
  64. {
  65. const float *caps = g_calibPoints.cap_values;
  66. const float *percents = calib_percent_values;
  67. // 边界处理
  68. if (cap <= caps[CALIB_POINT_NUM - 1]) return 100.0f;
  69. if (cap >= caps[0]) return 90.0f;
  70. for (int i = 0; i < CALIB_POINT_NUM - 1; i++) {
  71. float cap_high = caps[i];
  72. float cap_low = caps[i + 1];
  73. if (cap <= cap_high && cap >= cap_low) {
  74. float percent_high = percents[i];
  75. float percent_low = percents[i + 1];
  76. float percent = percent_low + (cap - cap_low) * (percent_high - percent_low) / (cap_high - cap_low);
  77. // 限幅
  78. if (percent < 0.0f) percent = 0.0f;
  79. if (percent > 100.0f) percent = 100.0f;
  80. return percent;
  81. }
  82. }
  83. return 0.0f;
  84. }