简介:这是一套基于Matlab平台、采用深度确定性策略梯度(DDPG)算法对滑模控制(SMC)进行参数优化的Simulink仿真工具,面向计算机、电子信息工程、数学等专业大学生及需要开展智能控制研究的工程技术人员。压缩包共32个文件,包含m脚本、slx模型、mat数据、xml配置等,其中12个m文件用于算法实现与参数设置,6个slx模型可直接搭建SMC调参环境,6个mat数据文件提供案例输入,整体仅235KB,轻量且易于部署。已有135人学习/下载。代码采用参数化编程,关键参数可灵活修改,注释明细、思路清晰;附赠案例数据,运行matlab程序即可复现仿真结果。借助Simulink可视化环境,可直观观察DDPG在线调整SMC参数的过程,帮助读者深入理解强化学习与控制理论结合的实践方法,适合用于课程设计、期末大作业或毕业设计中的智能控制模块开发。
1. 把 DDPG 塞进 SMC 调参里,到底值不值
做控制的人都知道,滑模控制(SMC)的切换增益、边界层厚度、趋近律系数,每一个参数都直接影响抖振和鲁棒性。手动试凑在标称模型上勉强能用,但负载突变、参数摄动一来,原来的参数就失灵。深度确定性策略梯度(DDPG)是一种适合连续动作空间的强化学习算法,恰好可以把这个“试参数”的过程转化为策略优化问题。这份名为DDPG_SMC-main的资源,就是一套在 Matlab/Simulink 环境下用 DDPG 自动调整 SMC 参数的完整仿真工具,附带 workspace、slprj 工程文件和可直接运行的案例数据。对于正在做课程设计、毕业设计,或者想验证“强化学习 + 滑模控制”思路的工程师,它提供了一条从环境搭建到训练评估的完整路径。
2. DDPG 与 SMC 结合的机理:连续动作空间里的策略搜索
2.1 滑模控制参数为什么难调
滑模控制的核心是设计一个滑模面 s(x),然后通过切换控制律把系统状态驱动到滑模面上并保持滑模运动。典型的控制器输出由等效控制 u_eq 和切换控制 u_sw 组成:
u = u_eq + u_sw; u_sw = -k * sign(s);这里的 k 是切换增益,sign(s) 是符号函数。k 取得太小,系统无法克服扰动,滑模面到达不了;k 取得太大,抖振剧烈,执行机构磨损,还可能激励未建模动态。边界层厚度 phi 也类似——把 sign(s) 换成 sat(s/phi) 可以抑制抖振,但 phi 太大会损失跟踪精度。传统做法是根据匹配条件和不确性上界估算 k,但那个上界往往是保守的,实际系统里很少能用那么大的增益。
更麻烦的是,SMC 参数之间不是独立的。增大 k 能提高鲁棒性,但会放大抖振;增大 phi 能削弱抖振,但会增大稳态误差。系统状态不同阶段对参数的需求也不一样——趋近阶段需要大增益快速收敛,滑模阶段希望减小切换幅值。静态参数无法同时满足这两个需求。
所以就有了“调参优化”的问题。DDPG 在这里做的事情,不是一次性给出最优参数,而是学习一个策略函数:根据当前系统状态(比如误差、误差变化率、滑模面值和它的导数),输出一组合理的 SMC 参数增量。这样一来,SMC 的参数是动态变化的,比固定参数更适合非线性、时变对象。
2.2 DDPG 如何把调参变成序贯决策问题
2.2.1 状态、动作、奖励的定义
用 DDPG 调 SMC 参数,本质是构造一个马尔可夫决策过程(MDP)。状态需要能反映系统当前的控制品质和控制难度。常见做法是把状态取为:
state = [e; de; s; ds]; % e: 跟踪误差 % de: 误差变化率 % s: 滑模面函数值 % ds: 滑模面的导数动作就是需要调整的 SMC 参数。这份资源里最典型的动作空间是二维的,例如切换增益 k 和边界层厚度 phi,或者再增加一个趋近律系数。动作可以定义为参数的增量,也可以定义为一个缩放因子:
k_new = k_old + action(1) * k_scale; phi_new = phi_old + action(2) * phi_scale; % 限制动作范围,防止参数越界导致系统发散 k_new = max(k_min, min(k_max, k_new));奖励函数的设计直接决定学习方向。如果只惩罚误差平方积分(ISE),agent 会倾向于把增益拉高,抖振加剧;如果只惩罚抖振,跟踪精度又不行。比较实用的奖励函数是把误差、控制量变化率和滑模面三者加权:
reward = - (w1 * e^2 + w2 * (u(k) - u(k-1))^2 + w3 * s^2) * dt; % w1,w2,w3 权重系数,需要按实际系统量纲调整这里把控制量变化率放进奖励,本质上是对抖振的间接惩罚。滑模面 s 本身很小的时候,说明系统已经进入滑模运动,这时候就不需要太大的切换增益,agent 可以通过学习意识到这一点,从而自动降低 k。
2.2.2 网络结构与更新流程
DDPG 包含四个网络:在线 actor、目标 actor、在线 critic、目标 critic。Actor 网络输入状态,输出动作;Critic 网络输入状态和动作,输出 Q 值。更新流程是经典的软更新方式:
% Critic 损失:最小化 TD 误差 td_error = reward + gamma * target_critic(next_state, target_actor(next_state)) - critic(state, action); critic_loss = mean(td_error.^2); % Actor 损失:最大化 Q 值(这里的负号用于梯度下降) actor_loss = -mean(critic(state, actor(state))); % 软更新目标网络 target_actor = tau * actor + (1 - tau) * target_actor; target_critic = tau * critic + (1 - tau) * target_critic;在 Simulink 里做这件事,有两种思路。一种是把整个模型写成 Level-2 MATLAB Function,在回调函数里调用 agent 的 step 方法;另一种是用 Reinforcement Learning Toolbox 的 RL Agent 模块,直接接收观测输入,输出动作给被控对象。压缩包里的slprj目录说明它走的是 Simulink 代码生成和仿真缓存,更像前者——通过 MATLAB 脚本控制仿真循环,在每个控制周期里调用 DDPG 的 action 计算函数。
2.3 在 Simulink 里搭强化学习环境的常见做法
如果是从零开始搭,我一般会先把被控对象和 SMC 控制器放在一个单独的.slx模型里,把控制器要用的状态通过 outport 引出,把 SMC 参数通过 inport 引入。然后在训练脚本里,用set_param修改模型参数或直接给 inport 赋值,用sim跑一个 episode。
一个 episode 的流程是:初始化系统状态 → 循环每一步:从模型输出提取状态 → 调用 agent 得到动作 → 把动作映射为 SMC 参数 → 执行一步仿真 → 计算奖励 → 存储经验 → 更新网络。这份资源里的.gitignore和reference目录,大概率记录了某一个参考版本或基准控制器,用来对比训练前后的控制效果。
3. 工程落地:从 workspace 到 slprj 的完整链路
3.1 压缩包里有什么:目录与文件作用
解压后根目录是DDPG_SMC-main,核心内容围绕 Matlab 工作区和 Simulink 工程文件组织。典型的文件结构如下:
DDPG_SMC-main/ ├── workspace/ # 保存数据、日志、训练好的网络参数 ├── slprj/ # Simulink 缓存目录,放编译中间产物 ├── reference/ # 参考实现或基准控制器代码 ├── .gitignore # Git 忽略规则,通常忽略 slprj 和缓存 ├── README.md # 项目说明 └── 主训练脚本.m # 入口脚本,通常是 run_training.m 之类workspace目录里存放的是 mat 文件,比如训练过程中的 reward 曲线、网络参数 checkpoint、被控对象参数。slprj是 Simulink 自动生成的工程缓存,里面是目标语言编译器(TLC)和代码生成器产生的中间文件。这个目录不需要手工修改,但注意如果要移动整个项目,最好在 Matlab 里通过openProject打开.prj文件,让 Simulink 自己刷新路径和缓存。
3.2 环境配置与版本兼容(2014 / 2019a / 2024a)
资源描述说明支持 Matlab 2014、2019a、2024a。这三个版本差异很大,尤其是 Reinforcement Learning Toolbox 在 2019a 之后才逐渐成熟。2014 版本里没有rlDDPGAgent这样的类,所以代码里的 DDPG 大概率是基于神经网络工具箱手写的实现,而不是调用官方 RL 工具箱。2019a 和 2024a 则可以用官方工具箱跑。
如果你用的是 2024a,建议先检查工具箱是否齐全:
ver('ReinforcementLearningToolbox') ver('Simulink') ver('DeepLearningToolbox')如果输出为空,说明没装对应工具箱。手写版 DDPG 只需要 Deep Learning Toolbox,不需要额外的强化学习工具箱,所以 2014 版也能跑。实际使用时,先打开主脚本,把前几行的addpath路径改成自己电脑上的实际路径,比如:
addpath(fullfile(pwd, 'workspace')); addpath(fullfile(pwd, 'reference'));注意不要把slprj加进搜索路径,它不是源码目录。
3.3 运行主脚本的步骤与关键参数
在 Matlab 命令行里切换到项目根目录,然后直接运行主脚本。主脚本里一般会包含以下部分:
% 1. 加载被控对象和 SMC 初始参数 plant_param.m; smc_param.k = 10; smc_param.phi = 0.05; smc_param.c = 5; % 滑模面系数 % 2. 初始化 DDPG 超参数 ddpg_param.lr_actor = 1e-4; ddpg_param.lr_critic = 1e-3; ddpg_param.gamma = 0.99; ddpg_param.tau = 0.001; ddpg_param.noise_std = 0.1; % 探索噪声标准差 ddpg_param.buffer_size = 1e5; ddpg_param.batch_size = 64; ddpg_param.num_episodes = 200; ddpg_param.steps_per_episode = 500; % 3. 创建 agent 和环境接口 agent = createDDPGAgent(ddpg_param); env = SimulinkEnv('smc_system_model', 'smc_system_model/RL_Controller'); % 4. 训练 trainingStats = train(agent, env, ... 'MaxEpisodes', ddpg_param.num_episodes, ... 'MaxStepsPerEpisode', ddpg_param.steps_per_episode);这里的关键参数是noise_std。DDPG 天然需要探索噪声,通常用 Ornstein-Uhlenbeck 噪声或高斯噪声。噪声太大,参数乱跳,系统可能发散;噪声太小,探索不够,policy 收敛到局部最优。我一般先控制器里加一个参数保护——当动作导致 k 或 phi 超出合理范围时,直接把增量截断,再返回给 Simulink。
3.4 把 DDPG agent 接入 Simulink 模型的调用方式
在 Simulink 模型里,DDPG 不是用 S-Function 就是用一个 MATLAB Function 块。如果是官方 RL 工具箱,环境中直接用rlSimulinkEnv绑定。如果是手写实现,通常是在 MATLAB Function 块里定义:
function action = ddpg_controller(state, params) % 从 actor 网络前向传播得到动作 % state 是模型输出的观测向量 action = actor_forward(state, params.actor_net); end这种方式的难点在于:每一步仿真都要访问工作区的网络参数。在普通仿真模式下,MATLAB Function 块可以直接读基础工作区的变量,但为了训练时参数频繁更新,最好把网络参数通过 Tunable Parameter 传入模型。具体做法是把 actor 网络的权重和偏置打包成一个结构体,在模型参数里定义为Parameter类型,这样训练脚本每次更新权重后,Simulink 模型不用重新编译,直接从外部拿最新参数。
4. 参数化编程:如何改参数而不破坏训练流程
4.1 参数化编程的核心思想
这份资源强调“参数化编程,参数可方便更改”。理解起来不复杂:所有与环境、控制器、学习算法相关的数值,都不应该硬编码在 Simulink 模块或函数内部,而是集中放在一个参数脚本或结构体里。这样当你从一台机器换到另一台机器,或者从 2014 版换到 2024 版,需要改的只有参数定义,而不是逻辑代码。
典型的参数结构体如下:
% smc_params.m smc_params.c = 5; % 滑模面斜率 smc_params.k = 8; % 切换增益初始值 smc_params.phi = 0.05; % 边界层厚度 smc_params.lambda = 0.2; % 指数趋近律系数 % ddpg_params.m ddpg_params.state_dim = 4; ddpg_params.action_dim = 2; ddpg_params.hidden = [64 48]; ddpg_params.actor_lr = 1e-4; ddpg_params.critic_lr = 1e-3; ddpg_params.gamma = 0.99; ddpg_params.tau = 0.005; ddpg_params.sigma = 0.1; % 探索噪声 ddpg_params.buffer_capacity = 100000; ddpg_params.batch_size = 64; ddpg_params.num_episodes = 300; ddpg_params.steps_per_episode = 600; ddpg_params.dt = 0.001; % 仿真步长在 Simulink 模型里,滑模控制模块直接引用smc_params.c、smc_params.k这些变量。训练脚本修改变量后,调用sim重新仿真,新参数自动生效。
4.2 关键参数表与调整建议
下面这张表列出 DDPG-SMC 系统里最经常需要调整的参数,以及调整时的方向性建议:
| 参数 | 作用 | 调整方向 | 风险 |
|---|---|---|---|
smc_params.c | 滑模面斜率 | 增大可加快收敛,但过大导致控制量放大 | 系统振荡 |
smc_params.k | 切换增益 | 增大提高鲁棒性,加剧抖振 | 抖振、饱和 |
smc_params.phi | 边界层厚度 | 增大大幅削弱抖振,但增大跟踪误差 | 稳态误差 |
ddpg_params.gamma | 折扣因子 | 接近 1 时更远视,训练更慢 | 不收敛 |
ddpg_params.tau | 目标网络软更新率 | 减小使目标网络更稳定,但更新过慢 | 学习缓慢 |
ddpg_params.sigma | 探索噪声标准差 | 增大多探索,但控制品质波动大 | 系统发散 |
reward.w1 | 误差权重 | 增大则重视跟踪精度 | 参数激进 |
reward.w2 | 控制变化率权重 | 增大则抑制抖振 | 响应变慢 |
reward.w3 | 滑模面权重 | 增大则强调滑模到达 | 与 w1 耦合 |
一个容易忽略的组合是c和phi。c 越大,滑模面越陡,等效控制对模型误差越敏感;这时候如果 phi 还很小,系统会频繁穿越滑模面,产生高频抖振。我通常在训练前先手动试一组 SMC 参数让系统稳定,再让 DDPG 在稳定邻域内搜索,而不是从完全未知的参数开始。
4.3 修改参数后需要检查的环节
改参数并不只是换数字。改完smc_params.k,必须看 Simulink 模型里对应的常量块或 MATLAB Function 是否引用了同一个变量名。最常见的问题是:脚本里定义的变量名叫做k_sw,但模型里写的是smc_params.k,导致模型读不到值,运行时报未定义参数错误。
另一种情况是改了ddpg_params.noise的类型,比如从一个标量改成一个向量,但 agent 的噪声生成函数还默认是标量,维度对不上。建议所有参数都用结构体组织,并在主脚本开头加上一次性检查:
assert(ddpg_params.action_dim == length(ddpg_params.noise_std) || isscalar(ddpg_params.noise_std), ... 'noise_std 维度与动作维度不一致');Simulink 的缓存问题也值得注意。如果你改了模型结构而不是只改参数,Matlab 可能会报 “Unable to update model because the model has been structurally changed”。这时候执行bdclose('all')然后重新打开模型,或者直接删除slprj缓存目录让它重新生成,通常能解决。
4.4 常见报错与排查
训练过程中最容易遇到的几个问题:
- 错误一:
Undefined function or variable 'smc_params'。原因是 Simulink 模型在编译时读取不到工作区变量。检查 baidu 是否有smc_params在当前工作区,或者是否在Model Properties -> Callbacks -> InitFcn里调用了参数脚本。 - 错误二:
The model workspace is empty。把参数定义写到了 Model Workspace,但脚本在基础工作区修改变量,模型不会自动同步。解法:统一使用基础工作区,或者用getVariable从模型工作区读值。 - 错误三:
Jacobian of the function is inaccurate。这是 DDPG 训练时给 Simulink 传非常规整的常数导数时触发的。常见于手写 actor 网络更新频率与仿真步长相匹配的场景。解法:在 MATLAB Function 块里使用coder.extrinsic('actor_forward'),或把网络前向计算改为查表近似。 - 错误四:训练到一半 reward 变成 NaN。大概率是系统发散导致状态爆掉。检查
state是否被归一化到合理范围;检查动作是否被截断;检查奖励中的s^2是否因为 s 数值巨大而溢出。我习惯在计算奖励前加一个max(abs(s), 10)的钳位。
5. 验证 DDPG-SMC 效果的一个实用技巧:记录滑模面与抖振指标
训练完成后,不能只看 episode reward 曲线,还要看控制系统的实际指标。你需要在 Simulink 模型里输出滑模面值 s、控制量 u 和跟踪误差 e,然后单独跑一次使用训练好的 actor 网络参数的仿真,与 baseline SMC 参数比较。
在模型里增加两个 To Workspace 模块,分别输出s_log和u_log,然后在训练脚本最后加上评估部分:
% 加载训练好的 actor 网络 actor_net = load('workspace/best_actor.mat'); assignin('base', 'actor_net', actor_net); % 切换为评估模式(关闭探索噪声) set_param('smc_system_model/RL_Controller', 'is_training', '0'); % 运行一次仿真 out = sim('smc_system_model', 'StopTime', '5'); % 提取数据 s = out.s_log.Data; u = out.u_log.Data; t = out.tout; % 抖振强度指标:控制信号总变差 tv = sum(abs(diff(u))); % 抖振频率近似:滑模面过零次数 zero_cross = sum(diff(sign(s)) ~= 0); fprintf('控制信号总变差 TV = %.4f\n', tv); fprintf('滑模面过零次数 = %d\n', zero_cross);这里用控制信号总变差(Total Variation)来量化抖振,比单纯看波形更客观。TV 越小,说明控制量越平缓,抖振抑制效果越好。滑模面过零次数则是另一个视角——系统在滑模面上来回穿越的次数越少,说明边界层设计越合理。这两个指标需要结合跟踪误差一起看:如果 TV 很小但跟踪误差很大,说明 DDPG 倾向于把 phi 调得过大,牺牲了精度,此时要调大奖励里的 w1 权重,重新训练。
最后一个实用的对比方式:在同一个图里画固定参数 SMC 和 DDPG-SMC 的跟踪曲线与滑模面曲线。如果 DDPG 的效果没有明显优于好的手工参数,先不要怀疑算法,检查训练时奖励的收敛情况——如果 reward 曲线波动很大且没有上升趋势,多半是状态归一化没做好,或者动作范围限制太紧。
把这一套跑通,你就真正掌握了 DDPG 调 SMC 的完整流程:从 MDP 建模、Simulink 环境搭建、网络训练到指标验证。之后换成其他被控对象,只需要改 plant 模型和状态定义,整个框架可以直接复用。
本文还有配套的精品资源,点击获取