Compare commits

...
8 Commits
11 changed files with 751 additions and 13 deletions

No files matched your search

+3 -1
View File
@@ -1,3 +1,5 @@
.DS_Store
heat_exchander_airflow_pressure_drop.dSYM
commit.md
commit.md
commit-rules.md
wiki-rules.md
+4 -1
View File
@@ -3,8 +3,11 @@
## Features
1. Calculation of pressure drop across heat exchangers.
2. Support for three heat exchanger models:
2. Support for heat exchanger models:
- Honeywell Heat Exchanger CMM 21-50-14
- Honeywell Ram Heat Exchanger CMM 21-52-80
- Honeywell NGS Heat Exchanger CMM 47-32-06
- Honeywell NGS Regen Heat Exchanger CMM 47-32-14
- Liebherr Reheater CMM 21-53-89
- Liebherr Condenser CMM 21-53-88
3. Multiple part number selection for each heat exchanger.
+217
View File
@@ -0,0 +1,217 @@
#pragma once
#include "ats0002.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @file 21_52_80.h
*
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80 configuration data.
*
* This module provides static configuration data for Honeywell Ram Heat
* Exchanger CMM 21-52-80, including pressure-to-airflow anchor points for
* cooling and hot sides, air passage definitions, and heat exchanger type
* mappings for part numbers 67200152-00 and 67200152-01.
*
* Key features:
* - Cooling side performance data (Figure TEST-8)
* - Primary hot side performance data (Figure TEST-10)
* - Main hot side performance data (Figure TEST-12)
* - Complete air passage configuration with operational limits
*
* @note All data arrays are static and const-qualified for read-only access.
*/
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-8 (P/N 67200152-00).
*
* Cooling side dependence of ΔPS (KPA) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _cooling_side_67200152_00[] = {
{50.0, 0.06},
{60.0, 0.08},
{70.0, 0.10},
{80.0, 0.13},
{90.0, 0.15},
{100.0, 0.17},
{200.0, 0.47},
{300.0, 0.85},
{400.0, 1.30},
{500.0, 1.74},
{600.0, 2.36}};
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-8 (P/N 67200152-01).
*
* Cooling side dependence of ΔPS (KPA) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _cooling_side_67200152_01[] = {
{50.0, 0.06},
{60.0, 0.08},
{70.0, 0.10},
{80.0, 0.13},
{90.0, 0.15},
{100.0, 0.17},
{200.0, 0.47},
{300.0, 0.85},
{400.0, 1.30},
{500.0, 1.74},
{600.0, 2.36}};
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-10 (P/N 67200152-00).
*
* Primary hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _primary_hot_side_67200152_00[] = {
{25.0, 0.14},
{30.0, 0.19},
{40.0, 0.29},
{50.0, 0.42},
{60.0, 0.61},
{70.0, 0.80},
{80.0, 0.92},
{90.0, 1.14},
{100.0, 1.38},
{200.0, 4.91},
{300.0, 11.30}};
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-10 (P/N 67200152-01).
*
* Primary hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _primary_hot_side_67200152_01[] = {
{25.0, 0.14},
{30.0, 0.19},
{40.0, 0.29},
{50.0, 0.42},
{60.0, 0.61},
{70.0, 0.80},
{80.0, 0.92},
{90.0, 1.14},
{100.0, 1.38},
{200.0, 4.91},
{300.0, 11.30}};
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-12 (P/N 67200152-00).
*
* Main hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _main_hot_side_67200152_00[] = {
{25.0, 0.34},
{30.0, 0.43},
{40.0, 0.68},
{50.0, 0.89},
{60.0, 1.18},
{70.0, 1.47},
{80.0, 1.82},
{90.0, 2.26},
{100.0, 2.75},
{200.0, 9.82},
{300.0, 27.01}};
/**
* @brief Honeywell Ram Heat Exchanger CMM 21-52-80, Figure TEST-12 (P/N 67200152-01).
*
* Main hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _main_hot_side_67200152_01[] = {
{25.0, 0.34},
{30.0, 0.43},
{40.0, 0.68},
{50.0, 0.89},
{60.0, 1.18},
{70.0, 1.47},
{80.0, 1.82},
{90.0, 2.26},
{100.0, 2.75},
{200.0, 9.82},
{300.0, 27.01}};
static const air_passage_data_t _air_passage_67200152_00_data[] = {
{.air_passage_description = "Cooling Air Side",
.air_passage_anchors = _cooling_side_67200152_00,
.anchors_data_size = ARRAY_SIZE(_cooling_side_67200152_00),
.recalculated_required = true,
.airflow_pressure_unit = KPA,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 2.0},
{.air_passage_description = "Primary Bleed Air Side",
.air_passage_anchors = _primary_hot_side_67200152_00,
.anchors_data_size = ARRAY_SIZE(_primary_hot_side_67200152_00),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0},
{.air_passage_description = "Main Bleed Air Side",
.air_passage_anchors = _main_hot_side_67200152_00,
.anchors_data_size = ARRAY_SIZE(_main_hot_side_67200152_00),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0}};
static const air_passage_data_t _air_passage_67200152_01_data[] = {
{.air_passage_description = "Cooling Air Side",
.air_passage_anchors = _cooling_side_67200152_01,
.anchors_data_size = ARRAY_SIZE(_cooling_side_67200152_01),
.recalculated_required = true,
.airflow_pressure_unit = KPA,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 2.0},
{.air_passage_description = "Primary Bleed Air Side",
.air_passage_anchors = _primary_hot_side_67200152_01,
.anchors_data_size = ARRAY_SIZE(_primary_hot_side_67200152_01),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0},
{.air_passage_description = "Main Bleed Air Side",
.air_passage_anchors = _main_hot_side_67200152_01,
.anchors_data_size = ARRAY_SIZE(_main_hot_side_67200152_01),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0}};
static const heat_exchanger_type_data_t heat_exchanger_21_52_80_data[] = {
{.part_number_description = "67200152-00",
.air_passages_data = _air_passage_67200152_00_data,
.air_passages_data_size = ARRAY_SIZE(_air_passage_67200152_00_data)},
{.part_number_description = "67200152-01",
.air_passages_data = _air_passage_67200152_01_data,
.air_passages_data_size = ARRAY_SIZE(_air_passage_67200152_01_data)}};
#ifdef __cplusplus
}
#endif
+98
View File
@@ -0,0 +1,98 @@
#pragma once
#include "ats0002.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @file 47_32_06.h
*
* @brief Honeywell NGS Heat Exchanger CMM 47-32-06 configuration data.
*
* This module provides static configuration data for Honeywell NGS Heat
* Exchanger CMM 47-32-06, including pressure-to-airflow anchor points for
* cooling and hot sides, air passage definitions, and heat exchanger type
* mappings for part number 2341790-1.
*
* Key features:
* - Cooling side performance data (Figure 4002)
* - Hot side performance data (Figure 4004)
* - Complete air passage configuration with operational limits
*
* @note All data arrays are static and const-qualified for read-only access.
*/
/**
* @brief Honeywell NGS Heat Exchanger CMM 47-32-06, Figure 4002 (P/N 2341790-1).
*
* Cooling side dependence of ΔPS (KPA) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _cooling_side_2341790_1[] = {
{2.6, 0.02},
{3.0, 0.03},
{4.0, 0.04},
{5.0, 0.06},
{6.0, 0.07},
{7.0, 0.09},
{8.0, 0.11},
{9.0, 0.14},
{10.0, 0.17},
{20.0, 0.55},
{30.0, 1.12},
{40.0, 1.84}};
/**
* @brief Honeywell NGS Heat Exchanger CMM 47-32-06, Figure 4004 (P/N 2341790-1).
*
* Hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _hot_side_2341790_1[] = {
{1.6, 0.04},
{2.0, 0.05},
{3.0, 0.07},
{4.0, 0.10},
{5.0, 0.14},
{6.0, 0.18},
{7.0, 0.24},
{8.0, 0.29},
{9.0, 0.35},
{10.0, 0.42},
{20.0, 1.37},
{30.0, 2.89},
{35.0, 3.61}};
static const air_passage_data_t _air_passage_2341790_1_data[] = {
{.air_passage_description = "Ram Air Side",
.air_passage_anchors = _cooling_side_2341790_1,
.anchors_data_size = ARRAY_SIZE(_cooling_side_2341790_1),
.recalculated_required = true,
.airflow_pressure_unit = KPA,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 2.0},
{.air_passage_description = "Bleed Air Side",
.air_passage_anchors = _hot_side_2341790_1,
.anchors_data_size = ARRAY_SIZE(_hot_side_2341790_1),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0}};
static const heat_exchanger_type_data_t heat_exchanger_47_32_06_data[] = {
{.part_number_description = "2341790-1",
.air_passages_data = _air_passage_2341790_1_data,
.air_passages_data_size = ARRAY_SIZE(_air_passage_2341790_1_data)}};
#ifdef __cplusplus
}
#endif
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#include "ats0002.h"
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @file 47_32_14.h
*
* @brief Honeywell NGS Regen Heat Exchanger CMM 47-32-14 configuration data.
*
* This module provides static configuration data for Honeywell NGS Regen Heat
* Exchanger CMM 47-32-14, including pressure-to-airflow anchor points for
* cooling and hot sides, air passage definitions, and heat exchanger type
* mappings for part number 2342176-1.
*
* Key features:
* - Cooling side performance data (Figure 1005)
* - Hot side performance data (Figure 1008)
* - Complete air passage configuration with operational limits
*
* @note All data arrays are static and const-qualified for read-only access.
*/
/**
* @brief Honeywell NGS Regen Heat Exchanger CMM 47-32-14, Figure 1005 (P/N 2342176-1).
*
* Cooling side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _cooling_side_2342176_1[] = {
{3.0, 0.10},
{4.0, 0.17},
{5.0, 0.23},
{6.0, 0.32},
{7.0, 0.41},
{8.0, 0.52},
{9.0, 0.63},
{10.0, 0.79}};
/**
* @brief Honeywell NGS Regen Heat Exchanger CMM 47-32-14, Figure 1008 (P/N 2342176-1).
*
* Hot side dependence of ΔPS (PSIG) on air flow rate (LB/MIN), UPPER LIMIT.
*/
static const airflow_to_pressure_anchors_data_t _hot_side_2342176_1[] = {
{3.0, 0.13},
{4.0, 0.21},
{5.0, 0.30},
{6.0, 0.40},
{7.0, 0.52},
{8.0, 0.66},
{9.0, 0.81},
{10.0, 1.01}};
static const air_passage_data_t _air_passage_2342176_1_data[] = {
{.air_passage_description = "Cold Air Side",
.air_passage_anchors = _cooling_side_2342176_1,
.anchors_data_size = ARRAY_SIZE(_cooling_side_2342176_1),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0},
{.air_passage_description = "Hot Air Side",
.air_passage_anchors = _hot_side_2342176_1,
.anchors_data_size = ARRAY_SIZE(_hot_side_2342176_1),
.recalculated_required = true,
.airflow_pressure_unit = PSIG,
.min_barometric_pressure = 840.0,
.max_barometric_pressure = 1070.0,
.min_airflow_temperature = 15.0,
.max_airflow_temperature = 35.0,
.min_airflow_pressure = 0.01,
.max_airflow_pressure = 15.0}};
static const heat_exchanger_type_data_t heat_exchanger_47_32_14_data[] = {
{.part_number_description = "2342176-1",
.air_passages_data = _air_passage_2342176_1_data,
.air_passages_data_size = ARRAY_SIZE(_air_passage_2342176_1_data)}};
#ifdef __cplusplus
}
#endif
+2 -4
View File
@@ -104,7 +104,6 @@ static void _get_selection(uint16_t *result, uint8_t size, const char *prompt, c
{
double input = 0.0;
_get_user_input(&input);
if (input == (double)EXIT)
{
*result = EXIT;
@@ -190,7 +189,7 @@ void get_airflow_temperature(double *airflow_temperature, const air_passage_data
{
double min = data->min_airflow_temperature;
double max = data->max_airflow_temperature;
_get_double_in_range(airflow_temperature, min, max, "Enter air temperature in C", "Incorrect air temperature. Try again.");
_get_double_in_range(airflow_temperature, min, max, "Enter airflow temperature in C", "Incorrect airflow temperature. Try again.");
}
void get_pressure_drop(double *pressure_drop_limit, const double *airflow, const double *airflow_pressure, double *corrected_airflow_pressure, const double *barometric_pressure, const double *airflow_temperature, const air_passage_data_t *data)
@@ -307,8 +306,7 @@ static void _get_log_interpolated_airflow_pressure_drop_limit(double *limit, con
}
for (uint8_t i = 0; i < data->anchors_data_size - 1; ++i)
{
if (*airflow >= data->air_passage_anchors[i].airflow &&
*airflow <= data->air_passage_anchors[i + 1].airflow)
if (*airflow >= data->air_passage_anchors[i].airflow && *airflow <= data->air_passage_anchors[i + 1].airflow)
{
double log_x = log(*airflow);
double log_x1 = log(data->air_passage_anchors[i].airflow);
Binary file not shown.
+12 -6
View File
@@ -1,10 +1,16 @@
#include "ats0002/ats0002.h"
#include "ats0002/21_50_14.h"
#include "ats0002/21_52_80.h"
#include "ats0002/47_32_06.h"
#include "ats0002/47_32_14.h"
#include "ats0002/21_53_89.h"
#include "ats0002/21_53_88.h"
#include "ats0002/21_50_14.h"
static const heat_exchanger_data_t heat_exchanger_data[] = {
static const heat_exchanger_data_t _heat_exchanger_data[] = {
{"Honeywell Heat Exchanger CMM 21-50-14", heat_exchanger_21_50_14_data, ARRAY_SIZE(heat_exchanger_21_50_14_data)},
{"Honeywell Ram Heat Exchanger CMM 21-52-80", heat_exchanger_21_52_80_data, ARRAY_SIZE(heat_exchanger_21_52_80_data)},
{"Honeywell NGS Heat Exchanger CMM 47-32-06", heat_exchanger_47_32_06_data, ARRAY_SIZE(heat_exchanger_47_32_06_data)},
{"Honeywell NGS Regen Heat Exchanger CMM 47-32-14", heat_exchanger_47_32_14_data, ARRAY_SIZE(heat_exchanger_47_32_14_data)},
{"Liebherr Reheater CMM 21-53-89", heat_exchanger_21_53_89_data, ARRAY_SIZE(heat_exchanger_21_53_89_data)},
{"Liebherr Condenser CMM 21-53-88", heat_exchanger_21_53_88_data, ARRAY_SIZE(heat_exchanger_21_53_88_data)}};
@@ -28,15 +34,15 @@ int main(void)
"* *\n"
"************************************************************\n"
"\n");
for (uint8_t i = 0; i < ARRAY_SIZE(heat_exchanger_data); ++i)
for (uint8_t i = 0; i < ARRAY_SIZE(_heat_exchanger_data); ++i)
{
printf("%d. %s\n", i + 1, heat_exchanger_data[i].heat_exchanger_description);
printf("%d. %s\n", i + 1, _heat_exchanger_data[i].heat_exchanger_description);
}
printf("\n");
uint16_t heat_exchanger_number = 0;
ASK_CHOICE(heat_exchanger_number, get_heat_exchanger_number, ARRAY_SIZE(heat_exchanger_data));
ASK_CHOICE(heat_exchanger_number, get_heat_exchanger_number, ARRAY_SIZE(_heat_exchanger_data));
printf("\n");
const heat_exchanger_data_t *he = &heat_exchanger_data[heat_exchanger_number];
const heat_exchanger_data_t *he = &_heat_exchanger_data[heat_exchanger_number];
for (uint8_t i = 0; i < he->heat_exchanger_type_data_size; ++i)
{
printf("%d. %s\n", i + 1, he->heat_exchanger_type_data[i].part_number_description);
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
1.0.0
1.3.0
+325
View File
@@ -0,0 +1,325 @@
# ATS0002 — Расчёт падения давления воздуха в теплообменнике
**ATS0002** — это программа для расчёта падения давления воздуха на теплообменниках аэрокосмического оборудования.
Программа поддерживает 6 моделей теплообменников от Honeywell и Liebherr, обеспечивает ввод параметров воздушного потока и статического давления на входе, автоматическую коррекцию показаний с учётом барометрического давления и температуры, а также оценку результата «пройдено/не пройдено» по допустимому пределу падения давления.
## Основные возможности
1. **Поддержка 6 моделей теплообменников** — Honeywell CMM 21-50-14, Honeywell Ram CMM 21-52-80, Honeywell NGS CMM 47-32-06, Honeywell NGS Regen CMM 47-32-14, Liebherr Reheater CMM 21-53-89, Liebherr Condenser CMM 21-53-88.
2. **Несколько номеров деталей (P/N)** для каждого теплообменника с индивидуальными характеристиками.
3. **Конфигурация воздушных каналов** — выбор стороны обдува (охлаждающая, горячая, primary bleed, main bleed и т.д.).
4. **Ввод расхода воздуха и статического давления** с валидацией в пределах допустимых диапазонов.
5. **Коррекция давления** по барометрическому давлению и температуре воздуха для получения скорректированного значения.
6. **Логарифмическая интерполяция** предела падения давления по якорным точкам (anchor points).
7. **Автоматическая оценка** «PASSED» или «FAILED» по допустимому пределу.
8. **Поддержка единиц KPA и PSIG** — в зависимости от конфигурации теплообменника.
9. **Поддержка запятых как десятичного разделителя** — автоматическая нормализация в точку.
## Внутреннее устройство
### Иерархия структур данных
Данные теплообменников организованы в трёхуровневую иерархию:
| Уровень | Структура | Описание |
|---------|-----------|----------|
| 1 | `heat_exchanger_data_t` | Модель теплообменника (описание + массив типов) |
| 2 | `heat_exchanger_type_data_t` | Номер детали (P/N) — описание + массив воздушных каналов |
| 3 | `air_passage_data_t` | Воздушный канал — описание + якорные точки + лимиты |
**`airflow_to_pressure_anchors_data_t`** — пара «расход-давление», используемая как якорная точка для интерполяции:
| Поле | Тип | Описание |
|------|-----|----------|
| `airflow` | `double` | Расход воздуха (LB/MIN) |
| `pressure` | `double` | Соответствующее падение давления (KPA или PSIG) |
**`air_passage_data_t`** — конфигурация одного воздушного канала:
| Поле | Тип | Описание |
|------|-----|----------|
| `air_passage_description` | `const char *` | Человеко-читаемое описание канала |
| `air_passage_anchors` | `const airflow_to_pressure_anchors_data_t *` | Указатель на массив якорных точек |
| `anchors_data_size` | `const uint8_t` | Количество якорных точек |
| `recalculated_required` | `const bool` | Флаг необходимости коррекции давления |
| `airflow_pressure_unit` | `const airflow_pressure_unit_t` | Единицы давления (KPA или PSIG) |
| `min_barometric_pressure` | `const double` | Минимальное барометрическое давление (MBAR) |
| `max_barometric_pressure` | `const double` | Максимальное барометрическое давление (MBAR) |
| `min_airflow_temperature` | `const double` | Минимальная температура воздуха (°C) |
| `max_airflow_temperature` | `const double` | Максимальная температура воздуха (°C) |
| `min_airflow_pressure` | `const double` | Минимальное давление воздушного потока |
| `max_airflow_pressure` | `const double` | Максимальное давление воздушного потока |
**`heat_exchanger_type_data_t`** — конфигурация типа теплообменника (номера деталей):
| Поле | Тип | Описание |
|------|-----|----------|
| `part_number_description` | `const char *` | Описание номера детали |
| `air_passages_data` | `const air_passage_data_t *` | Указатель на массив конфигураций воздушных каналов |
| `air_passages_data_size` | `const uint8_t` | Количество воздушных каналов |
**`heat_exchanger_data_t`** — конфигурация модели теплообменника:
| Поле | Тип | Описание |
|------|-----|----------|
| `heat_exchanger_description` | `const char *` | Описание модели теплообменника |
| `heat_exchanger_type_data` | `const heat_exchanger_type_data_t *` | Указатель на массив номеров деталей |
| `heat_exchanger_type_data_size` | `const uint8_t` | Количество номеров деталей |
### Управление памятью
Все данные теплообменников объявлены как `static const` и хранятся в сегменте данных исполняемого файла. Динамическое выделение памяти не используется — компонент не требует `malloc`/`free`.
### Глобальная таблица теплообменников
В файле `heat_exchander_airflow_pressure_drop.c` определяется массив `heat_exchanger_data[]` из 6 элементов, связывающий описания моделей с их конфигурационными данными:
| Индекс | Модель |
|--------|--------|
| 0 | Honeywell Heat Exchanger CMM 21-50-14 |
| 1 | Honeywell Ram Heat Exchanger CMM 21-52-80 |
| 2 | Honeywell NGS Heat Exchanger CMM 47-32-06 |
| 3 | Honeywell NGS Regen Heat Exchanger CMM 47-32-14 |
| 4 | Liebherr Reheater CMM 21-53-89 |
| 5 | Liebherr Condenser CMM 21-53-88 |
## API (интерфейс)
### Ввод команд
| Функция | Описание |
|---------|----------|
| `get_user_command()` | Ввод команды пользователя: числовой выбор, `q`/`Q` для выхода (EXIT), `r`/`R` для повтора (REPEAT) |
### Выбор параметров
| Функция | Описание |
|---------|----------|
| `get_heat_exchanger_number()` | Ввод номера модели теплообменника из доступных вариантов |
| `get_heat_exchanger_part_number()` | Ввод номера детали (P/N) для выбранной модели |
| `get_heat_exchanger_air_passage_number()` | Ввод номера воздушного канала для выбранной детали |
### Ввод физических параметров
| Функция | Описание |
|---------|----------|
| `get_airflow()` | Ввод расхода воздуха (LB/MIN) с валидацией по диапазону якорных точек |
| `get_airflow_pressure()` | Ввод статического давления на входе (KPA или PSIG) с валидацией по лимитам |
| `get_barometric_pressure()` | Ввод барометрического давления (MBAR) с валидацией по лимитам |
| `get_airflow_temperature()` | Ввод температуры воздуха (°C) с валидацией по лимитам |
### Расчёт
| Функция | Описание |
|---------|----------|
| `get_pressure_drop()` | Расчёт предела падения давления: при необходимости — коррекция давления по барометрии и температуре, затем логарифмическая интерполяция по якорным точкам |
## Потокобезопасность
Компонент **не является потокобезопасным**. Программа работает в однопоточном режиме и не использует механизмы синхронизации (мьютексы, критические секции). Все функции работают с глобальным стандартным вводом (`stdin`) и не содержат разделяемого состояния, кроме `static` константных данных.
## Алгоритмы
### Логарифмическая интерполяция предела падения давления
Алгоритм `_get_log_interpolated_airflow_pressure_drop_limit()` вычисляет допустимое падение давления для заданного расхода воздуха методом линейной интерполяции в логарифмическом пространстве между двумя ближайшими якорными точками:
- Если расход воздуха **меньше или равен** первой якорной точке — возвращается давление первой точки.
- Если расход воздуха **больше или равен** последней якорной точке — возвращается давление последней точки.
- Для расхода внутри диапазона:
- Вычисляются натуральные логарифмы: `log_x = log(airflow)`, `log_x1 = log(airflow[i])`, `log_x2 = log(airflow[i+1])`, `log_y1 = log(pressure[i])`, `log_y2 = log(pressure[i+1])`.
- Выполняется линейная интерполяция: `log_y = log_y1 + (log_x - log_x1) * (log_y2 - log_y1) / (log_x2 - log_x1)`.
- Результат: `limit = exp(log_y)`.
### Коррекция давления по плотности
Функция `_calculate_density_corrected_pressure()` корректирует показание давления с учётом барометрического давления и температуры по формуле:
1. `value_4 = airflow_pressure * 0.5`
2. `value_5 = barometric_pressure + value_4`
3. `value_6 = airflow_temperature + 273.2` (перевод в Кельвины)
4. `value_7 = (0.28443 * value_5) / value_6`
5. `corrected_airflow_pressure = airflow_pressure * value_7`
Результат вычисляется в **гектопаскалях (HPA)**. При входе в `get_pressure_drop()` результат конвертируется обратно в исходные единицы (KPA или PSIG):
- **KPA**: деление на 10.0
- **PSIG**: умножение на 0.0145038
## Примеры использования
### Базовый сценарий
```c
#include "ats0002/ats0002.h"
#include "ats0002/21_50_14.h"
// Глобальная таблица теплообменников определяется в main-файле.
// Для демонстрации — прямой вызов функций ввода и расчёта:
int main(void)
{
setlocale(LC_NUMERIC, "C");
// 1. Выбор теплообменника (индекс 0 — Honeywell CMM 21-50-14)
const heat_exchanger_data_t *he = &heat_exchanger_data[0];
// 2. Выбор номера детали (индекс 0 — 182820-1)
const heat_exchanger_type_data_t *hetd = &he->heat_exchanger_type_data[0];
// 3. Выбор воздушного канала (индекс 0 — Cooling Air Side)
const air_passage_data_t *apd = &hetd->air_passages_data[0];
// 4. Ввод параметров (в реальном коде — через get_* функции)
double airflow = 50.0; // LB/MIN
double airflow_pressure = 0.33; // KPA
double barometric_pressure = 1013.25; // MBAR
double airflow_temperature = 20.0; // °C
double pressure_drop_limit = 0.0;
double corrected_airflow_pressure = 0.0;
// 5. Расчёт предела падения давления
get_pressure_drop(&pressure_drop_limit, &airflow, &airflow_pressure,
&corrected_airflow_pressure, &barometric_pressure,
&airflow_temperature, apd);
// 6. Оценка результата
bool passed = corrected_airflow_pressure <= pressure_drop_limit;
printf("Test result: %s\n", passed ? "PASSED" : "FAILED");
return 0;
}
```
### Работа с разными единицами (PSIG)
```c
#include "ats0002/ats0002.h"
#include "ats0002/21_50_14.h"
int main(void)
{
setlocale(LC_NUMERIC, "C");
const heat_exchanger_data_t *he = &heat_exchanger_data[0];
const heat_exchanger_type_data_t *hetd = &he->heat_exchanger_type_data[0];
// Индекс 1 — Bleed Air Side (использует PSIG)
const air_passage_data_t *apd = &hetd->air_passages_data[1];
double airflow = 50.0; // LB/MIN
double airflow_pressure = 3.05; // PSIG
double barometric_pressure = 1013.25; // MBAR
double airflow_temperature = 20.0; // °C
double pressure_drop_limit = 0.0;
double corrected_airflow_pressure = 0.0;
get_pressure_drop(&pressure_drop_limit, &airflow, &airflow_pressure,
&corrected_airflow_pressure, &barometric_pressure,
&airflow_temperature, apd);
printf("Max allowed: %.2f PSIG\n", pressure_drop_limit);
printf("Corrected: %.2f PSIG\n", corrected_airflow_pressure);
printf("Result: %s\n",
corrected_airflow_pressure <= pressure_drop_limit ? "PASSED" : "FAILED");
return 0;
}
```
### Использование без коррекции (Liebherr Reheater)
```c
#include "ats0002/ats0002.h"
#include "ats0002/21_53_89.h"
int main(void)
{
setlocale(LC_NUMERIC, "C");
const heat_exchanger_data_t *he = &heat_exchanger_data[4];
const heat_exchanger_type_data_t *hetd = &he->heat_exchanger_type_data[0];
const air_passage_data_t *apd = &hetd->air_passages_data[0];
// У Liebherr Reheater recalculated_required = false,
// поэтому коррекция не требуется.
double airflow = 50.0; // LB/MIN
double airflow_pressure = 0.37; // PSIG (без коррекции)
double pressure_drop_limit = 0.0;
double corrected_airflow_pressure = 0.0; // Не используется
get_pressure_drop(&pressure_drop_limit, &airflow, &airflow_pressure,
&corrected_airflow_pressure, NULL, NULL, apd);
printf("Max allowed: %.2f PSIG\n", pressure_drop_limit);
printf("Result: %s\n",
airflow_pressure <= pressure_drop_limit ? "PASSED" : "FAILED");
return 0;
}
```
## Логирование
Компонент не использует ESP-IDF логирование. Все сообщения выводятся через стандартную функцию `printf` в консоль.
## Ошибки
| Код | Описание |
|-----|----------|
| `EXIT` (0xFFFF) | Команда выхода из программы — выводит «Goodbye.» и завершает работу |
| `REPEAT` (0xFFEE) | Команда повтора — возвращается к началу цикла ввода без завершения |
| `-1.0` | Внутренний код ошибки интерполяции — возвращается если якорные точки не найдены (не должно происходить при валидных данных) |
## Ограничения
1. **Однопоточная работа** — программа не поддерживает параллельное выполнение и не использует механизмы синхронизации.
2. **Статические данные** — все конфигурационные данные теплообменников зашиты в код. Добавление новых моделей требует изменения исходного кода и перекомпиляции.
3. **Текстовый интерфейс** — программа работает исключительно через стандартный ввод/вывод (`stdin`/`stdout`), графический интерфейс отсутствует.
4. **Жёстко заданные диапазоны** — лимиты для барометрического давления (840–1070 MBAR) и температуры (15–35 °C или 15–33 °C) фиксированы в конфигурации.
5. **Экстраполяция не поддерживается** — если расход воздуха выходит за пределы якорных точек, возвращается значение первой или последней точки без экстраполяции.
6. **Зависимость от `setlocale`** — для корректной работы с десятичными разделителями необходимо вызов `setlocale(LC_NUMERIC, "C")`.
7. **Максимум 65 535 элементов меню** — выбор элементов используется тип `uint16_t`, что ограничивает количество моделей, деталей и каналов.
## Требования для сборки
- C99 или новее (стандарт C11 рекомендуется)
- Стандартная библиотека C (`stdlib.h`, `stdio.h`, `string.h`, `math.h`, `locale.h`)
- Компилятор GCC (cross-compile для ESP-IDF) или MSVC (для Windows)
- Библиотека `libm` (математическая библиотека, подключается флагом `-lm`)
## Установка
```bash
# Клонирование репозитория
git clone https://github.com/aZholtikov/ats0002
cd ats0002
# Сборка
# Для Linux/macOS:
gcc -o ats0002 heat_exchander_airflow_pressure_drop.c \
ats0002/ats0002.c -lm
# Для Windows (MSVC):
cl heat_exchander_airflow_pressure_drop.c \
ats0002/ats0002.c
# Запуск
./ats0002
```
```c
#include "ats0002/ats0002.h"
#include "ats0002/21_50_14.h"
#include "ats0002/21_52_80.h"
#include "ats0002/47_32_06.h"
#include "ats0002/47_32_14.h"
#include "ats0002/21_53_89.h"
#include "ats0002/21_53_88.h"
```