/**@Doxygen风格注释
 * @file calib_piecewise_linear.c
 * @brief 电容值到油水比例的标定模块（分段线性插值）
 * @details
 * 本模块用于将电容传感器测量的电容值（单位：pF）转换为对应的油水混合比例百分比（单位：%）。
 * 采用 **分段线性插值法** 实现高精度估算。
 *
 * @section 功能特性
 * - 固定11个标定点，百分比范围为90% ~ 100%，每隔1%一个点
 * - 每个百分比点对应一个电容值，按降序排列（电容越小表示油越多）
 * - 使用线性插值法对任意电容值进行估算
 * - 超出标定范围的电容值自动限幅到0%或100%
 * - 支持结构体打包，将 float 电容值转换为 uint32_t，用于Flash存储
 *
 * @section 数据结构
 * - @c CalibPoints_t : 存储11个电容标定点及magic码
 * - @c uint_CalibPoints_t : 与CalibPoints_t等价的整型形式（用于Flash存取）
 * - @c Calib_residual_oil_t : 存储余油电容/压力/高度标定（与主功能无直接关系）
 * - @c Calib_rod_t : 阀杆电压标定（与主功能无直接关系）
 *
 * @section 使用示例
 * @code
 * Load_Default_CalibPoints();             // 加载默认电容标定点
 * float cap = read_sensor_capacitance();  // 读取电容值
 * float percent = Estimate_Percentage_piecewise(cap); // 转换为油水百分比
 * @endcode
 *
 * @note
 * - 标定点对应的百分比是固定的，不在结构体中存储，而是以 const 数组形式保存在代码段
 * - 所有标定点应按 cap 值降序排列（从90%到100%）
 *
 * @author
 * 开发者：
 *
 * @date 2025年8月
 */

#include "Callback.h"
#include "calib_piecewise_linear.h"
#include "FLASH.h"
#include "main.h"
#include <string.h>

CalibPoints_t g_calibPoints; 			// 油水检测电容float
Calib_residual_oil_t g_Calibresidualheight;	// 余油检测电容值压力值高度值float
OilType g_oil_type = OIL_95; // 油品
Calib_rod_t g_Calibrodvol; // 阀杆电压值

// ========================
// 标定油水数据点（按百分比升序排列）
// ========================
const float calib_cap_values[CALIB_POINT_NUM] = { // 电容值（pf）
    54.993f, 54.986f, 54.979f, 54.971f, 54.962f, 54.955f, 54.947f, 54.939f, 54.925f, 54.911f, 54.901f};

const float calib_percent_values[CALIB_POINT_NUM] = { // 百分比%
    90.0f, 91.0f, 92.0f, 93.0f, 94.0f, 95.0f, 96.0f, 97.0f, 98.0f, 99.0f, 100.0f};

// 初始化默认值函数
void Load_Default_CalibPoints(void)
{
    for (int i = 0; i < CALIB_POINT_NUM; i++) {
        g_calibPoints.cap_values[i] = calib_cap_values[i];
    }
}

// ========================
// 分段线性插值估算百分比（带限幅）
// ========================
float Estimate_Percentage_piecewise(float cap)
{
    const float *caps = g_calibPoints.cap_values;
		const float *percents = calib_percent_values;
	
    // 边界处理
    if (cap <= caps[CALIB_POINT_NUM - 1]) return 100.0f;
    if (cap >= caps[0]) return 90.0f;

    for (int i = 0; i < CALIB_POINT_NUM - 1; i++) {
        float cap_high = caps[i];
        float cap_low  = caps[i + 1];

        if (cap <= cap_high && cap >= cap_low) {
            float percent_high = percents[i];
            float percent_low  = percents[i + 1];

            float percent = percent_low + (cap - cap_low) * (percent_high - percent_low) / (cap_high - cap_low);

            // 限幅
            if (percent < 0.0f) percent = 0.0f;
            if (percent > 100.0f) percent = 100.0f;
            return percent;
        }
    }

    return 0.0f;
}


