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