diff --git a/include/constants.h b/include/constants.h new file mode 100644 index 0000000..fb731b5 --- /dev/null +++ b/include/constants.h @@ -0,0 +1,37 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Nikita Mandrykin. All rights reserved. + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef CONSTANTS_H +#define CONSTANTS_H + +// Максимальный размер массивов для данных. +// Используется в main для выделения памяти и в других модулях для проверки границ. +#define ARRAY_SIZE 1500 + +// Пути к внешним файлам данных +#define FILE_PATH_ARRAY_T "data/array_t.txt" +#define FILE_PATH_ARRAY_UVX "data/array_Uvx.txt" +#define FILE_PATH_ARRAY_UVIX "data/array_Uvix.txt" +#define FILE_PATH_ZAST "data/zast.txt" + +#endif // CONSTANTS_H diff --git a/include/forming.h b/include/forming.h index ffce02c..8111db4 100644 --- a/include/forming.h +++ b/include/forming.h @@ -25,7 +25,7 @@ #define FORMING_H void forming_time(int n, float *t, float *dt); -void forming_Uvx(int n, float *t, float *Uvx, float t1, float t2, float t3, float a, float b, float c); -void forming_Uvix(int n, float *Uvx, float *Uvix, float Uvx1, float a, float b); +void forming_Uvx(int n, float *t, float *Uvx); +void forming_Uvix(int n, float *Uvx, float *Uvix); #endif // FORMING_H diff --git a/include/response_dictionary.h b/include/response_dictionary.h new file mode 100644 index 0000000..ce7d72e --- /dev/null +++ b/include/response_dictionary.h @@ -0,0 +1,43 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Nikita Mandrykin. All rights reserved. + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef RESPONSE_DICTIONARY_H +#define RESPONSE_DICTIONARY_H + +typedef enum { + RESPONSE_UNKNOWN, + RESPONSE_AFFIRMATIVE, + RESPONSE_NEGATIVE +} ResponseType; + +typedef struct { + const char *keyword_text; + ResponseType type; +} KeywordMapping; + +extern const KeywordMapping RESPONSE_DICTIONARY[]; +extern const int DICTIONARY_SIZE; + +ResponseType get_response_type_by_keyword(const char* input); + +#endif // RESPONSE_DICTIONARY_H \ No newline at end of file diff --git a/src/file.c b/src/file.c index 026eb0b..009a61f 100644 --- a/src/file.c +++ b/src/file.c @@ -25,13 +25,14 @@ #include #include "file.h" +#include "constants.h" // Функция для открытия файлов для последующей записи в них информации void open_output_files(FILE **f1, FILE **f2, FILE **f3) { - *f1 = fopen("data/array_t.txt", "w"); - *f2 = fopen("data/array_Uvx.txt", "w"); - *f3 = fopen("data/array_Uvix.txt", "w"); - + *f1 = fopen(FILE_PATH_ARRAY_T, "w"); + *f2 = fopen(FILE_PATH_ARRAY_UVX, "w"); + *f3 = fopen(FILE_PATH_ARRAY_UVIX, "w"); + // Проверка успешности открытия файлов if (*f1 == NULL || *f2 == NULL || *f3 == NULL) { perror("Ошибка при открытии файлов"); diff --git a/src/forming.c b/src/forming.c index 67035c6..c7d876c 100644 --- a/src/forming.c +++ b/src/forming.c @@ -23,38 +23,53 @@ #include "forming.h" +// Параметры для функции forming_time +static const float TN_PARAM = 5.0f; +static const float TK_PARAM = 50.0f; + +// Параметры для функции forming_Uvx +static const float T1_PARAM = 10.0f; +static const float T2_PARAM = 15.0f; +static const float T3_PARAM = 45.0f; +static const float A_PARAM = 20.0f; +static const float B_PARAM = 0.5f; +static const float C_PARAM = 17.0f; + +// Параметры для функции forming_Uvix +static const float UVX1_PARAM = 20.0f; +static const float D_PARAM = 2.0f; +static const float E_PARAM = -5.0f; + // Функция формирования массива времени void forming_time(int n, float *t, float *dt) { - float tn = 5, tk = 50; - - *dt = (tk - tn) / (n - 1); + *dt = (TK_PARAM - TN_PARAM) / (n - 1); for (int i = 0; i < n; i++) { - t[i] = tn + i * (*dt); + t[i] = TN_PARAM + i * (*dt); } } // Функция формирования массива Uvx -void forming_Uvx(int n, float *t, float *Uvx, float t1, float t2, float t3, float a, float b, float c) { +void forming_Uvx(int n, float *t, float *Uvx) { for (int i = 0; i < n; i++) { - if (t[i] <= t1) { + if (t[i] <= T1_PARAM) { Uvx[i] = 0; - } else if (t1 < t[i] && t[i] <= t2) { - Uvx[i] = a * (t[i] - t1); - } else if (t2 < t[i] && t[i] <= t3) { - Uvx[i] = a * (t2 - t1) - b * (t[i] - t2); + } else if (T1_PARAM < t[i] && t[i] <= T2_PARAM) { + Uvx[i] = A_PARAM * (t[i] - T1_PARAM); + } else if (T2_PARAM < t[i] && t[i] <= T3_PARAM) { + Uvx[i] = A_PARAM * (T2_PARAM - T1_PARAM) - B_PARAM * (t[i] - T2_PARAM); } else { - Uvx[i] = a * (t2 - t1) - b * (t3 - t1) - c * (t[i] - t3); + Uvx[i] = A_PARAM * (T2_PARAM - T1_PARAM) - B_PARAM * (T3_PARAM - T1_PARAM) - C_PARAM * (t[i] - T3_PARAM); } } } // Функция формирования массива Uvix -void forming_Uvix(int n, float *Uvx, float *Uvix, float Uvx1, float a, float b) { +void forming_Uvix(int n, float *Uvx, float *Uvix) { for (int i = 0; i < n; i++) { - if (Uvx[i] <= Uvx1) { - Uvix[i] = a * Uvx[i] + b; + if (Uvx[i] <= UVX1_PARAM) { + Uvix[i] = D_PARAM * Uvx[i] + E_PARAM; } else { - Uvix[i] = a * Uvx1 + b; + Uvix[i] = D_PARAM * UVX1_PARAM + E_PARAM; } } } diff --git a/src/input.c b/src/input.c index c0cba80..1c60874 100644 --- a/src/input.c +++ b/src/input.c @@ -26,8 +26,11 @@ #include #include "input.h" +#include "constants.h" +#include "response_dictionary.h" -#define INPUT_SIZE 10 +// Размер буфера для чтения строкового ввода от пользователя ("да"/"нет"). С запасом для '\0'. +static const int INPUT_SIZE = 10; // Функция для ввода n int input_n() { @@ -55,7 +58,7 @@ bool ask_user_continue(void) { while (1) { printf("Хотите продолжить? (да/нет): "); - // Считываем строку ввода с ограничением + // Считываем строку ввода с ограничением. "%9s" для INPUT_SIZE == 10 (оставляет место для '\0') if (scanf("%9s", input) != 1) { while (getchar() != '\n'); // Если произошла ошибка ввода, очищаем буфер continue; @@ -65,12 +68,18 @@ bool ask_user_continue(void) { int c; while ((c = getchar()) != '\n' && c != EOF); - if ((strcmp(input, "да") == 0) || (strcmp(input, "ДА") == 0)) { - return true; - } else if ((strcmp(input, "нет") == 0) || (strcmp(input, "НЕТ") == 0)) { - return false; - } else { - printf("Некорректный ввод. Пожалуйста, введите 'да' или 'нет'.\n"); + ResponseType result = get_response_type_by_keyword(input); + + switch (result) { + case RESPONSE_AFFIRMATIVE: + return true; + break; + case RESPONSE_NEGATIVE: + return false; + break; + case RESPONSE_UNKNOWN: + printf("Некорректный ввод. Пожалуйста, введите 'да' или 'нет'.\n"); + break; } } diff --git a/src/output.c b/src/output.c index 541e544..817c55e 100644 --- a/src/output.c +++ b/src/output.c @@ -25,10 +25,11 @@ #include "output.h" #include "file.h" +#include "constants.h" // Функция вывода заставки из файла void print_banner() { - FILE *fp = fopen("data/zast.txt", "r"); + FILE *fp = fopen(FILE_PATH_ZAST, "r"); if (!fp) { perror("Не удалось открыть файл заставки"); diff --git a/src/parameter.c b/src/parameter.c index 9d043fd..5f60712 100644 --- a/src/parameter.c +++ b/src/parameter.c @@ -26,8 +26,19 @@ #include "parameter.h" #include "forming.h" +#include "constants.h" -#define N 1500 +// Требуемая относительная погрешность (1% в соотв. с README), при достижении которой расчет останавливается. +static const float EPSILON = 0.01f; + +// Начальная погрешность для входа в цикл while. Просто значение > EPSILON. +static const float INITIAL_CURRENT_PRECISION = 1.0f; + +// Стартовое значение для 'prev_parameter', чтобы избежать ложной точности на первой итерации. +static const float PREV_PARAMETER_INITIAL = 1e10f; + +// Начальное количество точек 'n' для первого шага итерационного расчета. +static const int INITIAL_POINTS = 11; // Функция расчета длительности переднего фронта импульса float calc_leading_edge(int n, float *U, float dt) { @@ -42,7 +53,7 @@ float calc_leading_edge(int n, float *U, float dt) { float U1 = Umin + 0.9 * (Umax - Umin); float U2 = Umin + 0.1 * (Umax - Umin); - // Считаем длительность заднего фронта + // Считаем длительность переднего фронта float duration = 0; for (int i = 0; i < n - 1; i++) { if (U[i] < U1 && U[i] > U2 && U[i + 1] > U[i]) duration += dt; @@ -53,29 +64,26 @@ float calc_leading_edge(int n, float *U, float dt) { // Функция расчета параметра с заданной точностью void calculate_with_precision() { - float epsilon = 0.01; // Требуемая точность (1%) - float current_precision = 1.0; // Текущая погрешность - float prev_parameter = 1e10; // Начальное (очень большое) значение - int n = 11; // Начальное количество точек + float current_precision = INITIAL_CURRENT_PRECISION; // Текущая погрешность + float prev_parameter = PREV_PARAMETER_INITIAL; // Начальное (очень большое) значение + int n = INITIAL_POINTS; // Начальное количество точек - float current_parameter, t[N], Uvx[N], Uvix[N], dt; + float current_parameter, t[ARRAY_SIZE], Uvx[ARRAY_SIZE], Uvix[ARRAY_SIZE], dt; - printf("\nЗаданный параметр: расчет длительности заднего фронта для Uвых\n"); + printf("\nЗаданный параметр: расчет длительности переднего фронта для Uвых\n"); - while (current_precision > epsilon) { + while (current_precision > EPSILON) { // Формирование массивов forming_time(n, t, &dt); - float t1 = 10, t2 = 15, t3 = 45, a = 20, b = 0.5, c = 17; - forming_Uvx(n, t, Uvx, t1, t2, t3, a, b, c); - float Uvx1 = 20, d = 2, e = -5; - forming_Uvix(n, Uvx, Uvix, Uvx1, d, e); + forming_Uvx(n, t, Uvx); + forming_Uvix(n, Uvx, Uvix); // Расчет параметра current_parameter = calc_leading_edge(n, Uvix, dt); // Расчет погрешности - if (prev_parameter != 1e10) { + if (prev_parameter != PREV_PARAMETER_INITIAL) { current_precision = fabs(prev_parameter - current_parameter) / current_parameter; } @@ -86,7 +94,7 @@ void calculate_with_precision() { n *= 2; } - if (n >= N) { + if (n >= ARRAY_SIZE) { printf("Предупреждение: достигнут максимальный размер массива без достижения требуемой точности\n"); } else { printf("Итоговое значение параметра: %.6f (точность: %.2f%%)\n", current_parameter, current_precision * 100); diff --git a/src/response_dictionary.c b/src/response_dictionary.c new file mode 100644 index 0000000..463d12b --- /dev/null +++ b/src/response_dictionary.c @@ -0,0 +1,54 @@ +/* + * SPDX-FileCopyrightText: Copyright (c) 2025 Nikita Mandrykin. All rights reserved. + * SPDX-License-Identifier: MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include + +#include "response_dictionary.h" + +const KeywordMapping RESPONSE_DICTIONARY[] = { + // Утвердительные ответы + {"да", RESPONSE_AFFIRMATIVE}, + {"Да", RESPONSE_AFFIRMATIVE}, + {"дА", RESPONSE_AFFIRMATIVE}, + {"ДА", RESPONSE_AFFIRMATIVE}, + + // Отрицательные ответы + {"нет", RESPONSE_NEGATIVE}, + {"Нет", RESPONSE_NEGATIVE}, + {"нЕт", RESPONSE_NEGATIVE}, + {"неТ", RESPONSE_NEGATIVE}, + {"НЕт", RESPONSE_NEGATIVE}, + {"нЕТ", RESPONSE_NEGATIVE}, + {"НЕТ", RESPONSE_NEGATIVE} +}; + +const int DICTIONARY_SIZE = sizeof(RESPONSE_DICTIONARY) / sizeof(RESPONSE_DICTIONARY[0]); + +ResponseType get_response_type_by_keyword(const char *input) { + for (int i = 0; i < DICTIONARY_SIZE; i++) { + if (strcmp(input, RESPONSE_DICTIONARY[i].keyword_text) == 0) { + return RESPONSE_DICTIONARY[i].type; + } + } + return RESPONSE_UNKNOWN; +} diff --git a/src/signal_analysis.c b/src/signal_analysis.c index 9f96443..05604df 100644 --- a/src/signal_analysis.c +++ b/src/signal_analysis.c @@ -29,11 +29,10 @@ #include "file.h" #include "forming.h" #include "parameter.h" - -#define N 1500 +#include "constants.h" int main() { - float t[N], Uvx[N], Uvix[N], dt; + float t[ARRAY_SIZE], Uvx[ARRAY_SIZE], Uvix[ARRAY_SIZE], dt; int n, choice; bool continueProgram = true; @@ -62,33 +61,36 @@ int main() { } switch (choice) { - case 1: - n = input_n(); - - forming_time(n, t, &dt); - - float t1 = 10, t2 = 15, t3 = 45, a = 20, b = 0.5, c = 17; - forming_Uvx(n, t, Uvx, t1, t2, t3, a, b, c); - - float Uvx1 = 20, d = 2, e = -5; - forming_Uvix(n, Uvx, Uvix, Uvx1, d, e); - - forming_table(n, t, Uvx, Uvix); - - break; - case 2: - calculate_with_precision(); - break; - case 3: - // Открываем файлы для записи - open_output_files(&f1, &f2, &f3); - - // Записываем данные в файлы - output_in_file(f1, f2, f3, n, t, Uvx, Uvix); - - // Закрываем файлы после записи - close_output_files(f1, f2, f3); - break; + case 1: + n = input_n(); + + // Формирование массива времени t и расчет шага dt + forming_time(n, t, &dt); + + // Формирование массива входного напряжения Uvx + forming_Uvx(n, t, Uvx); + + // Формирование массива выходного напряжения Uvix по Uvx + forming_Uvix(n, Uvx, Uvix); + + // Вывод сформированных данных в виде таблицы + forming_table(n, t, Uvx, Uvix); + + break; + case 2: + // Расчет параметра (длительности переднего фронта) с заданной точностью + calculate_with_precision(); + break; + case 3: + // Открываем файлы для записи + open_output_files(&f1, &f2, &f3); + + // Записываем данные в файлы + output_in_file(f1, f2, f3, n, t, Uvx, Uvix); + + // Закрываем файлы после записи + close_output_files(f1, f2, f3); + break; } printf("\n");