diff --git a/.gitignore b/.gitignore index 5a0ed1f..2deac91 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store heat_exchander_airflow_pressure_drop.dSYM -commit.md \ No newline at end of file +commit.md +commit-rules.md +wiki-rules.md diff --git a/wiki.md b/wiki.md new file mode 100644 index 0000000..d938266 --- /dev/null +++ b/wiki.md @@ -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" +```