Repository navigation
Expand file tree
/
Copy patht40_variant_subsystem.m
More file actions
191 lines (163 loc) · 8.25 KB
/
Copy patht40_variant_subsystem.m
File metadata and controls
191 lines (163 loc) · 8.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
%% ============================================================
% 教程 40:Variant Subsystem — 一个模型塞下多套方案
%
% 【为什么要学这课】
% 你设计了三种控制器——PID、LQR、SMC。想对比效果?
% 常规做法:复制三个模型,每个换一个控制器 → 改一处要同步三处 → 灾难。
%
% Variant Subsystem 让你在一个模型里放三套控制方案,
% 通过一个变量切换——不用复制粘贴,不用手动改连线。
%
% ┌─────────────────────────────────────────────────────────┐
% │ Variant Subsystem 结构 │
% ├─────────────────────────────────────────────────────────┤
% │ │
% │ Variant Subsystem (ctrl_type == 1 → PID) │
% │ (ctrl_type == 2 → LQR) │
% │ (ctrl_type == 3 → SMC) │
% │ │
% │ 输入 e → [PID block] ← ctrl_type=1 时激活 │
% │ → [LQR block] ← ctrl_type=2 时激活 │
% │ → [SMC block] ← ctrl_type=3 时激活 │
% │ → 输出 u │
% └─────────────────────────────────────────────────────────┘
%
% 【本课目标】
% 1. 用 Variant Subsystem 在一个模型里放 3 种控制器
% 2. 通过 workspace 变量切换激活哪个
% 3. 一键对比三种方案的效果
% ============================================================
clear; close all; bdclose('all');
addpath(fullfile(fileparts(mfilename('fullpath')), 'utils'));
fprintf('============================================\n');
fprintf(' 教程 40:Variant Subsystem\n');
fprintf('============================================\n\n');
%% ===== 第 1 步:搭 Plant + Variant 控制器 =====
mdl = 'tutorial40_variant';
addpath(fullfile(fileparts(mfilename('fullpath')), 'models'));
if bdIsLoaded(mdl), close_system(mdl, 1); end
new_system(mdl, 'Model');
open_system(mdl);
% 二阶 Plant (和 t05 一样)
add_block('simulink/Continuous/Transfer Fcn', [mdl '/Plant'], ...
'Position', [400, 60, 500, 110]);
set_param([mdl '/Plant'], 'Numerator', '[1]', 'Denominator', '[1 0.5 1]');
add_block('simulink/Sources/Step', [mdl '/Setpoint'], ...
'Position', [30, 70, 90, 100]);
set_param([mdl '/Setpoint'], 'Time', '0.5', 'After', '1');
add_block('simulink/Math Operations/Sum', [mdl '/Error'], ...
'Position', [120, 65, 150, 95]);
set_param([mdl '/Error'], 'Inputs', '|+-');
% Variant Subsystem
add_block('simulink/Ports & Subsystems/Variant Subsystem', ...
[mdl '/Controller'], 'Position', [220, 40, 320, 130]);
% 设置 Variant 条件 (在 Variant Subsystem 内部用 Variant choices)
% 先把内部的空 Subsystem 换成三个带条件的 Subsystem
sub_root = [mdl '/Controller'];
% 删除默认的 variant choice(保留顶层 In1/Out1 作为接口端口)
delete_block([sub_root '/Subsystem']);
% PID 方案
add_block('simulink/Ports & Subsystems/Subsystem', [sub_root '/PID'], ...
'Position', [120, 20, 200, 100]);
Simulink.SubSystem.deleteContents([sub_root '/PID']);
pid_root = [sub_root '/PID'];
add_block('simulink/Ports & Subsystems/In1', [pid_root '/In1'], 'Position', [30,50,50,70]);
add_block('simulink/Math Operations/Gain', [pid_root '/Kp'], 'Position', [100,50,140,80]);
set_param([pid_root '/Kp'], 'Gain', '3');
add_block('simulink/Ports & Subsystems/Out1', [pid_root '/Out1'], 'Position', [230,50,250,70]);
add_line(pid_root, 'In1/1', 'Kp/1');
add_line(pid_root, 'Kp/1', 'Out1/1');
set_param([sub_root '/PID'], 'VariantControl', 'ctrl_type == 1');
% LQR 方案 (简化: 放大增益)
add_block('simulink/Ports & Subsystems/Subsystem', [sub_root '/LQR'], ...
'Position', [120, 120, 200, 200]);
Simulink.SubSystem.deleteContents([sub_root '/LQR']);
lqr_root = [sub_root '/LQR'];
add_block('simulink/Ports & Subsystems/In1', [lqr_root '/In1'], 'Position', [30,50,50,70]);
add_block('simulink/Math Operations/Gain', [lqr_root '/K_lqr'], 'Position', [100,50,140,80]);
set_param([lqr_root '/K_lqr'], 'Gain', '5');
add_block('simulink/Ports & Subsystems/Out1', [lqr_root '/Out1'], 'Position', [230,50,250,70]);
add_line(lqr_root, 'In1/1', 'K_lqr/1');
add_line(lqr_root, 'K_lqr/1', 'Out1/1');
set_param([sub_root '/LQR'], 'VariantControl', 'ctrl_type == 2');
% SMC 方案 (简化: 饱和)
add_block('simulink/Ports & Subsystems/Subsystem', [sub_root '/SMC'], ...
'Position', [250, 20, 330, 100]);
Simulink.SubSystem.deleteContents([sub_root '/SMC']);
smc_root = [sub_root '/SMC'];
add_block('simulink/Ports & Subsystems/In1', [smc_root '/In1'], 'Position', [30,50,50,70]);
add_block('simulink/Math Operations/Gain', [smc_root '/K_smc'], 'Position', [100,50,140,80]);
set_param([smc_root '/K_smc'], 'Gain', '8');
add_block('simulink/Discontinuities/Saturation', [smc_root '/Sat'], ...
'Position', [190,50,230,80]);
set_param([smc_root '/Sat'], 'UpperLimit', '5', 'LowerLimit', '-5');
add_block('simulink/Ports & Subsystems/Out1', [smc_root '/Out1'], 'Position', [310,50,330,70]);
add_line(smc_root, 'In1/1', 'K_smc/1');
add_line(smc_root, 'K_smc/1', 'Sat/1');
add_line(smc_root, 'Sat/1', 'Out1/1');
set_param([sub_root '/SMC'], 'VariantControl', 'ctrl_type == 3');
% Variant Subsystem 接口端口自动路由(In1/Out1 同名匹配),无需内部连线
% To Workspace
add_block('simulink/Sinks/To Workspace', [mdl '/ws_y'], ...
'Position', [550, 60, 600, 85]);
set_param([mdl '/ws_y'], 'VariableName', 'y_data');
% 顶层连线
add_line(mdl, 'Setpoint/1', 'Error/1');
add_line(mdl, 'Error/1', 'Controller/1');
add_line(mdl, 'Controller/1', 'Plant/1');
add_line(mdl, 'Plant/1', 'Error/2');
add_line(mdl, 'Plant/1', 'ws_y/1');
Simulink.BlockDiagram.arrangeSystem(mdl);
model_path = fullfile(fileparts(mfilename('fullpath')), 'models', [mdl '.slx']);
save_system(mdl, model_path);
%% ===== 第 2 步:三种方案对比 =====
fprintf('【Step 2: 依次运行三种控制器】\n\n');
ctrl_types = [1, 2, 3];
ctrl_names = {'PID', 'LQR', 'SMC'};
K_gains = {'3', '5', '8'};
colors = {'b', 'r', 'g'};
figure('Name', 't40: Variant Subsystem — 三种控制器对比', ...
'Position', [50, 50, 900, 600]);
for ct = 1:3
assignin('base', 'ctrl_type', ctrl_types(ct));
set_param(mdl, 'StopTime', '5');
simOut = sim(mdl);
t = simOut.tout;
y = getSimData(simOut, 'y_data', t);
subplot(2,2,ct);
plot(t, y, colors{ct}, 'LineWidth', 2); hold on;
yline(1, 'k--');
title(sprintf('%s (ctrl_type=%d, K=%s)', ctrl_names{ct}, ctrl_types(ct), ...
K_gains{ct}));
xlabel('Time (s)'); ylabel('Output'); grid on;
fprintf(' %s: 稳态误差 = %.3f\n', ctrl_names{ct}, abs(1 - y(end)));
end
% 合并对比
subplot(2,2,4);
for ct = 1:3
assignin('base', 'ctrl_type', ctrl_types(ct));
simOut = sim(mdl);
t = simOut.tout;
y = getSimData(simOut, 'y_data', t);
plot(t, y, colors{ct}, 'LineWidth', 1.5); hold on;
end
yline(1, 'k--');
legend(ctrl_names, 'Location', 'southeast');
title('三种控制器叠加对比');
xlabel('Time (s)'); ylabel('Output'); grid on;
close_system(mdl, 0);
sgtitle('教程 40:Variant Subsystem — 一键切换三套控制方案');
fprintf('\n========================================\n');
fprintf(' 教程 40 完成!\n');
fprintf('========================================\n\n');
fprintf('【关键收获】\n');
fprintf(' 1. Variant Subsystem = 可控的选择器\n');
fprintf(' ctrl_type=1 → PID, =2 → LQR, =3 → SMC\n');
fprintf(' → 不用改模型,只改变量就切换\n\n');
fprintf(' 2. VariantControl 条件\n');
fprintf(' set_param(block, ''VariantControl'', ''ctrl_type == 1'')\n');
fprintf(' → 当条件为 true 时该 variant 被激活\n\n');
fprintf(' 3. 工程用法\n');
fprintf(' - A/B 测试不同控制方案\n');
fprintf(' - 同一个模型适配不同硬件配置\n');
fprintf(' - 仿真用简化版, 部署用精确版\n');