diff --git a/MATLAB/upp_demo.m b/MATLAB/upp_demo.m index c299d55..13cdb36 100644 --- a/MATLAB/upp_demo.m +++ b/MATLAB/upp_demo.m @@ -242,57 +242,102 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) thyristor_state(6, i) = 1; end end - + %% 2. Определяем, когда тиристоры ФИЗИЧЕСКИ открыты + % В схеме без нейтрали тиристоры открываются парами (фаза-фаза) - % VS1+ (A+): открыт, если есть импульс и положительная полуволна фазы A - if thyristor_state(1, i) == 1 && (theta_a_mod >= 0 && theta_a_mod <= pi) && (Ua(i) > Ub(i) && Ua(i) > Uc(i)) + % Пары тиристоров для линейных напряжений: + % Uab: VS1+ (A+) и VS4- (B-) + % Uba: VS3+ (B+) и VS2- (A-) + % Ubc: VS3+ (B+) и VS6- (C-) + % Ucb: VS5+ (C+) и VS4- (B-) + % Uca: VS5+ (C+) и VS2- (A-) + % Uac: VS1+ (A+) и VS6- (C-) + + % Проверяем каждую пару + % Пара A+ и B- (Uab) + if thyristor_state(1, i) == 1 && thyristor_state(4, i) == 1 && Ua(i) > Ub(i) thyristor_conducting(1, i) = 1; - end - - % VS1- (A-): открыт, если есть импульс и отрицательная полуволна фазы A - if thyristor_state(2, i) == 1 && (theta_a_mod >= pi && theta_a_mod <= 2*pi) && (Ua(i) < Ub(i) && Ua(i) < Uc(i)) - thyristor_conducting(2, i) = 1; - end - - % VS2+ (B+): открыт, если есть импульс и положительная полуволна фазы B - if thyristor_state(3, i) == 1 && (theta_b_mod >= 0 && theta_b_mod <= pi) && (Ub(i) > Ua(i) && Ub(i) > Uc(i)) - thyristor_conducting(3, i) = 1; - end - - % VS2- (B-): открыт, если есть импульс и отрицательная полуволна фазы B - if thyristor_state(4, i) == 1 && (theta_b_mod >= pi && theta_b_mod <= 2*pi) && (Ub(i) < Ua(i) && Ub(i) < Uc(i)) thyristor_conducting(4, i) = 1; + elseif i > 1 && thyristor_conducting(1, i-1) == 1 && thyristor_conducting(4, i-1) == 1 + if Ua(i) > Ub(i) + thyristor_conducting(1, i) = 1; + thyristor_conducting(4, i) = 1; + end end - % VS3+ (C+): открыт, если есть импульс и положительная полуволна фазы C - if thyristor_state(5, i) == 1 && (theta_c_mod >= 0 && theta_c_mod <= pi) && (Uc(i) > Ub(i) && Uc(i) > Ua(i)) - thyristor_conducting(5, i) = 1; + % Пара B+ и A- (Uba) + if thyristor_state(3, i) == 1 && thyristor_state(2, i) == 1 && Ub(i) > Ua(i) + thyristor_conducting(3, i) = 1; + thyristor_conducting(2, i) = 1; + elseif i > 1 && thyristor_conducting(3, i-1) == 1 && thyristor_conducting(2, i-1) == 1 + if Ub(i) > Ua(i) + thyristor_conducting(3, i) = 1; + thyristor_conducting(2, i) = 1; + end end - % VS3- (C-): открыт, если есть импульс и отрицательная полуволна фазы C - if thyristor_state(6, i) == 1 && (theta_c_mod >= pi && theta_c_mod <= 2*pi) && (Uc(i) < Ub(i) && Uc(i) < Ua(i)) + % Пара B+ и C- (Ubc) + if thyristor_state(3, i) == 1 && thyristor_state(6, i) == 1 && Ub(i) > Uc(i) + thyristor_conducting(3, i) = 1; thyristor_conducting(6, i) = 1; + elseif i > 1 && thyristor_conducting(3, i-1) == 1 && thyristor_conducting(6, i-1) == 1 + if Ub(i) > Uc(i) + thyristor_conducting(3, i) = 1; + thyristor_conducting(6, i) = 1; + end end - %% 3. Расчет выходных напряжений + % Пара C+ и B- (Ucb) + if thyristor_state(5, i) == 1 && thyristor_state(4, i) == 1 && Uc(i) > Ub(i) + thyristor_conducting(5, i) = 1; + thyristor_conducting(4, i) = 1; + elseif i > 1 && thyristor_conducting(5, i-1) == 1 && thyristor_conducting(4, i-1) == 1 + if Uc(i) > Ub(i) + thyristor_conducting(5, i) = 1; + thyristor_conducting(4, i) = 1; + end + end + % Пара C+ и A- (Uca) + if thyristor_state(5, i) == 1 && thyristor_state(2, i) == 1 && Uc(i) > Ua(i) + thyristor_conducting(5, i) = 1; + thyristor_conducting(2, i) = 1; + elseif i > 1 && thyristor_conducting(5, i-1) == 1 && thyristor_conducting(2, i-1) == 1 + if Uc(i) > Ua(i) + thyristor_conducting(5, i) = 1; + thyristor_conducting(2, i) = 1; + end + end + + % Пара A+ и C- (Uac) + if thyristor_state(1, i) == 1 && thyristor_state(6, i) == 1 && Ua(i) > Uc(i) + thyristor_conducting(1, i) = 1; + thyristor_conducting(6, i) = 1; + elseif i > 1 && thyristor_conducting(1, i-1) == 1 && thyristor_conducting(6, i-1) == 1 + if Ua(i) > Uc(i) + thyristor_conducting(1, i) = 1; + thyristor_conducting(6, i) = 1; + end + end + + %% 3. Расчет выходных напряжений % Фазные выходные напряжения Ua_out = 0; if thyristor_conducting(1, i) || thyristor_conducting(2, i) Ua_out = Ua(i); end - + Ub_out = 0; if thyristor_conducting(3, i) || thyristor_conducting(4, i) Ub_out = Ub(i); end - + Uc_out = 0; if thyristor_conducting(5, i) || thyristor_conducting(6, i) Uc_out = Uc(i); end - + % Линейные выходные напряжения Uab_out(i) = Ua_out - Ub_out; Ubc_out(i) = Ub_out - Uc_out; @@ -313,7 +358,7 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) title('Входные напряжения (сплошные - фазные, пунктир - линейные)'); xlabel('Время, с'); ylabel('Напряжение, В'); - legend('Location', 'best'); + legend('Location', 'west'); xlim([0, max(t)]); ylim([-700, 700]); @@ -327,7 +372,7 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) title(sprintf('Выходные линейные напряжения (α = %d°)', alpha_deg)); xlabel('Время, с'); ylabel('Напряжение, В'); - legend('Location', 'best'); + legend('Location', 'west'); xlim([0, max(t)]); ylim([-700, 700]); @@ -338,8 +383,13 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) % Цвета для тиристоров colors = {'r', 'r', 'g', 'g', 'b', 'b'}; line_styles = {'-', '--', '-', '--', '-', '--'}; + names = {'VS1+', 'VS1-', 'VS2+', 'VS2-', 'VS3+', 'VS3-'}; + % Измененный порядок отрисовки: VS1+, VS1-, VS2+, VS2-, VS3+, VS3- + order = [6, 5, 4, 3, 2, 1]; - for k = 1:6 + for idx = 1:6 + k = order(idx); % Берем тиристор в нужном порядке + % Находим интервалы, где подан управляющий импульс state = thyristor_state(k, :); diff_state = diff([0, state, 0]); @@ -348,7 +398,19 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) % Рисуем горизонтальные линии для каждого интервала for m = 1:length(start_idx) - plot(t(start_idx(m):end_idx(m)), k*ones(1, length(start_idx(m):end_idx(m))), ... + plot(t(start_idx(m):end_idx(m)), idx*ones(1, length(start_idx(m):end_idx(m))), ... + 'Color', colors{k}, 'LineStyle', line_styles{k}, 'LineWidth', 1); + end + + % Находим интервалы, где тиристор открыт + state = thyristor_conducting(k, :); + diff_state = diff([0, state, 0]); + start_idx = find(diff_state == 1); + end_idx = find(diff_state == -1) - 1; + + % Рисуем горизонтальные линии для каждого интервала + for m = 1:length(start_idx) + plot(t(start_idx(m):end_idx(m)), idx*ones(1, length(start_idx(m):end_idx(m))), ... 'Color', colors{k}, 'LineStyle', line_styles{k}, 'LineWidth', 2); end end @@ -358,15 +420,12 @@ function update_plots(alpha_deg, alpha_rad, t, f, U_phase, U_line, angle_text) ylabel('Тиристор'); ylim([0.5, 6.5]); yticks(1:6); - yticklabels({'VS1+', 'VS1-', 'VS2+', 'VS2-', 'VS3+', 'VS3-'}); + yticklabels(names(order)); xlim([0, max(t)]); % Обновление текста с текущим углом set(angle_text, 'String', sprintf('Угол α = %d°', alpha_deg)); - % Добавление пояснений к тиристорам - legend({'Фаза A (+)', 'Фаза A (-)', 'Фаза B (+)', 'Фаза B (-)', ... - 'Фаза C (+)', 'Фаза C (-)'}, 'Location', 'best'); end %% Функция обратного вызова для ползунка diff --git a/UPP/Core/Configs/upp_config.h b/UPP/Core/Configs/upp_config.h index f2996dd..a2e11de 100644 --- a/UPP/Core/Configs/upp_config.h +++ b/UPP/Core/Configs/upp_config.h @@ -23,10 +23,12 @@ */ #define UPP_SET_DEFAULT ///< Установить настройки по умолчанию -#define UPP_DISABLE_ERROR_BLOCK ///< Отключить блокировку УПП при ошибках -#define UPP_SIMULATE_I ///< Симулировт токи (Iref/2) а не брать с АЦП +//#define UPP_DISABLE_ERROR_BLOCK ///< Отключить блокировку УПП при ошибках +//#define UPP_SIMULATE_I ///< Симулировт токи (Iref/2) а не брать с АЦП //#define UPP_DISABLE_PROTECT_BOARDPOWER ///< Отключить проверки питания плат (+24, +5 В) -//#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы +#define UPP_DISABLE_PROTECT_LOSS_PHASE ///< Отключить проверки на потерянные фазы +#define UPP_DISABLE_PROTECT_VOLTAGE ///< Отключить проверки на потерянные фазы +#define UPP_DISABLE_PROTECT_LONGSTART ///< Отключить проверки на потерянные фазы @@ -86,15 +88,15 @@ #define NOM_F_HZ_DEFAULT 50 #define NOM_F_DEVIATION_PLUS_PERCENT_DEFAULT 10 #define NOM_F_DEVIATION_MINUS_PERCENT_DEFAULT 10 -#define NOM_I_A_DEFAULT 5 +#define NOM_I_A_DEFAULT 3 /* Параметры ПУИ */ -#define PUI_Iref_PERCENT_DEFAULT 1.5 -#define PUI_Tnt_MS_DEFAULT 300 +#define PUI_Iref_PERCENT_DEFAULT 3.0 +#define PUI_Tnt_MS_DEFAULT 5000 #define PUI_Tnt_CalcAlpha(...) FilterExp_CalcAlpha95(__VA_ARGS__) ///< Уровень в процентах, до куда нарастет ток за время Tnt #define PUI_Umin_PERCENT_DEFAULT 0.8 #define PUI_Umax_PERCENT_DEFAULT 1.2 -#define PUI_Imax_PERCENT_DEFAULT 0.99 +#define PUI_Imax_PERCENT_DEFAULT 0.24 #define PUI_Imin_PERCENT_DEFAULT 0.07 #define PUI_TiMax_US_DEFAULT 5000 #define PUI_Tdelay_SECONDS_DEFAULT 30 @@ -109,9 +111,9 @@ /* Параметры регулятора угла */ #define ANGLE_MAX_PERCENT_DEFAULT (140.0f/180.0f) // note: не больше 150! -#define ANGLE_MIN_PERCENT_DEFAULT (10.0f/180.0f) -#define ANGLE_PID_KP_COEF_DEFAULT 0.0001 -#define ANGLE_PID_KI_COEF_DEFAULT 0.0001 +#define ANGLE_MIN_PERCENT_DEFAULT (40.0f/180.0f) +#define ANGLE_PID_KP_COEF_DEFAULT (0.0025)//(0.0025) +#define ANGLE_PID_KI_COEF_DEFAULT (0.125)//(0.0450) #define ANGLE_PID_KD_COEF_DEFAULT 0 /* Параметри мониторинга сети */ @@ -134,8 +136,8 @@ /* Параметры ШИМ для тиристоров */ #define PWM_THYR_FREQUENCY_HZ_DEFAULT 16000 -#define PWM_THYR_DUTY_PERCENT_DEFAULT 0.5 -#define PWM_THYR_PULSE_LENGTH_DEFAULT (60.0/180.0) +#define PWM_THYR_DUTY_PERCENT_DEFAULT 0.16 +#define PWM_THYR_PULSE_LENGTH_DEFAULT (140.0/180.0) /** //UPP_PARAMS_DEFAULT * @} diff --git a/UPP/Core/PowerMonitor/power_monitor.c b/UPP/Core/PowerMonitor/power_monitor.c index 602259d..4bcc300 100644 --- a/UPP/Core/PowerMonitor/power_monitor.c +++ b/UPP/Core/PowerMonitor/power_monitor.c @@ -204,7 +204,7 @@ void PowerMonitor_FastCalc(PowerMonitor_t *hpm) // meas->fast.U[U_CA] = Filter_Process(&hpm->ufltr[U_CA], uac_fast); meas->fast.U[U_BC] = U_BC_calc(meas->fast.U[U_AB], meas->fast.U[U_CA]); - meas->fast.I[I_C] = hpm->adc.Data[ADC_CHANNEL_IC]/i_base; + meas->fast.I[I_C] = -hpm->adc.Data[ADC_CHANNEL_IC]/i_base; meas->fast.I[I_A] = hpm->adc.Data[ADC_CHANNEL_IA]/i_base; meas->fast.I[I_B] = I_B_calc(meas->fast.I[I_A], meas->fast.I[I_C]); diff --git a/UPP/Core/UPP/pwm_thyristors.c b/UPP/Core/UPP/pwm_thyristors.c index 38ee66a..292f95e 100644 --- a/UPP/Core/UPP/pwm_thyristors.c +++ b/UPP/Core/UPP/pwm_thyristors.c @@ -136,6 +136,7 @@ HAL_StatusTypeDef PWM_Stop(PWM_Handle_t *hpwm, UPP_Phase_t Phase, uint8_t force_ hpwm->AllPhases[ch].State = PWM_THYR_DISABLED; __PWM_SetOutputState(&hpwm->AllPhases[ch], PWM_DISABLE); } + hpwm->f.Running = 0; return HAL_OK; } // Если НЕ force_stop_all - сбрасываем ТОЛЬКО заданный канал diff --git a/UPP/Core/UPP/upp_errors.c b/UPP/Core/UPP/upp_errors.c index be3d023..2f68376 100644 --- a/UPP/Core/UPP/upp_errors.c +++ b/UPP/Core/UPP/upp_errors.c @@ -86,6 +86,7 @@ void UPP_Errors_Ranges(void) static int FMinCnt = 0; static int TMaxCnt = 0; +#ifndef UPP_DISABLE_PROTECT_VOLTAGE /* Напряжения */ ERR_PUI->OverVoltage = setError(ERR_PRIVATE->uamp_max, ERR_PUI->OverVoltage, @@ -96,18 +97,6 @@ void UPP_Errors_Ranges(void) &UMinCnt, MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_UAMP_ERR)); - - /* Токи */ - int i_max = ( ERR_PRIVATE->iamp_max || - ERR_PRIVATE->ia_max || - ERR_PRIVATE->ib_max || - ERR_PRIVATE->ic_max); - ERR_PUI->OverCurrent = setError(i_max, - ERR_PUI->OverCurrent, - &IMaxCnt, - ticksTiMax); - - /* Частота */ int f_max = ( ERR_PRIVATE->fac_max || ERR_PRIVATE->fba_max || @@ -124,6 +113,17 @@ void UPP_Errors_Ranges(void) ERR_PUI->UnderFrequency, &FMinCnt, MS_TO_SLOW_TICKS(ERRORS_DELAY_MS_F_ERR)); +#endif + + /* Токи */ + int i_max = ( ERR_PRIVATE->iamp_max || + ERR_PRIVATE->ia_max || + ERR_PRIVATE->ib_max || + ERR_PRIVATE->ic_max); + ERR_PUI->OverCurrent = setError(i_max, + ERR_PUI->OverCurrent, + &IMaxCnt, + ticksTiMax); /* Температуры */ @@ -181,11 +181,12 @@ void UPP_Errors_Other(void) { static int InterlaceCnt = 0; - +#ifndef UPP_DISABLE_PROTECT_LONGSTART if(ERR_PRIVATE->longstart) ERR_PUI->LongStart = 1; else ERR_PUI->LongStart = 0; +#endif ERR_PUI->Interlace = setError(ERR_PRIVATE->interlance, ERR_PUI->Interlace, diff --git a/UPP/Core/UPP/upp_main.c b/UPP/Core/UPP/upp_main.c index fd05954..e59841b 100644 --- a/UPP/Core/UPP/upp_main.c +++ b/UPP/Core/UPP/upp_main.c @@ -111,8 +111,9 @@ int test_green2 = 0; */ int UPP_While(void) { - PWM_SetPolarity(&upp.hpwm, dbg_polarity); int retval = 0; + PWM_SetPolarity(&upp.hpwm, dbg_polarity); + if(upp.pm.adc.RawData[0] < 2000) { __NOP(); @@ -132,7 +133,7 @@ int UPP_While(void) PowerMonitor_SlowCalc(&upp.pm); // Защиты // Защиты по току включаем только после разгона и в режиме работы - PowerMonitor_Protect(&upp.pm, upp.hangle.f.RazgonDone /*&& (upp.workmode == UPP_Work)*/); + PowerMonitor_Protect(&upp.pm, upp.hangle.f.RazgonDone && (upp.workmode == UPP_Work)); #ifdef UPP_SIMULATE_I // симулируем токи upp.pm.measured.final.Iamp = upp.hangle.Iref/2; @@ -172,7 +173,6 @@ int UPP_While(void) upp.call->set_default_internal = 0; } - #ifndef UPP_DISABLE_ERROR_BLOCK // если ошибка вызываем СТОП upp.call->stop = (errors.common != Err_None); @@ -180,7 +180,10 @@ int UPP_While(void) // Если СТОП - переходим в ошибку if (upp.call->stop) + { + Angle_PID_Reset(&upp.hangle); upp.workmode = UPP_Error; + } // Автомат состояний УПП switch(upp.workmode) @@ -237,7 +240,11 @@ int UPP_While(void) UPP_DO.Error(DISABLE); // если пришла команда на остановку if (!upp.call->go) + { + Angle_PID_Reset(&upp.hangle); upp.workmode = UPP_Init; + break; + } // Коррекция для отсчета угла открытия // 30 градусов - сдвиг между линейными и фазными напряжениями diff --git a/UPP/Core/UPP/upp_status.c b/UPP/Core/UPP/upp_status.c index 76e567a..8283f2c 100644 --- a/UPP/Core/UPP/upp_status.c +++ b/UPP/Core/UPP/upp_status.c @@ -7,7 +7,7 @@ ******************************************************************************/ #include "upp_main.h" // всё остальное по работе с УПП #include "upp_status.h" - +int cnt_oscil_size = 100; void UPP_Status_Handler(void) { /* Хендлы для отладочных светодиодов (если выбран режим моргания) */ @@ -49,10 +49,25 @@ void UPP_Status_Handler(void) { mb_u_cnt = 0; } - MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_AB]+1)*127; - MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_BC]+1)*127; - MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_CA]+1)*127; - MB_INTERNAL.oscil.data[mb_u_cnt++] = local_time(); +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_AB]+1)*127; +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_BC]+1)*127; +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.U[U_CA]+1)*127; +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.I[I_A]+1)*127; +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.I[I_B]+1)*127; +// MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.pm.measured.slow.I[I_C]+1)*127; + static int cnt_oscil = 0; + + if(cnt_oscil == 0) + { + MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.hangle.Iref)*32; + MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.hangle.Imeas)*32; + MB_INTERNAL.oscil.data[mb_u_cnt++] = (upp.hangle.alpha)*127; + MB_INTERNAL.oscil.data[mb_u_cnt++] = 0; + } + if (++cnt_oscil>cnt_oscil_size) + { + cnt_oscil = 0; + } if(GPIO_Read_Switch(&UPP_DIN.Pusk)) diff --git a/UPP/MDK-ARM/UPP.uvoptx b/UPP/MDK-ARM/UPP.uvoptx index 93f9c3a..0090099 100644 --- a/UPP/MDK-ARM/UPP.uvoptx +++ b/UPP/MDK-ARM/UPP.uvoptx @@ -312,12 +312,12 @@ 12 2 - hpm->adc.RawData[3],0x0A + MB_DATA.HoldRegs.pui_params,0x0A 13 2 - MB_DATA,0x0A + MB_DATA.InRegs.pui 14 @@ -332,12 +332,12 @@ 16 2 - MB_INTERNAL + MB_INTERNAL.param,0x0A 17 2 - upp.hangle + upp.hangle,0x0A 18 @@ -349,6 +349,11 @@ 2 hmodbus1 + + 20 + 2 + cnt_oscil_size,0x0A + 0