【控制系统】深入理解反步控制(Backstepping) | 反步法控制器原理与应用实例解析(附Matlab/Simulink仿真实现)
在本篇博客中,通过一个非线性弹簧系统实例,深入探讨了控制理论的应用。首先描述了系统的动态方程,并提出了控制目标:通过改变输入力𝐹,使小滑块按照指定轨迹移动。接着引入误差函数,并利用李雅普诺夫函数设计了反步控制器,通过反馈线性化将非线性系统转化为线性系统,并分析了系统的稳定性。 在 Simulink 仿真环节,构建了系统模型,并进行了动态方程的实现。通过设定不同的期望值,观察了系统对单目标值、多
💯 欢迎光临清流君的博客小天地,这里是我分享技术与心得的温馨角落 💯 🔥 个人主页:【清流君】🔥 📚 系列专栏: 运动控制 | 决策规划 | 机器人数值优化 📚 🌟始终保持好奇心,探索未知可能性🌟
引言
欢迎光临博主的高级控制系统课程系列博客!在这篇文章中,博主将带领大家深入探讨非线性反步控制的奥秘,涵盖了非线性控制器设计的基础知识。
本篇博客内容可谓干货满满,将迎来一系列复杂的数学推导,细致地从头到尾推导了所有相关公式,并将这些结果在 Simulink
中进行验证,理论与实际完美契合!
因此,请各位读者准备好纸笔,跟随博主一起开启这场数学与控制理论交织的思维之旅。前方高能预警,让一起挑战自我,享受知识带来的乐趣吧!
一、非线性弹簧系统示例
先以一个非线性弹簧系统作为控制理论的应用实例开始。
1.1 系统描述
非线性弹簧系统中,小滑块的质量为
m
m
m ,弹簧的系数为
α
\alpha
α,受一个向右的力,
F
F
F 向右的方向为
x
x
x 正方向,其动态方程可以写成
m
x
¨
+
α
x
3
=
F
m \ddot { x } + \alpha x ^ { 3 } = F
mx¨+αx3=F因为有一个非线性弹簧的力存在,所以是非线性系统。
1.2 控制目标
通过改变 F F F ,使小滑块儿按照一条指定的轨迹来进行移动。
1.3 系统动态方程
令:
- F = u F = u F=u 代表输入
- x 1 = x x_1=x x1=x 代表位移
- x 2 = x ˙ x_2=\dot x x2=x˙ 代表速度
目标是令
x
1
x_1
x1 趋向于
x
d
x_d
xd,而这个
d
d
d 代表了 desired
,就是一条规定的轨迹,这就是目标。
重新把它整理一下,变成
x ˙ 1 = x ˙ = x 2 x ˙ 2 = x ¨ = − α m x 3 + 1 m u \begin{align} \dot{x}_1&=\dot{x}=x_2 \tag{1}\\ \dot{x}_2&=\ddot{x}=-\frac{\alpha}{m}x^3+\frac{1}{m}u \tag{2} \\ \end{align} x˙1x˙2=x˙=x2=x¨=−mαx3+m1u(1)(2) 分析一下这个式子,看到在这里面有一个 u u u ,可以通过改变 u u u ,也就是改变系统的输入来控制 x 2 x_2 x2。而通过控制 x 2 x_2 x2 ,在这个式子当中又可以反向控制 x 1 x_1 x1,这也非常好理解,可以通过作用在滑块上的力 F F F 来控制滑块本身的速度,而这个速度将最终导致滑块所停留的位置改变。
这样的形式叫做链式系统,其实这样的系统在现实当中有很多。比如
- 空调系统:是通过电扇的转速和加热器的开关来控制向外发出空气的温度,从而最终导致屋内室温的变化。
- 油门系统:通过踩油门来控制进油量,最终控制汽车的速度。
1.4 误差函数与控制目标
这时引入误差函数
e
e
e
e
=
x
1
d
−
x
1
(3)
e = x _ { 1d } - x _ { 1 } \tag{3}
e=x1d−x1(3)
这个情况下目标就发生了改变,希望
e
→
0
e\rightarrow0
e→0,因为
e
e
e 等于
0
0
0 的话,就说明
x
1
x_1
x1 是在跟踪
x
1
d
x _{1d}
x1d 的,而
e
e
e 随时间变化,可以对
e
e
e 求导
e
˙
=
x
˙
1
d
−
x
˙
1
\dot { e } = \dot x _ { 1 d } - \dot { x } _ { 1 }
e˙=x˙1d−x˙1
把
(
2
)
( 2 )
(2) 式代入,就等于
e
˙
=
x
˙
1
d
−
x
2
(4)
\dot { e } = \dot x _ { 1 d } - { x } _ { 2 }\tag{4}
e˙=x˙1d−x2(4)
这个式子比较重要,因为目标是让 e e e 趋向于 0 0 0 。
二、反步控制器设计
2.1 李雅普诺夫函数的应用
可以寻找一个李亚普诺夫函数 V ( e ) V(e) V(e),使得 V ( e ) V(e) V(e) 是正定的,而 V ˙ ( e ) \dot V(e) V˙(e) 是负定的,这样就可以最终得出来 e e e 趋向于 0 0 0 的结论。
这时不妨设
V
1
=
1
2
e
2
(5)
V _ { 1 } = \frac { 1 } { 2 } e ^ { 2 } \tag{5}
V1=21e2(5) 就是选取的第一个李雅普诺夫函数,很显然它是正定函数,因为只有在
e
e
e 等于
0
0
0 时,
V
1
V_1
V1 才等于
0
0
0 ,其他时候
V
1
V_1
V1 都是大于
0
0
0 的
V
˙
1
=
∂
V
1
∂
e
⋅
d
e
d
t
=
e
e
˙
=
e
(
x
˙
1
d
−
x
2
)
(6)
\dot { V } _ { 1 } = \frac { \partial V _ { 1 } } { \partial e } \cdot \frac { d e } { d t } = e \dot { e } ^ { } = e ( \dot x _ { 1d }- x _ { 2 } )\tag{6}
V˙1=∂e∂V1⋅dtde=ee˙=e(x˙1d−x2)(6) 因为希望
e
e
e 趋向于
0
0
0 ,自然希望
V
˙
1
\dot V_1
V˙1 是一个负定的系统,所以就可以利用这一项设计
x
˙
1
d
−
x
2
=
−
k
1
e
\dot x _ { 1d }- x _ { 2 } =-k_1e
x˙1d−x2=−k1e其中,控制器增益
k
1
>
0
k_1>0
k1>0。
此时
V
˙
1
=
−
k
1
e
2
\dot{V}_1=-k_1e^2
V˙1=−k1e2很明显是负定函数。
如何实现让它等于 − k 1 e 2 -k_1e^2 −k1e2?
可以利用
x
2
x_2
x2:
x
2
d
=
x
˙
1
d
+
k
1
e
(7)
x _ { 2 d } = \dot x _ { 1 d} + k _ { 1 } e\tag{7}
x2d=x˙1d+k1e(7)其中,
x
2
d
x_{2d}
x2d 就是
x
2
x_2
x2 的期望值,也就是说当
x
2
d
=
x
2
x_{2d}=x_2
x2d=x2 时,
V
˙
1
=
−
k
1
e
2
\dot{V}_1=-k_1e^2
V˙1=−k1e2。
2.2 新的误差函数与控制目标
这时新的目标就产生了,需要令
x
2
→
x
2
d
x _ { 2 } \rightarrow x _ { 2d }
x2→x2d 。可以再引入一个误差函数
δ
=
x
2
d
−
x
2
(8)
\delta = x _ { 2d } - x _ { 2 }\tag{8}
δ=x2d−x2(8)这时候把
(
8
)
(8)
(8) 式带入到
(
6
)
(6)
(6) 式当中,可以得到新的
V
˙
1
\dot V_1
V˙1
V
˙
1
=
e
(
x
˙
1
d
−
(
x
2
d
−
δ
)
)
\dot { V } _ { 1 } = e ( \dot { x } _ { 1d } - ( x _ { 2d } - \delta ) )
V˙1=e(x˙1d−(x2d−δ))
把
x
2
d
x_{2d}
x2d 再代入,把
(
7
)
(7)
(7) 式代入
V
˙
1
=
−
k
1
e
2
+
e
δ
(9)
\dot { V } _ { 1 } = - k _ { 1 } e ^ { 2 } + e \delta \tag{9}
V˙1=−k1e2+eδ(9)这时来分析一下
δ
\delta
δ 的变化
δ
˙
=
x
˙
2
d
−
x
˙
2
\dot { \delta } = \dot x _ { 2d } - \dot { x } _ { 2 }
δ˙=x˙2d−x˙2把
(
2
)
(2)
(2) 式带入,同时也把
(
7
)
(7)
(7) 式带入
δ
˙
=
x
¨
1
d
+
k
1
e
˙
−
(
−
α
m
x
1
3
+
1
m
u
)
\dot { \delta } = \ddot { x} _ { 1 d} + k _ { 1 } \dot { e } - ( - \frac { \alpha } { m } x _ { 1 } ^ { 3 } + \frac { 1 } { m } u )
δ˙=x¨1d+k1e˙−(−mαx13+m1u)带入
(
4
)
(4)
(4) 式,消到
e
˙
\dot e
e˙,就就可以得到
δ
˙
=
x
¨
1
d
+
k
1
(
x
˙
1
d
−
x
2
)
+
α
m
x
1
3
−
1
m
u
(10)
\dot { \delta } =\ddot x _ { 1 d} + k _ { 1 } ( \dot { x } _ { 1 d} - x _ { 2 } ) + \frac { \alpha } { m } x _ { 1 } ^ { 3 } - \frac { 1 } { m } u\tag{10}
δ˙=x¨1d+k1(x˙1d−x2)+mαx13−m1u(10) 这时候目标,新的目标使得系统稳定,就希望
δ
,
e
\delta,e
δ,e 都趋向于零。也就是说要找到一个新的里阿普诺夫函数
V
(
e
,
δ
)
V(e,\delta)
V(e,δ),里面包含了
e
e
e 和
δ
\delta
δ ,使得它是正定函数,而且同时满足
V
˙
(
e
,
δ
)
\dot V(e,\delta)
V˙(e,δ) 是负定的。
2.3 李雅普诺夫函数的扩展
不妨构造新的李雅普诺夫函数
V
2
=
V
1
+
1
2
δ
2
V _ { 2 } = V _ { 1 } + \frac { 1 } { 2 } \delta ^ { 2 }
V2=V1+21δ2前面已经验证过了
V
1
V_1
V1 是一个正定的系统,而后面这一项
1
2
δ
2
\frac { 1 } { 2 } \delta ^ { 2 }
21δ2 也是正定的,所以整个来说,
V
2
V_2
V2 就是正定的,这时对
V
2
V_2
V2 求导
V
2
˙
=
V
1
˙
+
δ
δ
˙
\dot { V _ { 2 } } = \dot { V _ { 1 } } + \delta \dot { \delta }
V2˙=V1˙+δδ˙代入
(
9
)
(9)
(9) 式,这时
V
˙
2
=
−
k
1
e
2
+
e
δ
+
δ
δ
˙
=
−
k
1
e
2
+
δ
(
e
+
δ
˙
)
\dot V _ { 2 } = - k _ { 1 } e ^ { 2 } + e \delta + \delta \dot \delta = - k _ { 1 } e ^ { 2 } + \delta ( e + \dot { \delta } )
V˙2=−k1e2+eδ+δδ˙=−k1e2+δ(e+δ˙)
2.4 控制器增益的设计
从上式可见,
−
k
e
2
-ke^2
−ke2 是负定系统,而后面这一项
δ
(
e
+
δ
˙
)
\delta ( e + \dot { \delta } )
δ(e+δ˙) 当然也希望是负定的,所以就可以设计
e
+
δ
˙
=
−
k
2
δ
e + \dot { \delta } =-k_2\delta
e+δ˙=−k2δ 其中,
k
2
k_2
k2 也是大于
0
0
0 的控制器增益,这样
V
˙
2
=
−
k
1
e
2
−
k
2
δ
2
\dot{V}_2=-k_1e^2-k_2\delta ^2
V˙2=−k1e2−k2δ2所以新的目标就是让
e
+
δ
˙
=
−
k
2
δ
e + \dot { \delta } =-k_2\delta
e+δ˙=−k2δ。
2.5 输入表达式推导
这时把
(
10
)
(10)
(10) 代进去可以得到
e
+
x
¨
1
d
+
k
1
(
x
˙
1
d
−
x
2
)
+
α
m
x
1
3
−
1
m
u
=
−
k
2
δ
e + \ddot x _ { 1d }+ k _ { 1 } ( \dot x _ { 1 d} - x _ { 2 } ) + \frac { \alpha } { m } x _ { 1 } ^ { 3 } - \frac { 1 } { m } u = - k _ { 2 } \delta
e+x¨1d+k1(x˙1d−x2)+mαx13−m1u=−k2δ这时就可以推出来
u
=
m
e
+
m
x
¨
1
d
+
m
k
1
(
x
˙
1
d
−
x
2
)
+
α
x
1
3
+
m
k
2
δ
(11)
u = m e + m \ddot x _ { 1 d } + m k _ { 1 } ( \dot x _ { 1d } - x _ { 2 } ) + \alpha x _ { 1 } ^ { 3 } + m k _ { 2 } \delta\tag{11}
u=me+mx¨1d+mk1(x˙1d−x2)+αx13+mk2δ(11)经过了一系列的计算,这是最终想要得到的输入表达形式。
三、系统验证
下面来验证一下。
3.1 误差函数的动态方程
可以把
(
8
)
(8)
(8) 式代入
(
4
)
(4)
(4) 式,这时就可以得到
e
˙
=
x
˙
1
d
−
(
x
2
d
−
δ
)
\dot { e } = \dot x _ { 1d }- ( x _ { 2 d } - \delta )
e˙=x˙1d−(x2d−δ)这时再把
(
7
)
(7)
(7) 式
x
2
d
=
x
˙
1
d
+
k
1
e
x _ { 2 d } = \dot x _ { 1 d} + k _ { 1 } e
x2d=x˙1d+k1e 代入,就可以新的得到
e
˙
=
−
k
1
e
+
δ
\dot { e } = - k _ { 1 } e + \delta
e˙=−k1e+δ再把
(
11
)
(11)
(11) 式带回到
(
10
)
(10)
(10) 式,就可以得到
δ
˙
=
x
¨
1
d
+
k
1
(
x
˙
1
d
−
x
2
)
+
α
m
x
1
3
−
e
−
x
¨
1
d
−
k
1
(
x
˙
1
d
−
x
2
)
−
α
x
1
3
−
k
2
δ
=
−
e
−
k
2
δ
\begin{aligned} \dot{\delta}&=\ddot{x}_{1d}+k_1\left( \dot{x}_{1d}-x_2 \right) +\frac{\alpha}{m}x_{1}^{3}-e\\ &\ \ \ \ \ -\ddot{x}_{1d}-k_1\left( \dot{x}_{1d}-x_2 \right) -\alpha x_{1}^{3}-k_2\delta\\ &=-e-k_2\delta\\ \end{aligned}
δ˙=x¨1d+k1(x˙1d−x2)+mαx13−e −x¨1d−k1(x˙1d−x2)−αx13−k2δ=−e−k2δ
3.2 反馈线性化
把它们两个写在一起
[
e
˙
δ
˙
]
=
[
−
k
1
1
−
1
−
k
2
]
[
e
δ
]
\left[ \begin{array}{c} \dot{e}\\ \dot{\delta}\\ \end{array} \right] =\left[ \begin{matrix} -k_1& 1\\ -1& -k_2\\ \end{matrix} \right] \left[ \begin{array}{c} e\\ \delta\\ \end{array} \right]
[e˙δ˙]=[−k1−11−k2][eδ] 可以发现这是线性系统,所以整个过程就是通过反馈系统把它线性化 ( Feedback
Linurization
)了。
3.3 状态特征值分析
分析一下这个式子,对于这个系统来说,它的状态特征值
λ
1
+
λ
2
=
Λ
=
−
k
1
−
k
2
<
0
λ
1
⋅
λ
2
=
∣
−
k
1
1
−
1
−
k
2
∣
=
k
1
k
2
+
1
>
0
\begin{matrix} \lambda _ { 1 } + \lambda _ { 2 } = \Lambda = - k _ { 1 } - k _ { 2 } < 0 \\ \lambda _ { 1 } \cdot \lambda _ { 2 } = \left| \begin{matrix} -k_1& 1\\ -1& -k_2\\ \end{matrix} \right| = k _ { 1 } k _ { 2 } + 1 > 0 \end{matrix}
λ1+λ2=Λ=−k1−k2<0λ1⋅λ2=
−k1−11−k2
=k1k2+1>0所以可以推出
λ
1
,
λ
2
\lambda_1,\lambda_2
λ1,λ2 一定是同号,并且都小于
0
0
0 。
3.4 系统平衡点稳定性
再来看关于这个系统的平衡点,也就是
[
e
˙
δ
˙
]
=
0
⇒
[
e
δ
]
=
0
\left[ \begin{array}{c} \dot{e}\\ \dot{\delta}\\ \end{array} \right] =0\Rightarrow \left[ \begin{array}{c} e\\ \delta\\ \end{array} \right] =0
[e˙δ˙]=0⇒[eδ]=0就是它的平衡点是零点,而因为特征值都小于
0
0
0 ,所以它是渐进稳定的系统。
OK
,所有的问题都已经验证成功。
四、Simulink仿真
现在进入到 Simulink
当中来看一下整个系统的反应。下载链接如下:
链接:Simulink仿真文件
提取码:jjcc
4.1 Simulink模型构建
现在进入到 MATLAB Simulink
里:
4.2 动态方程实现
下面具体看一下
这一部分是系统的动态方程,有两个积分器,所以经过积分可分别得到
x
1
,
x
2
x_1,x_2
x1,x2 这里面就代表了系统方程,-u(2)/u(1)*u(3)^3+1/u(1)*u(4)
而这个方程对应于刚刚推导的
(
2
)
(2)
(2) 式:
x
˙
2
=
−
α
m
x
3
+
1
m
u
(2)
\dot{x}_2=-\frac{\alpha}{m}x^3+\frac{1}{m}u \tag{2}
x˙2=−mαx3+m1u(2)
4.3 输入信号构建
再看这一部分
这一部分就是系统输入,有很多项组成,可以在这里进行调节,由这一大堆式子来表明了 u u u 是怎么建立的:
u(1)*u(3)+u(1)*u(11)+u(1)*u(4)*(u(10)-u(8))+u(2)*u(7)^3+u(1)*u(5)*u(6)
4.4 期望值子系统设计
再回到头看左上角的期望值子系统,就是系统的设定值,打开看一下它的样子:
这里把它写成了一个正弦曲线的方法,因为如果自己直接用 Matlab
自带的 DDT
函数,就是 Derivative
模块的话,并不是一个很好的选择,因为它是用数值来解的,会出现无穷点,所以这部分自己写,因为考虑到是 sin
函数,所以这第一部分 sinx1
函数如下:
u(2)+u(3)*sin(u(1)*pi/u(4))
左侧第二个模块 u(2)
为重复序列阶梯(Repeating Sequence Stair),u(3)
Osc
为正弦函数的变化幅值,再乘以 sin
正弦函数。下面两个分别是它的导数以及二阶导数。
4.5 仿真结果分析
(1) 单目标值追踪
先来看一下,把正弦函数的变化幅值 Osc
设成
0
0
0 。假如就让目标值到
3
3
3 ,让
x
1
x_1
x1 的初始值是
0
0
0 ,这时候运行一下
这个 scope
代表了
x
1
x_1
x1 和
x
1
d
x_{1d}
x1d,
x
1
x_1
x1 是从
0
0
0 开始的,
3
3
3 是目标值,红线是目标,可以看到它很好地追踪到了黄线上。
(2) 多目标值追踪
这时改一下,把期望值改成有多个目标值的阶梯形式,比如 [3 5 7 2 1].'
,再来做运行一下
可以看到也是非常好的追踪效果。
(3) 波动与振荡效果测试
再来改一下,加上一些 波动,都让它从 3 3 3 开始,但是存在以 10 10 10 秒为周期的波动。
所以这时来看红线是想要的,走一个正弦波的形状,蓝线也是非常好的追踪效果,很快地就追踪过去了。
这时的输入可想而知,也是类似正弦的效果:
(4) 综合效果分析
这时再把期望值的 u(2)
复杂一点,比如说 [3 5 3 5 2].'
,同样让它有一个正弦信号的波动,这样再来看
追踪的效果依然还是非常好的,看到大概在 5 5 5 秒左右时,就可以很完整地贴合过去,最终效果比较好,大家可以把它下载下来,以后自己尝试不同的组合玩一玩。而且大家可以修改质量块的质量,修改弹性系数,包括可以修改不同的控制器增益,看会有什么不同的反应。
五、Matlab实现
%DSC example
%--------------------------------system-----------------------------------%
%dot_x1=x2
%dot_x2=-x1^2+u
%-------------------------------settings----------------------------------%
%initial state
%x1(0)=0.5,x2(0)=0
%sample time
%tao=0.01
%tracking target
%x_1d=[3 1 4 1 3]//interval time:20
%-------------------------------------------------------------------------%
%-------------------------------数据初始化--------------------------------%
%参数取值
k1=1;
k2=50;
%采样时间
tao=0.01;
%总采样次数
T=10000;
%总时间
total_time=tao*T; %观测时间设置为100秒
%定义初始状态
x1_initial=0.5;
x2_initial=0;
u_initial=0;
%定义状态变量矩阵和控制变量矩阵
x1=zeros(1,T);
x2=zeros(1,T);
u=zeros(1,T);
%x1d的定义
x1d=zeros(1,T);
for i=1:T/5
x1d(i)=3;
end
for i=T/5+1:2*T/5
x1d(i)=1;
end
for i=2*T/5+1:3*T/5
x1d(i)=4;
end
for i=3*T/5+1:4*T/5
x1d(i)=1;
end
for i=4*T/5+1:T
x1d(i)=3;
end
%x2d初始化
x2d=zeros(1,(T));
%x2_bar表示x2上面带杠杠
x2_bar=0;
for k=1:T
if k==1
x1(k)=x1_initial+tao*x2_initial;
x2(k)=x2_initial+tao*(-x1_initial^2+u_initial);
x2d(k)=x2_bar;
x2_bar=(x1d(k)-0)/tao-k1*(x1(k)-x1d(k));
u(k)=-(x1(k)-x1d(k))+x1(k)^2+(x2_bar-x2d(k))/tao-k2*(x2(k)-x2d(k));
else
x1(k)=x1(k-1)+tao*x2(k-1);
x2(k)=x2(k-1)+tao*(-x1(k-1)^2+u(k-1));
x2d(k)=x2_bar;
x2_bar=(x1d(k)-x1d(k-1))/tao-k1*(x1(k)-x1d(k));
u(k)=-(x1(k)-x1d(k))+x1(k)^2+(x2_bar-x2d(k))/tao-k2*(x2(k)-x2d(k));
end
end
figure(1),hold on;
plot(x1,'b','linewidth',1.2);
plot(x1d,'r','linewidth',1.2);
xlabel('时间/s');
ylabel('信号幅值');
title('动态面控制效果');
legend('x1','x1d')
set(gca,'xticklabel',0:10:100);
hold off;
六、总结
在本篇博客中,通过一个非线性弹簧系统实例,深入探讨了控制理论的应用。首先描述了系统的动态方程,并提出了控制目标:通过改变输入力 F F F,使小滑块按照指定轨迹移动。接着引入误差函数,并利用李雅普诺夫函数设计了反步控制器,通过反馈线性化将非线性系统转化为线性系统,并分析了系统的稳定性。
在 Simulink
仿真环节,构建了系统模型,并进行了动态方程的实现。通过设定不同的期望值,观察了系统对单目标值、多目标值以及波动和振荡效果的追踪能力。仿真结果显示,系统具有良好的追踪效果和稳定性。
本篇博客的内容就到这,下篇博客将进入自适应控制中,也就是说如果整个系统受到外界的不确定扰动,应该如何设计控制器,欢迎大家留言讨论。
参考资料
[1]【Advanced控制理论】15_Nonlinear Backstepping Control_反馈线性化控制_Feedback Linearization
[2] 全网最细反步法控制(Backstepping)设计讲解!!(3)——反步法控制、动态面matlab实例!(Dyanamic surface control)
后记:
🌟 感谢您耐心阅读这篇关于 反步法控制器原理与应用实例解析 的技术博客。 📚
🎯 如果您觉得这篇博客对您有所帮助,请不要吝啬您的点赞和评论 📢
🌟您的支持是我继续创作的动力。同时,别忘了收藏本篇博客,以便日后随时查阅。🚀
🚗 让我们一起期待更多的技术分享,共同探索移动机器人的无限可能!💡
🎭感谢您的支持与关注,让我们一起在知识的海洋中砥砺前行 🚀
更多推荐
所有评论(0)