简介这是一份基于MATLAB的双容水箱模糊控制仿真资源面向自动化、控制工程等专业的学生及需要实现液位控制的工程技术人员可用于课程设计、毕业设计或技术预研。资源以两个相互串联的水箱为被控对象围绕水位恒定控制目标完整展示了模糊控制从模糊集合划分、偏差与偏差变化率输入、模糊规则推理到去模糊化输出的设计流程并体现了模糊逻辑处理供水波动和测量扰动的能力。压缩包共6个文件包括2个.m源码脚本、1个.slx仿真模型、1个.fis模糊推理系统文件以及2份docx报告文档体积仅1.02MB便于快速获取与运行。已有2088人学习下载颇受相关领域学习者关注。通过代码和文档可掌握Fuzzy Logic Toolbox的实际用法理解模糊规则库建立思路并能在此框架上修改参数、扩展为自适应模糊PID等更高级策略。1. 双容水箱模糊控制为什么PID在这里不够用双容水箱是过程控制里最典型的被控对象之一两个水箱垂直串联前箱的出水直接进入后箱控制目标是借助调节阀开度让后箱液位稳定在设定值。它的数学模型看似简单但实际运行中的容量滞后、进水扰动和阀门非线性都会让常规PID参数只在一个工作点附近有效。模糊控制不依赖精确传递函数而是把熟练操作工的经验归纳成“偏差大、变化快就加大阀门”这类规则在MATLAB里只需一个.fis文件加一个Simulink模型就能完整复现。这套资源中的Fuzzy_Water_Tank.m、tank_s1.slx和FUZZ1.fis正好覆盖从建模到仿真的全流程适合做课程设计、毕业设计也适合刚接触模糊逻辑的工程师快速建立闭环控制直觉。2. 双容水箱机理建模与tank_s1.slx开环仿真结构2.1 双容水箱的机理方程与参数选取双容水箱可以看作两个一阶惯性环节的串联。设两个水箱的横截面积分别为 A1、A2底部出水孔面积为 a1、a2液位为 x1、x2调节阀开度为 u。根据托里切利定律流出流量与液位平方根成正比状态方程写成dx1/dt (ku - a1sqrt(2gx1)) / A1dx2/dt (a1sqrt(2gx1) - a2sqrt(2gx2)) / A2其中 k 是阀门增益g 是重力加速度。第一个方程描述前箱液位受进水阀和自流出的影响第二个方程中前箱流出流量成为后箱输入后箱出水 Q2a2sqrt(2g*x2) 作为负载。可以看到x2 对 u 的响应要经历两级惯性这就是容量滞后也是单纯用PID整定时容易把比例增益调得过大、引发振荡的原因。实际建模仿真中参数需要统一用SI单位否则仿真结果没有物理意义。下表是一组我在开环测试中常用的参数来自典型教学水箱的换算值。参数含义数值单位A1水箱1截面积0.5m^2A2水箱2截面积0.5m^2a1水箱1出水孔面积0.045m^2a2水箱2出水孔面积0.045m^2g重力加速度9.81m/s^2k调节阀增益1.0(m^3/s)/%x1_0前箱初始液位0.10mx2_0后箱初始液位0.10m选参数的逻辑是两个水箱截面积相近保证均衡状态下后箱液位跟随前箱出水孔面积取 0.045 平方米对应空箱放水时间常数在几十秒到百秒级别和实际工业水箱响应习惯接近。2.2 用Simulink搭建开环模型tank_s1.slx的结构tank_s1.slx 通常并不是用纯积分器和乘法器逐个搭方程而是用两个 Integration 模块配合 Fen 或 S-Function 实现非线性微分方程组。推荐的做法是写一个 MATLAB 函数文件作为 S-Function 回调然后在 Simulink 中用 S-Function 模块引用它。这样做的好处是日后切换控制算法时不需要改模型结构。在模型工作区或脚本中先初始化参数这一步我一般放在独立的 m 文件中方便改参数% tank_params.m - 双容水箱仿真参数初始化 % 供 tank_s1.slx 从 MATLAB 工作区读取 A1 0.5; % 水箱1横截面积m^2 A2 0.5; % 水箱2横截面积m^2 a1 0.045; % 水箱1出水孔面积m^2 a2 0.045; % 水箱2出水孔面积m^2 g 9.81; % 重力加速度m/s^2 k 1.0; % 调节阀增益(m^3/s)/% % 初始液位 x1_0 0.10; x2_0 0.10;这里所有变量都会写到 MATLAB 的基本工作区。模型里的常数模块和积分器初值可以使用工作区变量名比如 Integrator1 的 InitialCondition 写成 x1_0比直接填数字安全得多。S-Function 的第二个输出是后箱液位也就是被控量 x2。如果选择 S-Function 方式回调函数可以写成下面的形式% tank_sfun.m - 双容水箱S-Function % 输入u(1)为阀位开度指令输出为[x1; x2] function [sys,x0] tank_sfun(t,x,u,flag,A1,A2,a1,a2,k,g) switch flag case 0 sys [2;0;2;0;0;0]; % 2个连续状态2个输出 case 1 sys(1) (k*u(1) - a1*sqrt(2*g*x(1)))/A1; sys(2) (a1*sqrt(2*g*x(1)) - a2*sqrt(2*g*x(2)))/A2; case 3 sys x; case {2,4,9} sys []; otherwise error(unhandled flag); end x0 [0.1; 0.1];flag0 返回系统维度参数flag1 返回状态导数flag3 返回输出这是标准 S-Function 的骨架。Simulink 模型里的 S-Function 模块只要填函数名 tank_sfun并把 A1、A2、a1、a2、k、g 作为参数传入就能复用同一个模型文件跑不同工况。如果想快速验证开环响应也可以直接在模型里用两个 Integrator 和 Fen 模块搭缺点是不够直观控制器改型时容易误连线。2.3 开环阶跃响应为什么要上模糊控制在 Simulink 中给阀位加一个 50% 的阶跃用 scope 观察 x2。可以看到 x2 不是立刻上升而是先缓慢加速再逐渐逼近稳态整个过程表现为 S 形曲线。用一阶惯性加纯滞后模型近似滞后时间大约占整个响应时间的 20%~30%。这种纯滞后加上参数随液位变化是常规 PID 整定最头疼的地方整定出的比例增益只能在某个工况附近工作工况一变就容易出现持续振荡或响应太慢。模糊控制的价值就在这里。它把误差 E 和误差变化率 EC 作为输入直接映射到阀门开度本质上是一个变增益的非线性控制器。在大偏差时等效比例增益很大小偏差时自动降低增益从而避免超调和稳态振荡。这就是为什么很多过程控制课程把双容水箱作为模糊控制的入门案例。3. FUZZ1.fis 解析模糊集、规则表与去模糊化设计3.1 输入输出变量定义与论域选择FUZZ1.fis 是一个 Mamdani 型模糊推理系统输入变量通常选水位偏差 E 和偏差变化率 EC输出变量为控制阀开度 U。E 的论域范围一般取实际允许偏差的上下限比如[-0.5, 0.5] 米EC 的论域需要根据仿真步长和液位变化速率确定比如[-0.02, 0.02] 米/秒U 的论域对应阀门开度取[-1, 1] 或[0, 1]最后再乘以阀门增益 k。之所以选 E 和 EC 而不是直接用液位值是因为反馈控制本质上关心的是当前偏离了多少、偏离趋势是什么。如果 EC 为正且很大说明液位正在快速上升即使当前偏差不大也需要提前减小阀门这就是“预测”作用的来源。模糊控制器通过规则库把这个推理逻辑显式表达出来规则可以写得和人的操作习惯一一对应。在 MATLAB 中可以用 readfis 读取文件并检查三个变量的范围fis readfis(FUZZ1.fis); disp(fis.Type); disp(fis.AndMethod); disp(fis.ImplicationMethod); % 查看输入输出变量定义 fis.Inputs(1).Name, fis.Inputs(1).Range fis.Inputs(2).Name, fis.Inputs(2).Range fis.Outputs(1).Name, fis.Outputs(1).Rangefis.Type返回 mamdani说明推理方法是最大最小合成AndMethod是 min对应规则的与运算ImplicationMethod为 min 表示蕴含运算。Range返回每个变量的论域比如[-0.5 0.5]。如果readfis报错优先检查当前目录下是否存在 FUZZ1.fis以及 MATLAB 是否安装了 Fuzzy Logic Toolbox没有工具箱时readfis无法运行。3.2 隶属度函数设计与 FIS 文件生成每个变量定义 7 个模糊子集NB、NM、NS、ZO、PS、PM、PB覆盖负大到正大。E 的隶属度函数常用高斯型或三角型因为高斯型在边界更平滑三角型更容易在调参时观察重叠。下面是用命令方式创建一个简化 FIS 的片段实际 FUZZ1.fis 的结构与此类似fis newfis(FUZZ1, mamdani, min, max, centroid); % 输入变量 E论域 [-0.5 0.5] fis addvar(fis, input, E, [-0.5 0.5]); % 添加 NB 隶属度函数梯形 fis addmf(fis, input, 1, NB, trapmf, [-0.5 -0.5 -0.35 -0.15]); % 添加 ZO 隶属度函数三角形 fis addmf(fis, input, 1, ZO, trimf, [-0.15 0 0.15]); % 添加 PB 隶属度函数梯形 fis addmf(fis, input, 1, PB, trapmf, [0.15 0.35 0.5 0.5]);addvar的第一个参数是 fis 对象第二个参数指定input或output第三、四个参数分别是变量名和范围。addmf中第三个参数是隶属度函数编号第四个参数是名称第五个是关键不同函数类型的参数含义不同。trapmf需要四个断点trimf需要三个断点高斯型gaussmf需要均值和标准差。调试时可以用plotmf(fis,input,1)把第 1 个输入变量的所有隶属度函数画出来观察相邻 MF 的重叠程度。3.3 模糊规则库与推理/去模糊化规则表是模糊控制器的核心。常见规则可以写成二维表行是当前偏差 E列是偏差变化率 EC输出是阀门开度 U。比如E\ECNBNMNSZOPSPMPBNBPBPBPMPMPSPSZONMPBPMPMPSPSZONSNSPMPMPSPSZONSNMZOPMPSPSZONSNSNMPSPSPSZONSNSNMNMPMPSZONSNSNMNMNBPBZONSNMNMNBNBNB规则含义是当偏差为负大且偏差变化为负大时说明水位远低于目标且在继续下降阀门应开最大当偏差为正大且变化率为正时水位会继续冲高阀门应快速关小。对角线两侧规则对称这是模糊控制器稳定性的基本要求。在 Fuzzy Logic Toolbox 中规则用文本或数字矩阵存储。读取已建好的 FUZZ1.fis 并查看规则showrule(fis, [1 2], symbolic); gensurf(fis);showrule以符号形式打印指定规则例如If (E is NB) and (EC is NB) then (U is PB) (1)。gensurf生成控制曲面X 轴是 EY 轴是 ECZ 轴是 U。如果控制曲面有明显台阶或鞍部说明规则表有冲突或者隶属度函数重叠不足需要回到规则库检查。去模糊化采用 centroid重心法输出是隶属度函数覆盖区域的重心坐标计算连续且光滑不会出现最大隶属度法那样的跳变。重心法虽然计算量大但对现代 CPU 可以忽略所以在 MATLAB 仿真中基本都是用 centroid。4. Fuzzy_Water_Tank.m 与 FuzzyPID.m仿真脚本与模糊PID对比4.1 Fuzzy_Water_Tank.m 主程序流程Fuzzy_Water_Tank.m 的核心作用是把 FUZZ1.fis 加载进工作区设置仿真参数然后驱动 Simulink 模型运行。写好的脚本可以在批处理实验中反复调用省去每次手动点击 Start 的麻烦。% Fuzzy_Water_Tank.m % 双容水箱模糊控制主仿真脚本 clear; clc; % 1. 加载参数和模糊控制器 tank_params; % 调用第2章的初始化脚本 fis readfis(FUZZ1.fis); % 读取FIS文件 assignin(base, fis, fis); % 2. 设置仿真时长和液位目标 t_end 300; % 仿真时长秒 setpoint 0.30; % 目标液位米 % 3. 运行Simulink模型 % 模型名 tank_s1.slx输出变量 yout 在工作区中返回 simOut sim(tank_s1.slx, StopTime, num2str(t_end)); t simOut.tout; y simOut.yout; % 4. 绘图观察液位跟踪与阀门开度 figure(1); plot(t, y(:,1), LineWidth, 1.5); hold on; yline(setpoint, --); xlabel(时间/s); ylabel(水箱2液位/m); legend(液位, 设定值);第一行tank_params调用前面的参数脚本保证 S-Function 里的工作区变量都存在readfis读取模糊控制器assignin把 fis 对象写到基础工作区这是接下来 Simulink 里 Fuzzy Logic Controller 模块读取 FIS 的必要步骤否则模块会报 undefined variable。sim命令的第一个参数是模型名不用带 .slx 扩展名也可以加扩展名更明确第二个参数用字符向量指定 StopTime也可以直接写成sim(tank_s1.slx,StopTime,300)。仿真对象simOut里通过.tout和.yout取时间序列和输出矩阵新版本 MATLAB 也可以用simOut.logsout按信号名取值具体写法取决于模型输出端口的配置方式。4.2 模糊控制仿真结果与常规PID对比在同样的水箱模型上分别跑一个整定良好的 PID 和一个模糊控制器通常能看到几个典型差异模糊控制的上升时间略慢但几乎没有超调PID 为了让上升时间快很难兼顾超调在进入稳态后模糊控制对阶跃扰动的恢复更快因为规则中 EC 的输入项会提前反应。下面是我在双容水箱参数下得到的一组对比指标实际数值依赖你的模型参数但趋势一致控制器超调量 (%)调节时间 (s)稳态误差 (m)抗扰恢复时间 (s)常规PID18.6950.00642模糊控制3.2780.00425需要说明的是上表不是固定结论。模糊控制器的性能完全由规则表和量化因子决定如果量化因子取得过大模糊控制器同样会超调并振荡。对比实验的意义在于展示变增益特性模糊控制器在小偏差时等效增益低因此不容易激发小幅度振荡大偏差时等效增益高所以响应速度和 PID 相当。4.3 FuzzyPID.m自适应模糊PID的设计思路FuzzyPID.m 是另一个方向的进阶实现它不直接输出阀位而是输出 PID 参数增量。结构上它把当前 PID 参数写成全局变量或模型工作区变量在每个仿真步进中根据 E 和 EC 查询三个 FIS得到 dKp、dKi、dKd再和基准值相加。这样做保留了 PID 的积分作用又能让增益随工况变化适合双容水箱这种有容量滞后且工况变化频繁的对象。function [Kp, Ki, Kd] FuzzyPID(E, EC) % E - 液位偏差EC - 偏差变化率 % 用三个FIS分别整定PID参数增量 global Kp0 Ki0 Kd0; % 基准PID参数 global fisKp fisKi fisKd; % 三个模糊控制器 global KpScale KiScale KdScale; % 输出比例因子 dKp evalfis(fisKp, [E, EC]); dKi evalfis(fisKi, [E, EC]); dKd evalfis(fisKd, [E, EC]); Kp Kp0 dKp * KpScale; Ki Ki0 dKi * KiScale; Kd Kd0 dKd * KdScale; endevalfis是模糊逻辑工具箱的推理函数输入是 [E EC] 行向量返回该规则库推理并去模糊化后的输出。三个 FIS 的规则经验是Kp 调整量在偏差大时取正偏差小时取负Ki 在偏差较小、EC 较小时取大避免小偏差时积分作用太弱导致稳态误差Kd 要响应 EC 的符号偏差变化剧烈时加大微分作用以抑制超调。这里使用global只是为了演示方便工程上更推荐写成函数参数或使用 Simulink 的 Tunable 参数能避免命名冲突。把这个函数写成 MATLAB Function 模块嵌入 Simulink 的 PID 控制器之前即可实现自适应模糊PID仿真。5. 量化因子整定、积分修正与MATLAB调试技巧5.1 量化因子与输出比例因子的整定顺序模糊控制器在接入实际模型前要先确定三个无量纲化系数量化因子 Ke、Kec 和输出比例因子 Ku。我的经验是从开环阶跃响应读数据设定值变化量记为 delta取 Ke1/delta观察液位变化速度的最大值记为 max_ec取 Kec1/max_ecKu 则从阀门最大可调范围反推取 Ku100/k让规则表里的 PB 对应全开。% 根据开环响应计算量化因子 delta 0.2; % 设定值阶跃幅值 max_ec 0.015; % 开环响应最大变化率 Ke 1 / delta; % 偏差量化因子 Kec 1 / max_ec; % 偏差变化率量化因子 Ku 50 / 1.0; % 输出比例因子50%阀门开度对应1.0控制量整定顺序是先固定 Ke用 Kec 控制动态状态响应震荡就调大 Kec 或调小 Ku响应太缓就调大 Ku 或调小 Kec。每轮修改后重新运行 Fuzzy_Water_Tank.m看gensurf的控制曲面是否出现平台区出现平台区说明某个规则组合落入死区需要检查量化因子是否覆盖满论域。5.2 稳态误差、积分修正与工具箱兼容双容水箱本身是自衡对象模糊控制器不引入积分项也能做到零稳态误差但这依赖规则表在零点附近有足够精细的 ZO 子集。如果发现稳态误差在量级上不可接受比较实用的方案不是加密规则而是在模糊控制输出后并联一个增益很小的积分环节把积分输出与模糊输出相加送给阀门。积分系数一般取 0.01 到 0.05太大容易出现低频振荡。MATLAB 调试时还有几个常见坑。readfis报文件不存在先检查当前路径用which FUZZ1.fis查看evalfis报维度错误检查输入变量是否按 [E EC] 顺序拼接sim命令返回的.yout在新版本是 Simulink SimulationOutput 对象不能直接取冒号索引要改用simOut.logsout或配置信号记录。最后安装 MATLAB 时记得选择 Fuzzy Logic Toolbox否则readfis和evalfis都会提示未定义函数下载安装后可以通过ver(fuzzy)确认工具箱版本再重新运行仿真脚本。本文还有配套的精品资源点击获取