<think>我们注意到在运行过程中,控制输入u一直处于饱和状态(u=-12),并且theta_ref始终为-10。这可能是由于模糊控制器的输出theta_ref被限制在了-10。
观察模糊控制器fuzzy_controller2.m,我们发现以下问题:
1. 在解模糊时,theta_ref = 1 * (numerator / denominator); 这里乘以1,但实际输出范围可能超出预期。
2. 模糊控制器的输入e和de的范围是[-50,50],而输出中心点为[-10,-5,0,5,10]。但在解模糊时,我们直接使用了这些中心点,没有进行缩放。
3. 在规则矩阵中,我们使用了1到5的整数,对应中心点的索引。但是,当输出权重的分母为0时(即没有任何规则被激活),会导致除以0错误(虽然当前输出没有出现,但需要防范)。
然而,从打印的e和de的值来看(例如e=16.0302, de=38.4436),这些值都在定义的范围[-50,50]内,所以不会因为超出范围而无法计算隶属度。
但是,为什么theta_ref总是-10呢?
我们检查模糊控制器的计算过程:
1. 模糊化:计算e和de在5个隶属函数上的隶属度。
2. 规则矩阵:根据规则矩阵,每个规则对应一个输出语言变量(1到5,分别代表负大、负小、零、正小、正大?)
3. 输出强度:对每个输出语言变量,取所有激活规则中的最大隶属度作为该输出的强度。
4. 解模糊:用输出强度加权中心点,然后除以总强度。
问题可能出在规则矩阵的设计上。我们观察规则矩阵:
rule_matrix = [
1 1 2 3 4
1 2 3 3 5
2 3 3 3 2
5 3 3 2 1
3 3 2 1 1
];
这个规则矩阵的含义是:行表示e的隶属函数(从负到正5个),列表示de的隶属函数(从负到正5个),值代表输出的语言变量索引。
例如,当e为第一个隶属函数(负大)且de为第一个隶属函数(负大)时,输出为1(负大,对应中心点-10)。
当e和de都很大(正大)时,即最后一行最后一列,输出为1(负大?)?这看起来不合理。
实际上,当误差e为正(即alpha小于设定值,因为error_out=alpha_ref-alpha,而alpha_ref=0,所以alpha为负时误差为正)且误差变化率de为正(即alpha_dot为负,因为error_dot_out=-alpha_dot,所以alpha_dot为负时de为正)时,我们应该增加theta_ref(使theta_ref为正)以减小alpha的负值(即让alpha往正方向走)。但是规则矩阵最后一行最后一列输出1(负大)会使得theta_ref为负,这显然是不合理的。
因此,规则矩阵的设计可能存在问题。另外,我们注意到当e和de都很大时,激活的规则应该是输出正大的控制量,但这里规则矩阵给出的是1(负大)。
另外,我们注意到在计算输出强度时,我们初始化output_strength为zeros(1,5),然后对每个规则,取激活强度(隶属度的最小值)与当前该输出的强度比较取大。但是,如果没有任何规则激活某个输出,那么该输出的强度为0,在解模糊时就会忽略这个输出。
但是,从打印的e和de来看,它们都比较大(正),所以应该激活的是e和de的最后一个或两个隶属函数(即正大)。我们检查模糊化部分:
例如,e=16.0302,隶属函数定义:
centers = [-10,-5,0,5,10]
最后一个隶属函数:中心点为10,其三角形为[5,10,50](因为max_val=50,所以c=50)。所以对于e=16.0302,它在最后一个隶属函数上的隶属度为:
a=5, b=10, c=50
mu = (50-16.0302)/(50-10) = (33.9698)/40 ≈ 0.8492
同样,de=38.4436,最后一个隶属函数:a=5, b=10, c=50,所以
mu = (50-38.4436)/40 = 11.5564/40 ≈ 0.2889
那么激活的规则是:e的第五个隶属函数和de的第五个隶属函数,即规则矩阵(5,5)=1(负大)。所以输出语言变量1的强度为min(0.8492,0.2889)=0.2889。
同时,e的第五个隶属函数和de的第四个隶属函数(de=38.4436在第四个隶属函数上的隶属度?第四个隶属函数:中心5,三角形[0,5,10]?显然38.4436不在这个三角形内,所以隶属度为0。同理,e的第四个隶属函数(中心5,三角形[0,5,10])对于e=16.0302的隶属度也为0(因为16>10)。所以只有规则(5,5)被激活?那么输出只有语言变量1(负大)被激活,强度0.2889。
因此,解模糊:theta_ref = (0.2889 * (-10)) / 0.2889 = -10。
这就是为什么theta_ref总是-10的原因:因为当e和de都很大(正)时,规则矩阵(5,5)指向了1(负大),而其他规则没有被激活。
所以,我们需要重新设计规则矩阵。通常,当误差和误差变化率都为正时,我们应该输出正的控制量(即正大)。因此,规则矩阵的最后一行最后一列应该是5(正大)而不是1。
修改规则矩阵为:
rule_matrix = [
1, 1, 1, 2, 3;
1, 1, 2, 3, 4;
1, 2, 3, 4, 5;
2, 3, 4, 5, 5;
3, 4, 5, 5, 5
];
或者更常见的做法(对角线为同一类):
rule_matrix = [
1, 1, 2, 3, 4;
1, 2, 3, 4, 5;
2, 3, 4, 5, 5;
3, 4, 5, 5, 5;
4, 5, 5, 5, 5
];
但具体需要根据控制逻辑调整。
这里我们采用常见的规则:当误差和误差变化率都为正大时,输出正大(5)。所以将(5,5)改为5。
同时,我们还需要注意,当没有任何规则激活时(分母为0),需要给一个默认输出(比如0)。
因此,修改fuzzy_controller2.m中的解模糊部分:
if denominator == 0
theta_ref = 0;
else
theta_ref = 1 * (numerator / denominator);
end
另外,我们也可以考虑对输出进行缩放。目前中心点是[-10,-5,0,5,10],而实际我们可能希望输出在[-20,20]之间,那么可以乘以一个增益(比如2)。但这里我们先不改变,等调试规则后再看。
修改后的模糊控制器函数如下(只修改了规则矩阵和添加分母为0的判断):</think>根据提供的代码和运行结果,主要问题在于模糊控制器`fuzzy_controller2`的输出始终为`-10`,导致内环PID持续饱和(`u=-12`)。以下是详细分析和解决方案:
### 问题原因分析
1. **规则矩阵设计错误**
- 当前规则矩阵:
```matlab
rule_matrix = [
1 1 2 3 4
1 2 3 3 5
2 3 3 3 2
5 3 3 2 1
3 3 2 1 1
];
```
- 当误差`e`和误差变化率`de`均为正大时(对应右下角元素),规则输出为`1`(负大),但正确逻辑应为输出正大(`5`)。
2. **未处理零激活规则**
当`output_strength`全为0时(无规则激活),解模糊计算`numerator/denominator`会导致`NaN`(未发生但需预防)。
3. **输出范围过小**
中心点`centers = [-10, -5, 0, 5, 10]`的范围不足以覆盖控制需求(实际误差`e`已达16)。
### 解决方案
#### 1. 修正规则矩阵
```matlab
% 新规则矩阵(行:e的隶属度,列:de的隶属度)
rule_matrix = [
1 1 2 3 4; % e: NB
1 2 3 4 5; % e: NS
2 3 4 5 5; % e: ZE
3 4 5 5 5; % e: PS
4 5 5 5 5 % e: PB
];
```
**解释**:当`e`和`de`均为正大(PB)时,输出正大(`5`),符合控制逻辑。
#### 2. 添加零激活处理
```matlab
% 解模糊前添加判断
if denominator == 0
theta_ref = 0; % 默认输出
else
theta_ref = 1 * (numerator / denominator);
end
```
#### 3. 扩展输出范围
```matlab
% 修改中心点范围(扩大至±30)
centers = [-30, -15, 0, 15, 30];
```
**解释**:适应实际误差范围(`e`≈16),避免输出饱和。
### 完整修正代码
```matlab
function theta_ref = fuzzy_controller2(e, de)
% === 范围定义 ===
e_min = -50; e_max = 50;
de_min = -50; de_max = 50;
centers = [-30, -15, 0, 15, 30]; % 扩展输出范围
% === 定义三角形隶属函数 ===
mf_e = define_mf(e_min, e_max, centers);
mf_de = define_mf(de_min, de_max, centers);
% === 模糊化 ===
mu_e = fuzzify(e, mf_e);
mu_de = fuzzify(de, mf_de);
% === 修正规则矩阵 ===
rule_matrix = [
1 1 2 3 4; % e: NB
1 2 3 4 5; % e: NS
2 3 4 5 5; % e: ZE
3 4 5 5 5; % e: PS
4 5 5 5 5 % e: PB
];
% === 推论输出权重 ===
output_strength = zeros(1, 5);
for i = 1:5
for j = 1:5
activation = min(mu_e(i), mu_de(j));
k = rule_matrix(i, j);
output_strength(k) = max(output_strength(k), activation);
end
end
% === 解模糊(含零激活保护)===
numerator = sum(output_strength .* centers);
denominator = sum(output_strength);
if denominator == 0
theta_ref = 0; % 默认值
else
theta_ref = 1 * (numerator / denominator);
end
end
```
### 其他优化建议
1. **添加抗饱和重置逻辑**
在`dynamics.m`中,当`u`饱和时重置积分项:
```matlab
if u >= params.u_max || u <= params.u_min
dE_in_dt = 0; % 当前已有
params.integral_error = 0; % 添加:重置积分项
end
```
2. **调整PID参数**
当前`Kp_in=10, Ki_in=5, Kd_in=3`可能过大,建议逐步调整:
```matlab
params1.Kp_in = 5; % 降低比例增益
params1.Ki_in = 2; % 降低积分增益
params1.Kd_in = 1; % 降低微分增益
```
3. **检查初始状态**
初始角度`x0_1 = [test_angle; 0; 0; 0; 0]`中`test_angle=0.2`(约11.5°),确保符合物理约束。
### 验证步骤
1. 用修正后的`fuzzy_controller2`替换原函数。
2. 运行`main1.m`观察`theta_ref`和`u`是否脱离饱和。
3. 绘制响应曲线验证控制效果:
```matlab
figure;
subplot(2,1,1); plot(t1, x1(:,3)); title('Alpha');
subplot(2,1,2); plot(t1, u1); title('Control Input');
```