MODEL_ADC_EX/APP/src/ADC_Temp.c

763 lines
28 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// Created by cfif on 02.12.2025.
//
#include "ADC_Temp.h"
#include <math.h>
#include <stdio.h>
#include <stdbool.h>
// Структура для хранения табличных данных
typedef struct {
int temp_c; // Температура (°C)
float r_nom; // Номинальное сопротивление (Ω)
} ntc_table_entry;
// Таблица из документа KST45 (Duct)
static const ntc_table_entry ntc_table_duct[] = {
{-40, 100950.0f},
{-35, 72777.0f},
{-30, 53100.0f},
{-25, 39111.0f},
{-20, 29121.0f},
{-15, 21879.0f},
{-10, 16599.0f},
{-5, 12695.0f},
{0, 9795.0f},
{5, 7616.0f},
{10, 5970.0f},
{15, 4712.0f},
{20, 3747.0f},
{25, 3000.0f},
{30, 2417.0f},
{35, 1959.0f},
{40, 1598.0f},
{45, 1311.0f},
{50, 1081.0f},
{55, 895.9f},
{60, 746.4f},
{65, 624.9f},
{70, 525.6f},
{75, 444.4f},
{80, 377.4f},
{85, 321.7f}
};
// Таблица из документа Incar
static const ntc_table_entry ntc_table_incar[] = {
{-40, 101000.0f},
{-35, 72600.0f},
{-30, 52720.0f},
{-25, 38660.0f},
{-20, 28620.0f},
{-15, 21390.0f},
{-10, 16120.0f},
{-5, 12260.0f},
{-4, 11620.0f},
{-3, 11010.0f},
{-2, 10440.0f},
{-1, 9907.0f},
{0, 9399.0f},
{1, 8924.0f},
{2, 8473.0f},
{3, 8048.0f},
{4, 7646.0f},
{5, 7267.0f},
{6, 6909.0f},
{7, 6570.0f},
{8, 6250.0f},
{9, 5947.0f},
{10, 5661.0f},
{15, 4441.0f},
{20, 3512.0f},
{25, 2795.0f},
{30, 2239.0f},
{35, 1806.0f},
{40, 1464.0f},
{45, 1195.0f},
{50, 980.0f},
{55, 809.0f},
{60, 670.0f},
{65, 559.0f},
{70, 468.0f},
{75, 394.0f},
{80, 333.0f},
{85, 283.0f}
};
// Таблица для NTC 10 кОм (Ambient)
static const ntc_table_entry ntc_table_ambient[] = {
{-40, 332776.0f},
{-35, 240264.0f},
{-30, 175427.0f},
{-25, 129449.0f},
{-20, 96481.0f},
{-15, 72592.0f},
{-10, 55109.0f},
{-5, 42193.0f},
{0, 32566.0f},
{5, 25338.0f},
{10, 19869.0f},
{15, 15695.0f},
{20, 12486.0f},
{25, 10000.0f},
{30, 8060.0f},
{35, 6536.0f},
{40, 5331.0f},
{45, 4373.0f},
{50, 3606.0f},
{55, 2990.0f},
{60, 2490.0f},
{65, 2085.0f},
{70, 1754.0f},
{75, 1482.0f},
{80, 1257.0f},
{85, 1071.0f},
{90, 916.4f},
{95, 786.9f},
{100, 678.1f},
{105, 586.5f},
{110, 509.1f},
{115, 443.3f},
{120, 387.3f},
{125, 339.5f},
{130, 298.4f},
{135, 263.1f},
{140, 232.6f},
{145, 206.1f},
{150, 183.2f}
};
// Глобальная структура для хранения таблиц быстрого доступа
fast_lookup_tables_t g_fast_tables = {
.duct_initialized = false,
.incar_initialized = false,
.ambient_initialized = false,
.duct_r1 = 3300.0f,
.incar_r1 = 3300.0f,
.ambient_r1 = 3300.0f,
.vcc_mv = VCC_DIVIDER_MV,
.vref_mv = VREF_MV
};
// Активная конфигурация
static ntc_config_t active_config = {
.table_type = TABLE_DUCT,
.r1 = 3300.0f,
.vcc_mv = VCC_DIVIDER_MV,
.vref_mv = VREF_MV,
.start_temp = -40,
.end_temp = 85,
.table_size = TABLE_SIZE_DUCT
};
// Вспомогательная функция для получения таблицы по типу
static const ntc_table_entry* get_table_by_type(eNtcTable table_type, uint16_t* size, int16_t* start_temp, int16_t* end_temp) {
const ntc_table_entry* table = NULL;
*size = 0;
switch(table_type) {
case TABLE_DUCT:
table = ntc_table_duct;
*size = TABLE_SIZE_DUCT;
*start_temp = -40;
*end_temp = 85;
break;
case TABLE_INCAR:
table = ntc_table_incar;
*size = TABLE_SIZE_INCAR;
*start_temp = -40;
*end_temp = 85;
break;
case TABLE_AMBIENT:
table = ntc_table_ambient;
*size = TABLE_SIZE_AMBIENT;
*start_temp = -40;
*end_temp = 150;
break;
default:
table = ntc_table_duct;
*size = TABLE_SIZE_DUCT;
*start_temp = -40;
*end_temp = 85;
break;
}
return table;
}
// Функция для получения указателя на таблицу быстрого доступа по типу
static adc_temp_lookup* get_fast_table_by_type(eNtcTable table_type) {
switch(table_type) {
case TABLE_DUCT:
return g_fast_tables.duct;
case TABLE_INCAR:
return g_fast_tables.incar;
case TABLE_AMBIENT:
return g_fast_tables.ambient;
default:
return g_fast_tables.duct;
}
}
// Функция для получения статуса инициализации таблицы
static bool is_table_initialized(eNtcTable table_type) {
switch(table_type) {
case TABLE_DUCT:
return g_fast_tables.duct_initialized;
case TABLE_INCAR:
return g_fast_tables.incar_initialized;
case TABLE_AMBIENT:
return g_fast_tables.ambient_initialized;
default:
return false;
}
}
// Расширенная функция расчёта сопротивления NTC с учетом VCC и VREF
static float calculate_resistance_full(uint16_t adc_value, float r1, float vcc_mv, float vref_mv) {
if (adc_value == 0) {
return INFINITY; // Бесконечное сопротивление при 0 ADC (обрыв)
}
// Защита от переполнения
if (adc_value >= (uint16_t) (ADC_MAX - 1)) {
return 0.0f; // Нулевое сопротивление при максимальном ADC (короткое замыкание)
}
// Напряжение на NTC (измеренное АЦП)
float v_ntc = (adc_value * vref_mv) / ADC_MAX;
// Напряжение на балластном резисторе
float v_r1 = vcc_mv - v_ntc;
// Проверка на корректность
if (v_r1 <= 0.0f) {
return 0.0f; // Короткое замыкание или ошибка
}
if (v_ntc <= 0.0f) {
return INFINITY; // Обрыв
}
// Сопротивление NTC (закон Ома)
float r_ntc = r1 * (v_ntc / v_r1);
// Ограничиваем разумными пределами (1 Ом - 10 МОм)
if (r_ntc < 1.0f) r_ntc = 1.0f;
if (r_ntc > 10000000.0f) r_ntc = 10000000.0f;
return r_ntc;
}
// Оптимизированная функция для случая VCC == VREF
static float calculate_resistance_optimized(uint16_t adc_value, float r1) {
if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) {
return 0.0f;
}
return r1 * (float) adc_value / (ADC_MAX - (float) adc_value);
}
// Главная функция расчета сопротивления (использует константу времени компиляции)
static float calculate_resistance(uint16_t adc_value, float r1) {
#if VCC_EQUALS_VREF == 1
// Оптимизированный путь, когда напряжения равны
return calculate_resistance_optimized(adc_value, r1);
#else
// Точный путь с учетом разных напряжений
return calculate_resistance_full(adc_value, r1, VCC_DIVIDER_MV, VREF_MV);
#endif
}
// Бинарный поиск в таблице
static int find_interval_index(float resistance, const ntc_table_entry* table, uint16_t table_size) {
int left = 0;
int right = table_size - 1;
// Проверка границ
if (resistance >= table[0].r_nom) return 0;
if (resistance <= table[right].r_nom) return right - 1;
// Бинарный поиск
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid < table_size - 1 &&
resistance <= table[mid].r_nom &&
resistance >= table[mid + 1].r_nom) {
return mid;
}
if (resistance > table[mid].r_nom) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return -1; // Не найден
}
// Интерполяция с использованием уравнения Стейнхарта-Харта между точками
static float interpolate_steinhart(float resistance, int index, const ntc_table_entry* table) {
// Берем две соседние точки из таблицы
float t1 = (float) table[index].temp_c + 273.15f; // в Кельвинах
float t2 = (float) table[index + 1].temp_c + 273.15f;
float r1 = table[index].r_nom;
float r2 = table[index + 1].r_nom;
// Вычисляем коэффициент B для интервала
float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2);
// Используем уравнение Стейнхарта-Харта для вычисления температуры
float steinhart = logf(resistance / r1) / B + 1.0f / t1;
float temp_k = 1.0f / steinhart;
return temp_k - 273.15f; // Конвертация в °C
}
// Линейная интерполяция в логарифмическом масштабе
static float interpolate_log_linear(float resistance, int index, const ntc_table_entry* table) {
float t1 = (float) table[index].temp_c;
float t2 = (float) table[index + 1].temp_c;
float r1 = table[index].r_nom;
float r2 = table[index + 1].r_nom;
float log_r1 = logf(r1);
float log_r2 = logf(r2);
float log_r = logf(resistance);
return t1 + (t2 - t1) * (log_r - log_r1) / (log_r2 - log_r1);
}
// Более надежная версия с проверкой параметров
static float interpolate_steinhart_full(float resistance, int index, const ntc_table_entry* table) {
// Проверка корректности входных данных
if (resistance <= 0.0f) {
return -273.15f; // Абсолютный ноль при некорректном сопротивлении
}
// Для повышения точности можно использовать таблицу как справочную,
// но основное вычисление - по уравнению с коэффициентами
double L = logf(resistance);
// Для термисторов NTC коэффициент C обычно очень маленький (порядка 1e-7...1e-8)
// Убедимся, что кубический член вычислен корректно
double L3 = L * L * L;
double inv_T = koef_A + koef_B * L + koef_C * L3;
// Проверка на физическую реализуемость (температура должна быть положительной в Кельвинах)
if (inv_T <= 0.0f || inv_T > 1.0f) { // 1/T не может быть <= 0 (T < 0K) или слишком большим
// В случае ошибки возвращаем температуру из таблицы по индексу
return (float) table[index].temp_c;
}
double temp_K = 1.0f / inv_T;
// Дополнительная проверка диапазона (например, для NTC обычно -50...+150°C)
if (temp_K < 223.15f || temp_K > 423.15f) { // -50°C...150°C в Кельвинах
// Возвращаем значение из таблицы как запасной вариант
return (float) table[index].temp_c;
}
return (float) (temp_K - 273.15f);
}
// Основная функция для получения температуры с указанием таблицы и R1
float get_temperature_from_adc_with_table(uint16_t adc_value, eAlg alg, eNtcTable table_type, float r1) {
float resistance = calculate_resistance(adc_value, r1);
if (resistance <= 0.0f || isinf(resistance)) {
return -273.15f; // Ошибка
}
uint16_t table_size;
int16_t start_temp, end_temp;
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
int index = find_interval_index(resistance, table, table_size);
if (index < 0 || index >= table_size - 1) {
// Вне диапазона таблицы
if (resistance >= table[0].r_nom) return (float) start_temp;
if (resistance <= table[table_size - 1].r_nom) return (float) end_temp;
return -273.15f; // Ошибка
}
if (alg == ALG_STEINHART) {
return interpolate_steinhart(resistance, index, table);
} else if (alg == ALG_STEINHART_FULL) {
return interpolate_steinhart_full(resistance, index, table);
} else {
return interpolate_log_linear(resistance, index, table);
}
}
// Функция для получения температуры с активной конфигурацией
float get_temperature_from_adc(uint16_t adc_value, eAlg alg) {
return get_temperature_from_adc_with_table(adc_value, alg, active_config.table_type, active_config.r1);
}
// Функция для получения сопротивления из значения АЦП с указанием таблицы
float get_resistance_from_adc_with_table(uint16_t adc_value, eNtcTable table_type, float r1) {
return calculate_resistance(adc_value, r1);
}
// Функция для получения сопротивления с активной конфигурацией
float get_resistance_from_adc(uint16_t adc_value) {
return calculate_resistance(adc_value, active_config.r1);
}
// Функция для получения напряжения из АЦП
uint16_t get_voltage_from_adc(uint16_t adc_value) {
return adc_to_voltage_mv(adc_value);
}
// Функция для получения точного напряжения на NTC
float get_ntc_voltage_fast(uint16_t adc_value) {
return (adc_value * VREF_MV) / ADC_MAX;
}
// Функция для получения напряжения на балластном резисторе
float get_r1_voltage_fast(uint16_t adc_value) {
return VCC_DIVIDER_MV - ((adc_value * VREF_MV) / ADC_MAX);
}
// Функция для получения напряжения из таблицы быстрого доступа
uint16_t get_voltage_fast_for_table(uint16_t adc_value, eNtcTable table_type) {
if (!is_table_initialized(table_type)) {
// Если таблица не инициализирована, вычисляем напрямую
return adc_to_voltage_mv(adc_value);
}
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
// Поиск ближайшего значения в таблице
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
if (fast_table[i].adc_value == adc_value) {
return fast_table[i].voltage_mv;
}
if (i < TABLE_SIZE_LOOKUP - 1 &&
adc_value > fast_table[i].adc_value &&
adc_value < fast_table[i + 1].adc_value) {
// Линейная интерполяция напряжения
uint16_t adc1 = fast_table[i].adc_value;
uint16_t adc2 = fast_table[i + 1].adc_value;
uint16_t v1 = fast_table[i].voltage_mv;
uint16_t v2 = fast_table[i + 1].voltage_mv;
if (adc2 == adc1) return v1;
return v1 + (uint16_t)(((uint32_t)(v2 - v1) * (adc_value - adc1)) / (adc2 - adc1));
}
}
// Если не нашли, возвращаем ближайшее значение
if (adc_value <= fast_table[0].adc_value) {
return fast_table[0].voltage_mv;
} else {
return fast_table[TABLE_SIZE_LOOKUP - 1].voltage_mv;
}
}
void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg) {
uint16_t table_size;
int16_t start_temp, end_temp;
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
// Сохраняем значение R1 для этой таблицы
if (table_type == TABLE_DUCT) {
g_fast_tables.duct_r1 = r1;
} else if (table_type == TABLE_INCAR) {
g_fast_tables.incar_r1 = r1;
} else {
g_fast_tables.ambient_r1 = r1;
}
// Находим рабочий диапазон ADC
uint16_t min_valid_adc = 0;
uint16_t max_valid_adc = (uint16_t)(ADC_MAX - 1);
float max_resistance = table[0].r_nom; // Максимальное сопротивление (мин. температура)
float min_resistance = table[table_size - 1].r_nom; // Минимальное сопротивление (макс. температура)
// Ищем минимальное ADC, при котором сопротивление <= max_resistance
for (uint16_t adc = 1; adc < ADC_MAX; adc++) {
float resistance = calculate_resistance(adc, r1);
if (resistance <= max_resistance && !isinf(resistance)) {
min_valid_adc = adc;
break;
}
}
// Ищем максимальное ADC, при котором сопротивление >= min_resistance
for (uint16_t adc = (uint16_t)(ADC_MAX - 1); adc > 0; adc--) {
float resistance = calculate_resistance(adc, r1);
if (resistance >= min_resistance && resistance < INFINITY) {
max_valid_adc = adc;
break;
}
}
printf("DEBUG: %s - min_valid_adc=%u, max_valid_adc=%u\n",
table_type == TABLE_DUCT ? "DUCT" : (table_type == TABLE_INCAR ? "INCAR" : "AMBIENT"),
min_valid_adc, max_valid_adc);
// Заполняем таблицу
uint32_t adc_step = ((uint32_t)(ADC_MAX - 1) * 1000) / (TABLE_SIZE_LOOKUP - 1);
uint32_t current_adc = 0;
uint16_t prev_adc = 0;
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
uint16_t adc;
float resistance;
float temp;
// Определяем ADC для текущей записи
if (i == 0) {
adc = 0;
} else if (i == TABLE_SIZE_LOOKUP - 1) {
adc = (uint16_t)(ADC_MAX - 1);
} else {
current_adc += adc_step;
adc = (uint16_t)(current_adc / 1000);
if (adc <= prev_adc) adc = prev_adc + 1;
if (adc >= (uint16_t)(ADC_MAX - 1)) adc = (uint16_t)(ADC_MAX - 2);
}
// Расчет сопротивления и температуры в зависимости от зоны
if (adc <= min_valid_adc) {
// Зона низких ADC (высокая температура) - насыщение
resistance = min_resistance;
temp = (float)end_temp; // Максимальная температура (+85°C)
}
else if (adc >= max_valid_adc) {
// Зона высоких ADC (низкая температура) - насыщение
resistance = max_resistance;
temp = (float)start_temp; // Минимальная температура (-40°C)
}
else {
// Рабочая зона - нормальный расчет
resistance = calculate_resistance(adc, r1);
if (isinf(resistance) || resistance <= 0.0f) {
temp = (float)start_temp - 10.0f;
} else {
int index = find_interval_index(resistance, table, table_size);
if (index < 0 || index >= table_size - 1) {
if (resistance >= table[0].r_nom) {
temp = (float)start_temp;
} else if (resistance <= table[table_size - 1].r_nom) {
temp = (float)end_temp;
} else {
temp = 25.0f;
}
} else {
if (use_alg == ALG_STEINHART) {
temp = interpolate_steinhart(resistance, index, table);
} else if (use_alg == ALG_STEINHART_FULL) {
temp = interpolate_steinhart_full(resistance, index, table);
} else {
temp = interpolate_log_linear(resistance, index, table);
}
}
}
}
// Заполняем запись
fast_table[i].adc_value = adc;
fast_table[i].temp_c = (int16_t)(temp * 10.0f);
fast_table[i].resistance_ohm = resistance;
fast_table[i].voltage_mv = adc_to_voltage_mv(adc);
fast_table[i].v_ntc_mv = (adc * VREF_MV) / ADC_MAX;
fast_table[i].v_r1_mv = VCC_DIVIDER_MV - fast_table[i].v_ntc_mv;
fast_table[i].table_type = table_type;
prev_adc = adc;
}
// Устанавливаем флаг инициализации
if (table_type == TABLE_DUCT) {
g_fast_tables.duct_initialized = true;
} else if (table_type == TABLE_INCAR) {
g_fast_tables.incar_initialized = true;
} else {
g_fast_tables.ambient_initialized = true;
}
}
// Инициализация таблицы Duct
void init_duct_table(float r1, eAlg use_alg) {
init_fast_lookup_table(TABLE_DUCT, r1, use_alg);
}
// Инициализация таблицы Incar
void init_incar_table(float r1, eAlg use_alg) {
init_fast_lookup_table(TABLE_INCAR, r1, use_alg);
}
// Инициализация таблицы Ambient
void init_ambient_table(float r1, eAlg use_alg) {
init_fast_lookup_table(TABLE_AMBIENT, r1, use_alg);
}
// Инициализация всех трех таблиц
void init_all_tables(float r1_duct, float r1_incar, float r1_ambient, eAlg use_alg) {
init_fast_lookup_table(TABLE_DUCT, r1_duct, use_alg);
init_fast_lookup_table(TABLE_INCAR, r1_incar, use_alg);
init_fast_lookup_table(TABLE_AMBIENT, r1_ambient, use_alg);
}
// Установка активной конфигурации
void set_active_config(eNtcTable table_type, float r1) {
active_config.table_type = table_type;
active_config.r1 = r1;
active_config.vcc_mv = VCC_DIVIDER_MV;
active_config.vref_mv = VREF_MV;
uint16_t table_size;
get_table_by_type(table_type, &table_size, &active_config.start_temp, &active_config.end_temp);
active_config.table_size = table_size;
}
// Получение активной конфигурации
const ntc_config_t* get_active_config(void) {
return &active_config;
}
// Получение таблиц быстрого доступа
const fast_lookup_tables_t* get_fast_tables(void) {
return &g_fast_tables;
}
// Функция для получения информации о конфигурации VCC/VREF
void get_vcc_vref_info(float* vcc_mv, float* vref_mv) {
if (vcc_mv) *vcc_mv = VCC_DIVIDER_MV;
if (vref_mv) *vref_mv = VREF_MV;
}
float get_vcc_divider_voltage(void) {
return VCC_DIVIDER_MV;
}
float get_vref_voltage(void) {
return VREF_MV;
}
bool is_vcc_equal_to_vref(void) {
return (VCC_DIVIDER_MV_INT == VREF_MV_INT);
}
// Быстрая функция для конкретной таблицы
int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_type) {
if (!is_table_initialized(table_type)) {
// Если таблица не инициализирована, используем обычный расчет
float r1 = (table_type == TABLE_DUCT) ? g_fast_tables.duct_r1 :
((table_type == TABLE_INCAR) ? g_fast_tables.incar_r1 : g_fast_tables.ambient_r1);
float temp = get_temperature_from_adc_with_table(adc_value, ALG_STEINHART, table_type, r1);
return (int16_t)(temp * 10.0f);
}
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
// Простой линейный поиск (так как таблица небольшая - 4096 элементов)
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP - 1; i++) {
if (adc_value >= fast_table[i].adc_value && adc_value <= fast_table[i + 1].adc_value) {
// Линейная интерполяция
uint16_t adc1 = fast_table[i].adc_value;
uint16_t adc2 = fast_table[i + 1].adc_value;
int16_t temp1 = fast_table[i].temp_c;
int16_t temp2 = fast_table[i + 1].temp_c;
if (adc2 == adc1) {
return temp1;
}
return temp1 + ((int32_t)(temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
}
}
// Если не нашли, возвращаем ближайшее значение
if (adc_value <= fast_table[0].adc_value) {
return fast_table[0].temp_c;
} else {
return fast_table[TABLE_SIZE_LOOKUP - 1].temp_c;
}
}
// Быстрые функции с использованием активной таблицы
int16_t get_temperature_log_fast(uint16_t adc_value) {
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
}
// Альтернативная простая версия
int16_t get_temperature_linear_fast(uint16_t adc_value) {
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
}
// Функция для получения сопротивления из температуры для конкретной таблицы
float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type) {
if (!is_table_initialized(table_type)) {
return 0.0f;
}
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
// Защита от выхода за границы
if (temperature_c10 >= fast_table[0].temp_c) {
return fast_table[0].resistance_ohm;
}
if (temperature_c10 <= fast_table[TABLE_SIZE_LOOKUP - 1].temp_c) {
return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
}
// Бинарный поиск интервала по температуре
int left = 0;
int right = TABLE_SIZE_LOOKUP - 1;
while (left <= right) {
int mid = left + (right - left) / 2;
if (mid < TABLE_SIZE_LOOKUP - 1 &&
temperature_c10 <= fast_table[mid].temp_c &&
temperature_c10 >= fast_table[mid + 1].temp_c) {
// Нашли интервал
int16_t temp_high = fast_table[mid].temp_c;
int16_t temp_low = fast_table[mid + 1].temp_c;
float res_high = fast_table[mid].resistance_ohm;
float res_low = fast_table[mid + 1].resistance_ohm;
if (temp_high == temp_low) {
return res_high;
}
// Интерполяция в логарифмическом масштабе
float log_res_high = logf(res_high);
float log_res_low = logf(res_low);
float log_res = log_res_high + (log_res_low - log_res_high) *
(float)(temp_high - temperature_c10) / (float)(temp_high - temp_low);
return expf(log_res);
}
if (temperature_c10 > fast_table[mid].temp_c) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
}
// Функция для получения сопротивления из температуры (обратное преобразование)
float get_resistance_log_fast(int16_t temperature_c10) {
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
}
// Упрощенная версия с линейным поиском
float get_resistance_fast_simple(int16_t temperature_c10) {
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
}