Тесты в матлабе
А также: - Коррекция фазового сдвига фильтра - Определение порядка фаз
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
182
MATLAB/calc_filt.m
Normal file
182
MATLAB/calc_filt.m
Normal file
@@ -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
|
||||
Binary file not shown.
Reference in New Issue
Block a user