/*
 * @Date: 2025-07-04 13:05:24
 * @Author: mypx
 * @LastEditors: mypx mypx_coder@163.com
 * @LastEditTime: 2025-07-10 13:28:55
 * @FilePath: pt100x.c
 * @Description: 
 * Copyright (c) 2025 by mypx, All Rights Reserved.
 */
#include "pt100x.h"
#include <math.h>

/* 
 * Low temperature region (T < 0°C):
 * R(T) = R0(1 + A*T + B*T^2 + C*(T - R0)T^3)
 * High temperature region (T >= 0°C):
 * R(T) = R0(1 + A*T + B*T^2)
*/
#define A 3.9083e-3
#define B -5.775e-7
#define C -4.183e-12

#define PT100_R0  100
#define PT1000_R0 1000

/**
 * @brief Calculate the temperature based on the resistance value of a PT100 
 *        platinum resistor (precise calculation).
 * @param resistance Measured resistance value (Ω).
 * @param ptType Type of the PT sensor (PT100 or PT1000).
 * @return Temperature value (°C), returns NaN if the resistance value is invalid.
 */
double pt_precise_temperature(double resistance, PtType ptType)
{
    double R0 = (ptType == PT100) ? PT100_R0 : PT1000_R0;

    if (resistance < R0)
    {
        // Build the cubic equation: a*T³ + b*T² + c*T + d = 0
        double a = C * R0;
        double b = B - 100 * C;
        double c = A;
        double d = 1 - resistance / R0;

        // Use Newton's iteration method to solve the equation
        double T              = 0.0; // Initial guess value
        int    max_iterations = 100;
        double tolerance      = 1e-6;

        for (int i = 0; i < max_iterations; i++)
        {
            // Calculate the polynomial value and its derivative
            double f  = a * T * T * T + b * T * T + c * T + d;
            double df = 3 * a * T * T + 2 * b * T + c;

            // Check if the derivative is close to zero
            if (fabs(df) < tolerance) break;

            // Iterative update
            double delta  = f / df;
            T            -= delta;

            // Check convergence
            if (fabs(delta) < tolerance) break;
        }

        return T;
    }
    else
    {
        // High temperature region (T ≥ 0°C): Solve the quadratic equation
        // Quadratic equation: B*T² + A*T + (1 - R/R0) = 0
        double discriminant = A * A - 4 * B * (1 - resistance / R0);

        if (discriminant < 0)
        {
            return NAN;
        }

        // Take the positive root
        return (-A + sqrt(discriminant)) / (2 * B);
    }
}

/**
 * @brief Calculate the temperature based on the resistance value of a PT100 platinum resistor 
 * (engineering approximation).
 * @param resistance Measured resistance value (Ω).
 * @param type Type of the PT sensor (PT100 or PT1000).
 * @return Temperature value (°C).
 */
double pt_approximate_temperature(double resistance, PtType type)
{
    double R0 = (type == PT100) ? PT100_R0 : PT1000_R0;
    return (resistance / R0 - 1) / 0.00385;
}

float pt_temperature_to_resistance(double t, PtType type)
{
    float resistance;
    float r0 = (type == PT100) ? PT100_R0 : PT1000_R0;
    if (t >= 0.0f)
    {
        resistance = r0 * (1 + A * t + B * t * t);
    }
    else
    {
        resistance = r0 * (1 + A * t + B * t * t + C * (t - r0) * t * t * t);
    }
    return resistance;
}
