diff --git a/MATLAB/MCU_Wrapper/mcu_wrapper.c b/MATLAB/MCU_Wrapper/mcu_wrapper.c index 344e6ab..9c3888b 100644 --- a/MATLAB/MCU_Wrapper/mcu_wrapper.c +++ b/MATLAB/MCU_Wrapper/mcu_wrapper.c @@ -39,7 +39,7 @@ const int inOffsets[IN_PORT_NUMB] = { */ const int outLengths[OUT_PORT_NUMB] = { THYR_PORT_1_WIDTH, - DO_PORT_2_WIDTH, + WORK_PORT_2_WIDTH, PM_PORT_3_WIDTH, ANGLE_PORT_4_WIDTH, OUT_PORT_5_WIDTH diff --git a/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h b/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h index 80bdbe3..bc39e48 100644 --- a/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h +++ b/MATLAB/MCU_Wrapper/mcu_wrapper_conf.h @@ -60,7 +60,7 @@ #define OUT_PORT_NUMB 5 #define THYR_PORT_1_WIDTH 6 -#define DO_PORT_2_WIDTH 3 +#define WORK_PORT_2_WIDTH 48 #define PM_PORT_3_WIDTH 32 #define ANGLE_PORT_4_WIDTH 16 #define OUT_PORT_5_WIDTH 16 @@ -103,12 +103,12 @@ #define OFFSET_IN_ARRAY_3 (OFFSET_IN_ARRAY_2 + PUI_PORT_2_WIDTH) /// === Полный размер буфера === -#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + DO_PORT_2_WIDTH + PM_PORT_3_WIDTH + ANGLE_PORT_4_WIDTH + OUT_PORT_5_WIDTH) +#define TOTAL_OUT_SIZE (THYR_PORT_1_WIDTH + WORK_PORT_2_WIDTH + PM_PORT_3_WIDTH + ANGLE_PORT_4_WIDTH + OUT_PORT_5_WIDTH) /// === Смещения массивов (внутри общего буфера) === #define OFFSET_OUT_ARRAY_1 0 #define OFFSET_OUT_ARRAY_2 (OFFSET_OUT_ARRAY_1 + THYR_PORT_1_WIDTH) -#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + DO_PORT_2_WIDTH) +#define OFFSET_OUT_ARRAY_3 (OFFSET_OUT_ARRAY_2 + WORK_PORT_2_WIDTH) #define OFFSET_OUT_ARRAY_4 (OFFSET_OUT_ARRAY_3 + PM_PORT_3_WIDTH) #define OFFSET_OUT_ARRAY_5 (OFFSET_OUT_ARRAY_4 + ANGLE_PORT_4_WIDTH) diff --git a/MATLAB/app_wrapper/app_io.c b/MATLAB/app_wrapper/app_io.c index 99b49ac..0567512 100644 --- a/MATLAB/app_wrapper/app_io.c +++ b/MATLAB/app_wrapper/app_io.c @@ -10,24 +10,14 @@ float dbg_err_limit = 0; float dbg[16]; #define PIN_READ(_verbname_) (_verbname_##_GPIO_Port->ODR & (_verbname_##_Pin)) ? 1 : 0 -void pwm_wtf(PWM_State_t state1, PWM_State_t state2, int* pwm_pin) -{ - if ((*pwm_pin == 0) && (state1 == PWM_THYR_TIM_ACTIVE)) - { - *pwm_pin = 1; - } - else if ((*pwm_pin == 1) && (state2 == PWM_THYR_TIM_ACTIVE)) - { - *pwm_pin = 0; - } -} - int pwm1_pin = 0; int pwm2_pin = 0; int pwm3_pin = 0; int pwm4_pin = 0; int pwm5_pin = 0; int pwm6_pin = 0; + + void Write_UPP_Outputs(real_T* Buffer, int ind_port) { //int pwm1_pin = PIN_READ(PWM1); @@ -43,15 +33,6 @@ void Write_UPP_Outputs(real_T* Buffer, int ind_port) int pwm5_pin = (upp.hpwm.AllPhases[PHASE_C_POS].State == PWM_THYR_TIM_ACTIVE); int pwm6_pin = (upp.hpwm.AllPhases[PHASE_C_NEG].State == PWM_THYR_TIM_ACTIVE); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_A_POS].State, upp.hpwm.AllPhases[PHASE_A_NEG].State, &pwm1_pin); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_A_NEG].State, upp.hpwm.AllPhases[PHASE_A_POS].State, &pwm2_pin); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_B_POS].State, upp.hpwm.AllPhases[PHASE_B_NEG].State, &pwm3_pin); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_B_NEG].State, upp.hpwm.AllPhases[PHASE_B_POS].State, &pwm4_pin); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_C_POS].State, upp.hpwm.AllPhases[PHASE_C_NEG].State, &pwm5_pin); - //pwm_wtf(upp.hpwm.AllPhases[PHASE_C_NEG].State, upp.hpwm.AllPhases[PHASE_C_POS].State, &pwm6_pin); - int err = PIN_READ(RDO1); - int work = PIN_READ(RDO2); - int ready = upp.errors->common; if (CEN_GPIO_Port->ODR & CEN_Pin) { @@ -62,10 +43,6 @@ void Write_UPP_Outputs(real_T* Buffer, int ind_port) WriteOutputArray(0, ind_port, 4); WriteOutputArray(0, ind_port, 5); - - WriteOutputArray(0, ind_port+1, 0); - WriteOutputArray(0, ind_port+1, 1); - WriteOutputArray(0, ind_port+1, 2); } else { @@ -76,14 +53,32 @@ void Write_UPP_Outputs(real_T* Buffer, int ind_port) WriteOutputArray(pwm5_pin, ind_port, 4); WriteOutputArray(pwm6_pin, ind_port, 5); - WriteOutputArray(ready, ind_port+1, 0); - WriteOutputArray(work, ind_port+1, 1); - WriteOutputArray(err, ind_port+1, 2); } } +void Write_UPP_WorkInfo(real_T* Buffer, int ind_port) +{ + int nn = 0; + int err = PIN_READ(RDO3); + int work = PIN_READ(RDO2); + int ready = PIN_READ(RDO1); + int err_num = upp.errors->common; + + WriteOutputArray(ready, ind_port, nn++); + WriteOutputArray(work, ind_port, nn++); + WriteOutputArray(err, ind_port, nn++); + + WriteOutputArray(err_num, ind_port, nn++); + int prv_err = 0; + for (int i = 0; i < 32; i++) + { + prv_err = (errors.prvt.f.all & (1 << i)) ? 1 : 0; + WriteOutputArray(prv_err, ind_port, nn++); + } +} + void Write_PowerMonitor(real_T* Buffer, int ind_port) { int nn = 0; @@ -123,7 +118,6 @@ void Write_PowerMonitor(real_T* Buffer, int ind_port) } - void Write_AngleControl(real_T* Buffer, int ind_port) { int nn = 0; @@ -133,10 +127,19 @@ void Write_AngleControl(real_T* Buffer, int ind_port) WriteOutputArray(upp.hangle.alpha, ind_port, nn++); - WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR1) - upp.hangle.htim->Instance->CNT, ind_port, nn++); - WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR2) - upp.hangle.htim->Instance->CNT, ind_port, nn++); - WriteOutputArray((long long)(upp.hangle.htim->Instance->CCR3) - upp.hangle.htim->Instance->CNT, ind_port, nn++); +#define get_diff(ccrx) ((long long)(upp.hangle.htim->Instance->ccrx) - upp.hangle.htim->Instance->CNT) +#define diff_cnt(ccrx) \ + ((upp.workmode == UPP_Work) ? \ + ((abs(get_diff(ccrx)) > upp.hangle.alpha_tick/upp.hangle.alpha_real) ? 0 : get_diff(ccrx)) : \ + 0) + WriteOutputArray(diff_cnt(CCR1), ind_port, nn++); + WriteOutputArray(diff_cnt(CCR2), ind_port, nn++); + WriteOutputArray(diff_cnt(CCR3), ind_port, nn++); + + WriteOutputArray(upp.hangle.alpha_real, ind_port, nn++); + WriteOutputArray(upp.hangle.alpha, ind_port, nn++); + WriteOutputArray(ADC_GetPhaseCorrection(upp.pm.measured.final.Fmean)/180, ind_port, nn++); } /** @@ -196,6 +199,8 @@ void app_writeOutputBuffer(real_T* Buffer) { // USER APP OUTPUT START Write_UPP_Outputs(Buffer, 0); + Write_UPP_WorkInfo(Buffer, 1); + Write_PowerMonitor(Buffer, 2); Write_AngleControl(Buffer, 3); diff --git a/MATLAB/calc_filt.m b/MATLAB/calc_filt.m new file mode 100644 index 0000000..c5da35d --- /dev/null +++ b/MATLAB/calc_filt.m @@ -0,0 +1,182 @@ +clc, clear all + +%% Конфигурация фильтра +fs = 1000000/25; % Частота дискретизации = 40000 Гц +fc = 50; % Центральная частота фильтра = 50 Гц +fc_ratio = fc/fs; % 50/40000 = 0.00125 +bandwidth_ratio = 0.3; % Полоса 30% + +% Создаем фильтр +[b, a] = create_bandpass_filter(fc_ratio, bandwidth_ratio); + +%% 1. Расчет ФЧХ для графика (в Гц) +% Частоты для подробного графика +freqslow = 40:0.1:49; % [40 41 ... 49] Гц +freqshigh = 51:0.1:60; % [51 52 ... 60] Гц +freqscenter = 49:0.1:51; % [49.0 49.1 ... 51.0] Гц +freqs_hz = [freqslow, freqscenter, freqshigh]; % Все в Гц + +% Преобразуем в нормированные частоты (f/fs) +freqs_ratio = freqs_hz / fs; % Разделить на fs + +% Рассчитываем фазы для этих частот +phases = zeros(size(freqs_ratio)); +for i = 1:length(freqs_ratio) + phases(i) = calc_phase_at_freq(b, a, freqs_ratio(i)); +end + +% График ФЧХ (по частоте в Гц) +figure; +plot(freqs_hz, phases, 'b-', 'LineWidth', 2); +xlabel('Частота, Гц'); +ylabel('Фаза, градусы'); +title(sprintf('ФЧХ фильтра: fc=%d Гц, fs=%d Гц', fc, fs)); +grid on; +xlim([40 60]); + +%% 2. Табличный расчет (используем ТЕ ЖЕ данные!) +% Используем ТЕ ЖЕ частоты для таблицы +table_freqs_ratio = freqs_ratio; % нормированные частоты +table_phases = phases; % соответствующие фазы +table_freqs_hz = freqs_hz; % частоты в Гц + +% Вывод таблицы +fprintf('=== Таблица фазовых сдвигов ===\n'); +fprintf('f/fs\t\tФаза, °\t\tЧастота, Гц\n'); +fprintf('-------------------------------\n'); +for i = 1:length(table_freqs_hz) + fprintf('%.6f\t%6.1f\t\t%6.1f\n', ... + table_freqs_ratio(i), table_phases(i), table_freqs_hz(i)); +end + +%% 3. Проверка поиска по таблице (ближайшее значение) +% Теперь target_freq ДОЛЖНА быть в нормированных частотах! +% Например, хотим найти фазу для 53 Гц: +target_freq_hz = 53; % 53 Гц +target_freq_ratio = target_freq_hz / fs; % 53/40000 = 0.001325 + +% Ищем в таблице по нормированным частотам +phase_from_table = get_phase_from_table(table_phases, table_freqs_ratio, target_freq_ratio); +phase_exact = calc_phase_at_freq(b, a, target_freq_ratio); + +fprintf('\n=== Проверка поиска по таблице ===\n'); +fprintf('Целевая частота: %.3f Гц (%.6f f/fs)\n', target_freq_hz, target_freq_ratio); +fprintf('Из таблицы: %.1f°\n', phase_from_table); +fprintf('Точное значение: %.1f°\n', phase_exact); +fprintf('Погрешность: %.1f°\n', abs(phase_exact - phase_from_table)); + +%% 4. Дополнительная проверка на разных частотах +test_freqs_hz = [45, 49.5, 50, 50.5, 55]; % Частоты в Гц для проверки +fprintf('\n=== Проверка на разных частотах ===\n'); +fprintf('Частота, Гц\tИз таблицы\tТочное\t\tПогрешность\n'); +fprintf('-----------------------------------------------\n'); + +for i = 1:length(test_freqs_hz) + test_freq_hz = test_freqs_hz(i); + test_freq_ratio = test_freq_hz / fs; + + % Из таблицы + phase_table = get_phase_from_table(table_phases, table_freqs_ratio, test_freq_ratio); + + % Точное значение + phase_exact = calc_phase_at_freq(b, a, test_freq_ratio); + + fprintf('%6.1f\t\t%6.1f\t\t%6.1f\t\t%6.1f\n', ... + test_freq_hz, phase_table, phase_exact, abs(phase_exact - phase_table)); +end + +%% 5. Сравнение идеальной ФЧХ и табличной (ступенчатой) +figure; +% Идеальная ФЧХ (гладкая) +plot(table_freqs_hz, table_phases, 'b-', 'LineWidth', 2); +hold on; +% Табличная ФЧХ (ступенчатая) +stairs(table_freqs_hz, table_phases, 'r-', 'LineWidth', 1.5); +% Точки таблицы +plot(table_freqs_hz, table_phases, 'ko', 'MarkerSize', 5, 'MarkerFaceColor', 'k'); + +xlabel('Частота, Гц'); +ylabel('Фаза, градусы'); +title('Сравнение идеальной и табличной ФЧХ'); +legend('Идеальная ФЧХ', 'Табличная ФЧХ (ступеньки)', 'Точки таблицы', 'Location', 'best'); +grid on; +xlim([40 60]); + + + + + + + + +%% ФУНКЦИИ +function [b, a] = create_bandpass_filter(fc_ratio, bandwidth_ratio) + w0 = 2 * pi * fc_ratio; + Q = 1 / bandwidth_ratio; + alpha = sin(w0) / (2 * Q); + cos_w0 = cos(w0); + + b0_bp = alpha; + b1_bp = 0.0; + b2_bp = -alpha; + a0_bp = 1.0 + alpha; + a1_bp = -2.0 * cos_w0; + a2_bp = 1.0 - alpha; + + b0 = b0_bp / a0_bp; + b1 = b1_bp / a0_bp; + b2 = b2_bp / a0_bp; + a1 = a1_bp / a0_bp; + a2 = a2_bp / a0_bp; + + b = [b0, b1, b2]; + a = [1, a1, a2]; +end + +function phase_deg = calc_phase_at_freq(b, a, freq_ratio) + omega = 2 * pi * freq_ratio; + + cos_w = cos(omega); + sin_w = sin(omega); + cos_2w = cos(2 * omega); + sin_2w = sin(2 * omega); + + num_real = b(1) + b(2) * cos_w + b(3) * cos_2w; + num_imag = -b(2) * sin_w - b(3) * sin_2w; + + den_real = 1 + a(2) * cos_w + a(3) * cos_2w; + den_imag = -a(2) * sin_w - a(3) * sin_2w; + + den_sqr = den_real^2 + den_imag^2; + if den_sqr < 1e-12 + phase_deg = 0; + return; + end + + H_real = (num_real * den_real + num_imag * den_imag) / den_sqr; + H_imag = (num_imag * den_real - num_real * den_imag) / den_sqr; + + phase_rad = atan2(H_imag, H_real); + phase_deg = phase_rad * 180 / pi; + + while phase_deg > 180 + phase_deg = phase_deg - 360; + end + while phase_deg < -180 + phase_deg = phase_deg + 360; + end +end + +function phase_table = calc_phase_table(b, a, freq_points) + num_points = length(freq_points); + phase_table = zeros(1, num_points); + + for i = 1:num_points + phase_table(i) = calc_phase_at_freq(b, a, freq_points(i)); + end +end + +function phase = get_phase_from_table(phase_table, freq_table, target_freq) + [~, idx] = min(abs(freq_table - target_freq)); + phase = phase_table(idx); +end \ No newline at end of file diff --git a/MATLAB/upp_r2023.slx b/MATLAB/upp_r2023.slx index b12adc6..d98ecbc 100644 Binary files a/MATLAB/upp_r2023.slx and b/MATLAB/upp_r2023.slx differ diff --git a/UPP/AllLibs/MyLibs b/UPP/AllLibs/MyLibs index 795ebbd..cb3783b 160000 --- a/UPP/AllLibs/MyLibs +++ b/UPP/AllLibs/MyLibs @@ -1 +1 @@ -Subproject commit 795ebbd220fd16ba9db4d1c071ed66700c2df928 +Subproject commit cb3783bd07cd9261bf650aad086c3a5684092d0c diff --git a/UPP/Core/Configs/upp_config.h b/UPP/Core/Configs/upp_config.h index 0b19a66..b960297 100644 --- a/UPP/Core/Configs/upp_config.h +++ b/UPP/Core/Configs/upp_config.h @@ -49,7 +49,6 @@ #define PM_TEMP_SLOW_PERIOD_MS 1000 ///< Период обновлениия (фильтрации) датчиков температуры в мс #define PM_F_SLOW_PERIOD_MS 40 ///< Период обновления (фильтрации) частоты в мс #define UPP_INIT_BEFORE_READY_MS 2000 ///< Сколько сканировать сеть, перед выставлением состояния готовности -#define UPP_HALFWAVE_PERIOD 10 ///< Период полуволны. От него будет рассчитываться углы от 0 до 180 градусов /* Частоты таймеров в МГц*/ #define PWM_TIM1_FREQ_MHZ 180 ///< Частота тактирования таймера ШИМ (1-4 каналы) diff --git a/UPP/Core/Configs/upp_defs.h b/UPP/Core/Configs/upp_defs.h index 37be046..2cb857a 100644 --- a/UPP/Core/Configs/upp_defs.h +++ b/UPP/Core/Configs/upp_defs.h @@ -271,6 +271,13 @@ typedef enum { UPP_PHASE_UNKNOWN = 3 } UPP_Phase_t; +/** + * @brief Варианты последовательности фаз + */ +typedef enum { + UPP_Sequence_ABC = 0, + UPP_Sequence_BAC = 1, +} UPP_PhaseSequence_t; /** //UPP_INTERNAL_DEFS * @} */ diff --git a/UPP/Core/PowerMonitor/adc_tools.c b/UPP/Core/PowerMonitor/adc_tools.c index 0107ea1..33c5b31 100644 --- a/UPP/Core/PowerMonitor/adc_tools.c +++ b/UPP/Core/PowerMonitor/adc_tools.c @@ -6,29 +6,22 @@ * @details ******************************************************************************/ #include "adc_tools.h" + + +#define FreqTableFreqStart 40.0f +#define FreqTableFreqStep 0.1f +#define FreqTableSize 200 +float phase_table[FreqTableSize]; +float freq_table[FreqTableSize]; +//float freq_table[FreqTableSize] = { 49.0f, 49.1f, 49.2f, 49.3f, 49.4f, 49.5f, 49.6f, 49.7f, 49.8f, 49.9f, \ +// 50.0f, 50.1f, 50.2f, 50.3f, 50.4f, 50.5f, 50.6f, 50.7f, 50.8f, 50.9f, 51.0f }; static void ADC_InitAllFilters(ADC_Periodic_t *adc) { - -// FilterBandPassDerivative_Init(&adc->u_fltr[U_AB], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1); -// FilterBandPassDerivative_Init(&adc->u_fltr[U_CA], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1); -// -// FilterMedianInt_Init(&adc->i_fltr[I_C], 5, 2048); -// FilterMedianInt_Init(&adc->i_fltr[I_A], 5, 2048); -// -// FilterLUT_Init(&adc->temp_map[TEMP_1], -// (float *)adc_temp_quants, -// (float *)adc_temp_vals, -// numbof(adc_temp_quants), 1); -// FilterLUT_Init(&adc->temp_map[TEMP_2], -// (float *)adc_temp_quants, -// (float *)adc_temp_vals, -// numbof(adc_temp_quants), 1); - // Инициализация фильтров for(int i = 0; i < 2; i++) { - FilterBandPassDerivative_Init(&adc->u_fltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1); + FilterBandPass_Init(&adc->u_fltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.3); FilterMedianInt_Init(&adc->i_fltr[i], 5, 2048); FilterLUT_Init(&adc->temp_map[i], (float *)adc_temp_quants, @@ -36,6 +29,14 @@ static void ADC_InitAllFilters(ADC_Periodic_t *adc) numbof(adc_temp_quants), 1); } + float freq_temp = FreqTableFreqStart; + for (int i = 0; i < FreqTableSize; i++) + { + freq_table[i] = (freq_temp*PM_FAST_PERIOD_US)/1000000; + freq_temp += FreqTableFreqStep; + } + FilterBandPass_CalcPhaseDegTable(&adc->u_fltr[0], phase_table, freq_table, FreqTableSize); + // Запуск фильтров for(int i = 0; i < 2; i++) { @@ -45,9 +46,33 @@ static void ADC_InitAllFilters(ADC_Periodic_t *adc) } } -__STATIC_FORCEINLINE void ADC_FilterRaw(ADC_Periodic_t *adc, int ch_start, int ch_end) + +float ADC_GetPhaseCorrection(float freq) { + float target_freq = (freq * PM_FAST_PERIOD_US) / 1000000; + // Если частота меньше первой в таблице + if (target_freq <= freq_table[0]) { + return phase_table[0]; + } + // Если частота больше последней в таблице + if (target_freq >= freq_table[FreqTableSize-1]) { + return phase_table[FreqTableSize-1]; + } + + // Поиск ближайшей частоты + int best_idx = 0; + float min_diff = fabsf(target_freq - freq_table[0]); + + for (int i = 1; i < FreqTableSize; i++) { + float diff = fabsf(target_freq - freq_table[i]); + if (diff < min_diff) { + min_diff = diff; + best_idx = i; + } + } + + return phase_table[best_idx]; } /** diff --git a/UPP/Core/PowerMonitor/adc_tools.h b/UPP/Core/PowerMonitor/adc_tools.h index 1b9d4ec..5b577bd 100644 --- a/UPP/Core/PowerMonitor/adc_tools.h +++ b/UPP/Core/PowerMonitor/adc_tools.h @@ -103,7 +103,7 @@ typedef struct uint16_t RawData[ADC_NUMB_OF_CHANNELS]; ///< Сырые значения АЦП ADC_Coefs_t Coefs[ADC_NUMB_OF_REGULAR_CHANNELS]; ///< Коэффициенты @ref ADC_Coefs_t для регулярных каналов (не температуры) - FilterBandPassDerivative_t u_fltr[ADC_NUMB_OF_U_CHANNELS]; ///< Полосовой Фильтр Напряжений от шумов + FilterBandPass_t u_fltr[ADC_NUMB_OF_U_CHANNELS]; ///< Полосовой Фильтр Напряжений от шумов FilterMedianInt_t i_fltr[ADC_NUMB_OF_I_CHANNELS]; ///< Медианный Фильтр Токов от шумов FilterLUT_t temp_map[ADC_NUMB_OF_T_CHANNELS]; ///< Коррекция нелинейности датчиков температуры @@ -133,4 +133,5 @@ HAL_StatusTypeDef ADC_UpdateTemperatures(ADC_Periodic_t *adc); /* Обработка АЦП после получения данных. */ HAL_StatusTypeDef ADC_UpdateRegular(ADC_Periodic_t *adc); +float ADC_GetPhaseCorrection(float freq); #endif //_ADC_TOOLS_H_ diff --git a/UPP/Core/PowerMonitor/power_monitor.c b/UPP/Core/PowerMonitor/power_monitor.c index 3f269c3..d6abab1 100644 --- a/UPP/Core/PowerMonitor/power_monitor.c +++ b/UPP/Core/PowerMonitor/power_monitor.c @@ -68,16 +68,6 @@ HAL_StatusTypeDef PowerMonitor_Init(PowerMonitor_t *hpm) Filter_Start(&hpm->avg[ADC_TEMP_CHANNELS_START+i]); } - /* Инициализация фильтра для сглаживания синусоиды*/ - for(int i = 0; i < 2; i++) - { -// if(FilterBandPassDerivative_Init(&hpm->ufltr[i], (50.0f*PM_FAST_PERIOD_US/1000000), 0.1)) -// return HAL_ERROR; -// -// Filter_Start(&hpm->ufltr[i]); - } - - return HAL_OK; } @@ -210,6 +200,22 @@ void PowerMonitor_FastCalc(PowerMonitor_t *hpm) /* Ищем переход через ноль */ ZC_ProcessAllChannels(&hpm->zc, meas->fast.U, usTick); + /* Определяем порядок фаз */ + if(ZC_isOccurred(&hpm->zc, U_CA)) + { + if(meas->fast.U[U_CA] > 0) + { + if(meas->fast.U[U_BC] > meas->fast.U[U_AB]) + { + meas->final.PhaseSequence = UPP_Sequence_ABC; + } + else + { + meas->final.PhaseSequence = UPP_Sequence_BAC; + } + } + } + /* Вообще фильтры должны рабтоать синхронно, но на всякий синхронизация */ //__SynchAvgFilters(hpm); diff --git a/UPP/Core/PowerMonitor/power_monitor.h b/UPP/Core/PowerMonitor/power_monitor.h index a9fa87d..fa9f793 100644 --- a/UPP/Core/PowerMonitor/power_monitor.h +++ b/UPP/Core/PowerMonitor/power_monitor.h @@ -58,18 +58,19 @@ typedef struct */ typedef struct { - /** @brief Усредненные величины (о.е.) */ + /** @brief Финальные величины (о.е.) */ struct { - float Uamp; ///< Результирующий вектор Напряжения по трем фазам - float Iamp; ///< Результирующий вектор Тока по трем фазам - float U[3]; ///< Среднее Наряжение по трем фазам - float I[3]; ///< Средний Ток по трем фазам - float Fmean; ///< Средняя Частота по трем фазам - float F[3]; ///< Частота от Zero Cross (обновляется в main) - float Phase[3]; ///< Фазовое смещение по отношению к фазе A - float Offset[3]; ///< Смещение синуса относителньо нуля (определяется по отношению полупериодов) - float T[2]; ///< Температура (обновляется в main) + float Uamp; ///< Результирующий вектор Напряжения по трем фазам + float Iamp; ///< Результирующий вектор Тока по трем фазам + float U[3]; ///< Среднее Наряжение по трем фазам + float I[3]; ///< Средний Ток по трем фазам + float Fmean; ///< Средняя Частота по трем фазам + float F[3]; ///< Частота от Zero Cross (обновляется в main) + float T[2]; ///< Температура (обновляется в main) + float PhaseOffset[3]; ///< Фазовое смещение по отношению к фазе A + float AmpOffset[3]; ///< Смещение синуса относителньо нуля (определяется по отношению полупериодов) + UPP_PhaseSequence_t PhaseSequence; ///< Определенный порядок фаз }final; /** @brief Быстрые величины (в о.е.) - обновляются в каждом прерывании АЦП @ref PowerMonitor_FastCalc */ @@ -105,7 +106,7 @@ typedef struct PowerMonitor_Measured_t measured; ///< Измеренные/рассчитанные величины - FilterBandPassDerivative_t ufltr[2]; ///< Фильтры для сглаживаний напряжений в синусы + FilterBandPass_t ufltr[2]; ///< Фильтры для сглаживаний напряжений в синусы FilterRMS_t rms[RMS_ALL]; ///< Фильтры для расчета действующего значения Напряжения/Токов FilterExp_t rms_exp[RMS_EXP_ALL]; ///< Фильтры для сглаживания действующего значения Напряжения/Токов +2 для результируюзих U, I FilterAverage_t avg[AVG_ALL]; ///< Фильтры для сглаживания медленных величин АЦП diff --git a/UPP/Core/PowerMonitor/power_protect.c b/UPP/Core/PowerMonitor/power_protect.c index e5c2f17..ea9ce19 100644 --- a/UPP/Core/PowerMonitor/power_protect.c +++ b/UPP/Core/PowerMonitor/power_protect.c @@ -19,7 +19,7 @@ int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *params, /* Переводим уставки ПУИ в удобный вид */ float lUmin = u2f(params->Umin, 100)/**u2f(nominal->U, 10)*/; float lUmax = u2f(params->Umax, 100)/**u2f(nominal->U, 10)*/; - float lPhaseSequence = u2f(nominal->PhaseSequence, 100); + UPP_PhaseSequence_t nomPhaseSequence = nominal->PhaseSequence; /* Общее напряжение */ if(measure->final.Uamp > lUmax) @@ -36,9 +36,8 @@ int Protect_Voltages(PowerMonitor_Measured_t *measure, UPP_PUI_Params_t *params, ERR_PRIVATE->uamp_min = 0; } - /* Последовательность фаз */ - int realPhaseSequence = 0; - if(realPhaseSequence != lPhaseSequence) + /* Последовательность фаз */ + if(measure->final.PhaseSequence != nomPhaseSequence) { ERR_PRIVATE->interlance = 1; } diff --git a/UPP/Core/PowerMonitor/zero_cross.c b/UPP/Core/PowerMonitor/zero_cross.c index b60c8c8..19863b4 100644 --- a/UPP/Core/PowerMonitor/zero_cross.c +++ b/UPP/Core/PowerMonitor/zero_cross.c @@ -239,10 +239,23 @@ int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel) return 0; } int occurred = zc->Channel[channel].Occurred; - zc->Channel[channel].Occurred = 0; +// zc->Channel[channel].Occurred = 0; return occurred; } +/** + * @brief Сбросить флаг - переход произошел. + * @param zc Указатель на хендл детектора нуля + * @param channel Номер канала + * @return 1 - переход произошел, 0 - перехода не было. + */ +void ZC_resetOccurred(ZeroCross_Handle_t *zc, uint8_t channel) +{ + if (assert_upp(zc)){ + return; + } + zc->Channel[channel].Occurred = 0; +} /** * @brief Получение полуволны (после последнего zero-cross). * @param zc Указатель на хендл детектора нуля diff --git a/UPP/Core/PowerMonitor/zero_cross.h b/UPP/Core/PowerMonitor/zero_cross.h index 08857a8..4117521 100644 --- a/UPP/Core/PowerMonitor/zero_cross.h +++ b/UPP/Core/PowerMonitor/zero_cross.h @@ -153,6 +153,8 @@ void ZC_ProcessAllChannels(ZeroCross_Handle_t *zc, float *values, // ====== API ========== /* Полученить флаг - переход произошел. */ int ZC_isOccurred(ZeroCross_Handle_t *zc, uint8_t channel); +/* Сбросить флаг - переход произошел. */ +void ZC_resetOccurred(ZeroCross_Handle_t *zc, uint8_t channel); /* Получение частоты сигнала */ float ZC_GetFrequency(ZeroCross_Handle_t *zc, uint8_t channel); /* Получение смещение частот полупериода сигнала */ diff --git a/UPP/Core/UPP/angle_control.c b/UPP/Core/UPP/angle_control.c index 875ed88..d3af143 100644 --- a/UPP/Core/UPP/angle_control.c +++ b/UPP/Core/UPP/angle_control.c @@ -33,8 +33,7 @@ HAL_StatusTypeDef Angle_Init(Angle_Handle_t *hangle) Angle_Reset(hangle, UPP_PHASE_C); - hangle->f.Initialized = 1; - hangle->Config.PeriodLimit = 1; + hangle->f.Initialized = 1; return HAL_OK; } @@ -146,15 +145,23 @@ HAL_StatusTypeDef Angle_SetAlpha(Angle_Handle_t *hangle, float Alpha, float Corr { if(assert_upp(hangle)) return HAL_ERROR; - + if(Alpha > hangle->Config.AngleMax) Alpha = hangle->Config.AngleMax; if(Alpha < hangle->Config.AngleMin) - Alpha = hangle->Config.AngleMin; + Alpha = hangle->Config.AngleMin; + + float AlphaCorrect = Alpha + (Correction/180.0); + + if(AlphaCorrect > 1) + AlphaCorrect = 1; + + if(AlphaCorrect < 0) + AlphaCorrect = 0; // сколько надо выжидать исходя из заданного угла - hangle->alpha_real = Alpha + (Correction/180.0); + hangle->alpha_real = AlphaCorrect; hangle->alpha = Alpha; @@ -174,9 +181,9 @@ HAL_StatusTypeDef Angle_Start(Angle_Handle_t *hangle, UPP_Phase_t Phase, float P return HAL_ERROR; // сколько тиков надо выждать для угла - uint32_t timer_ticks = TIM_MillisToTick(PeriodMs*hangle->alpha_real, ANGLE_TIM2_FREQ_MHZ); + hangle->alpha_tick = TIM_MillisToTick(PeriodMs*hangle->alpha_real, ANGLE_TIM2_FREQ_MHZ); // сколько тиков будет в таймере когда угол отсчитается (пойдет в CCRx регистр) - uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + timer_ticks; + uint32_t ccr_ticks = __HAL_TIM_GET_COUNTER(hangle->htim) + hangle->alpha_tick; // Выставялем switch(Phase) @@ -272,34 +279,10 @@ HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase) -/** - * @brief Инициализация предельного угла открытия. - * @param hangle Указатель на таймер - * @param PeriodLimit Лимит AngleMax, рассчитывается от параметров ШИМ - * @param AngleMin Минимально возможный угол открытия - * @param AngleMax Максимально возможный угол открытия - * @return HAL Status. - */ -HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float PeriodLimit) -{ - if(assert_upp(hangle)) - return HAL_ERROR; - if(hangle->f.Running) - return HAL_BUSY; - - if(PeriodLimit <= 0 || PeriodLimit > 1) - return HAL_ERROR; - - hangle->Config.PeriodLimit = PeriodLimit; - - return HAL_OK; -} - /** * @brief Инициализация углов открытия. * @param hangle Указатель на таймер - * @param PeriodLimit Лимит AngleMax, рассчитывается от параметров ШИМ * @param AngleMin Минимально возможный угол открытия * @param AngleMax Максимально возможный угол открытия * @return HAL Status. diff --git a/UPP/Core/UPP/angle_control.h b/UPP/Core/UPP/angle_control.h index cfad508..d957c96 100644 --- a/UPP/Core/UPP/angle_control.h +++ b/UPP/Core/UPP/angle_control.h @@ -13,7 +13,6 @@ */ typedef struct { - float PeriodLimit; ///< Лимит периода, выше которого нельзя выставить рассчитывается от параметров ШИМ float AngleMin; ///< Минимально возможный угол открытия float AngleMax; ///< Максимально возможный угол открытия }Angle_Config_t; @@ -28,12 +27,11 @@ typedef struct float Iref; ///< текущее задание тока в о.е. [0..1] float Imeas; ///< измеренное значение тока в о.е. [0..1] - float alpha; ///< текущий угол открытия в о.е. [0..1] от 180 градусов - + float alpha; ///< текущий угол открытия в о.е. [0..1] от 180 градусов float alpha_real; /*!< @brief Фактический отсчитываемый угол открытия в о.е. [0..1] от 180 градусов - @details Этот угол отличается от @ref alpha дополнительными задержками и компенсациями: - - 30 градусов - смещение между линейными и фазными напряжение (мы смотрим линейные, а коммутируем фазные) */ + @details Этот угол отличается от @ref alpha дополнительными задержками и компенсациями*/ + float alpha_tick; ///< текущий угол открытия в тиках таймера arm_pid_instance_f32 pid; ///< ПИД регулятор для управления углом FilterExp_t refFilter; ///< Фильтр для плавного нарастания регулирования @@ -66,8 +64,6 @@ HAL_StatusTypeDef Angle_Reset(Angle_Handle_t *hangle, UPP_Phase_t Phase); void Angle_PID_Reset(Angle_Handle_t *hangle); // ====== СЕРВИС ========== -/* Инициализация предельного угла открытия. */ -HAL_StatusTypeDef Angle_SetLimit(Angle_Handle_t *hangle, float PeriodLimit); /* Инициализация углов открытия. */ HAL_StatusTypeDef Angle_SetRange(Angle_Handle_t *hangle, float AngleMin, float AngleMax); /* Хендл таймера для рассчета угла открытия. */ diff --git a/UPP/Core/UPP/upp_errors.h b/UPP/Core/UPP/upp_errors.h index fdebec0..ba3e32b 100644 --- a/UPP/Core/UPP/upp_errors.h +++ b/UPP/Core/UPP/upp_errors.h @@ -87,7 +87,7 @@ typedef struct unsigned temp_err:1; unsigned longstart:1; - unsigned interlance:3; + unsigned interlance:1; unsigned overrun_slow_calc:1; unsigned overrun_fast_calc:1; diff --git a/UPP/Core/UPP/upp_main.c b/UPP/Core/UPP/upp_main.c index ecf5ae7..df03fa9 100644 --- a/UPP/Core/UPP/upp_main.c +++ b/UPP/Core/UPP/upp_main.c @@ -191,8 +191,8 @@ int UPP_While(void) // Коррекция для отсчета угла открытия // 30 градусов - сдвиг между линейными и фазными напряжениями - // 0 градусов - фазовое смщеение эксп. фильтра АЦП для сглаживания напряжений - float Correction = 30 + 0; + // ADC_GetPhaseCorrection фазовое смщеение полосового фильтра АЦП для сглаживания напряжений + float Correction = 30 + ADC_GetPhaseCorrection(upp.pm.measured.final.Fmean); // Регулирование тиристоров Angle_PID(&upp.hangle, u2f(PARAM_PUI->Iref,100), upp.pm.measured.final.Iamp, Correction); @@ -283,11 +283,13 @@ void UPP_ADC_Handle(void) PowerMonitor_FastCalc(&upp.pm); + for(int phase = 0; phase < 3; phase++) { // Если произошел Zero Cross if(ZC_isOccurred(&upp.pm.zc, phase)) { + ZC_resetOccurred(&upp.pm.zc, phase); // Если УПП в работе if(upp.workmode == UPP_Work) { @@ -295,7 +297,8 @@ void UPP_ADC_Handle(void) UPP_HalfWave_t curr_halfwave = ZC_GetHalfWave(&upp.pm.zc, phase); res = PWM_SetHalfWave(&upp.hpwm, phase, curr_halfwave); // Начинаем отсчитывать угол - res = Angle_Start(&upp.hangle, phase, UPP_HALFWAVE_PERIOD); + int voltage_halfwave_period = 1.0f/(upp.pm.measured.final.F[phase]*2)*1000; + res = Angle_Start(&upp.hangle, phase, voltage_halfwave_period); if(res != HAL_OK) __NOP(); } @@ -303,7 +306,7 @@ void UPP_ADC_Handle(void) } // ШИМим ключи - res = PWM_Handle(&upp.hpwm, UPP_HALFWAVE_PERIOD); + res = PWM_Handle(&upp.hpwm, 10); upp.Timings.isr_adc_us = BenchTime_End(BT_ADC, angletim.Instance->CNT)/ANGLE_TIM2_FREQ_MHZ; upp.pm.f.inIsr = 0; diff --git a/UPP/Core/UPP/upp_params.c b/UPP/Core/UPP/upp_params.c index d50f6f5..7bea2bd 100644 --- a/UPP/Core/UPP/upp_params.c +++ b/UPP/Core/UPP/upp_params.c @@ -221,7 +221,6 @@ void UPP_Params_ControlInternal(void) // Обновление регулятора угла открытия - __AngleSetLimit(); if(alpha_update) { if(Angle_SetRange(&upp.hangle, angle_min, angle_max) == HAL_OK) @@ -472,15 +471,6 @@ void UPP_Params_SetDefault(int pui_default, int internal_default) #define ANGLE_PERIOD_MS(_freq_) (((float)1/(_freq_*2))*1000) -// Перерасчет максимально допустимого угла -static void __AngleSetLimit(void) -{ // Сколько пачка ипульсов занимает процентов от всего периода - float pulses_percent_of_period = (((float)PARAM_INTERNAL->pwm.PulseLength / PARAM_INTERNAL->pwm.Frequency) * 1000) / ANGLE_PERIOD_MS(upp.pm.measured.final.Fmean); - // Вычитаем этот процент из 1 - получаем максимально безопасный угол - float angle_limit = 1; - angle_limit -= pulses_percent_of_period*u2f(PARAM_INTERNAL->angle.PulseLengthReserve, 100); // добавляем запас в PulseLengthReserve процентов от пачки импульсов - Angle_SetLimit(&upp.hangle, angle_limit); -} diff --git a/UPP/MDK-ARM/UPP.uvoptx b/UPP/MDK-ARM/UPP.uvoptx index 283c5c4..2f1f9f3 100644 --- a/UPP/MDK-ARM/UPP.uvoptx +++ b/UPP/MDK-ARM/UPP.uvoptx @@ -339,18 +339,18 @@ 0 0 - 50 + 38 1 -
134253566
+
134219914
0 0 0 0 0 1 - ../Core/Src/usart.c + ..\Core\PowerMonitor\adc_tools.c - \\Debug_F417\../Core/Src/usart.c\50 + \\Debug_F417\../Core/PowerMonitor/adc_tools.c\38
@@ -384,6 +384,16 @@ 1 pclk,0x0A + + 6 + 1 + freq_table + + + 7 + 1 + phase_table + 0 @@ -1057,7 +1067,7 @@ MyLibs - 0 + 1 0 0 0