一篇文章带你搞懂使用PID

news2024/12/23 17:01:27

节选自本人博客:https://www.blog.zeeland.cn/archives/pid-learning
本文为笔者参考了网上众多大神的解析之后加上自己的理解整合起来的,因此在内容上部分参考了其他作者,目的仅用作参考以便更好地学习,如有侵犯,可联系笔者修改。

Introduction

本文先从介绍PID的概念开始,由Kp到Ki再到Kd逐步深入讲解,并展现出了从Kp到pid三个变量组合发展过程和Python代码实现,适合新手入门。

应用PID控制的前提是系统一定要是一个闭环系统,什么是闭环系统?就是一定要有反馈回路,要能及时反馈我们最终控制的那个量的状态,给到控制器。也就是说,PID控制是根据被控系统的状态来进行控制的,我们需要知道这个状态才能决定控制器下一步应该怎么做。

总的来说,PID控制的用途分为两种,

  • 一种是使某个物理量“保持稳定",即便出现外界干扰也能很快回到原始的稳定状态;
  • 另一种是使物理量稳定地“跟踪”给定的信号,稳定地随着给定信号变化。

PID公式如下所示:

具体地,被控系统输出c(t)与给定量r(t)进行比较,得到偏差e(t),控制器对偏差值进行比例P、积分I、微分D三种运算合成,得到对应的控制器输出u(t),反馈给被控系统,进一步调节作动器的行为(例如阀门开度、电机转速、力矩输出等等)从而使偏差趋近于零,进而使被控对象的行为趋近于给定的指令信号。

  • 比例环节P可以提高系统响应的快速性,但单独使用比例环节并不能使系统性能稳定在一个理想的状态,当有余差出现,较大的比例系数会引起较大的控制器输出,导致超调过大,系统产生振荡,使系统稳定性变差;
  • 积分调节I可以在比例调节的基础上减小余差,提升系统的稳态性能;
  • 微分环节D属于超前调节,可以提升系统的动态性能,使系统超调量减小、稳定性增加。

PID中三个参数,大体对应于控制系统的三个最重要的方面:
P对应“稳”,即稳定性,放大控制作用;I对应“准”,消除稳态误差;D对应“快”,对误差进行预判、做出快速反应。

Example

接下来我们从一些生活中的例子开始逐步地讲解PID三者。

比例控制算法

我们先说PID中最简单的比例控制,抛开其他两个不谈,还是用一个经典的例子吧。假设我有一个水缸,最终的控制目的是要保证水缸里的水位永远的维持在1米的高度。假设初始时刻,水缸里的水位是0.2米,那么当前时刻的水位和目标水位之间是存在一个误差的error,且error为0.8.这个时候,假设旁边站着一个人,这个人通过往缸里加水的方式来控制水位。如果单纯的用比例控制算法(kp),就是指加入的水量u和误差error是成正比的。即u = kp * error

假设现在kp = 0.5,则有:

t=1时(表示第1次加水,也就是第一次对系统施加控制),那么u=0.50.8=0.4,所以这一次加入的水量会使水位在0.2的基础上上升0.4,达到0.6.
t=2时刻(第2次施加控制),当前水位是0.6,所以error是0.4。u=0.5
0.4=0.2,会使水位再次上升0.2,达到0.8。
t=3…

t=n…

可以看到,最终水位会达到我们需要的1米。

用Python实现这一过程,可以看到结果如下所示:

import matplotlib.pyplot as plt

class ApplicationWithKp:
    def __init__(self, ex=1, current=0.2, kp=0.5):
        self.ex = ex
        self.current = current
        self.kp = kp
        self.error = self.ex - self.current
        self.iterate_times = 0

        self.output_list = [self.current]
        self.error_list = [self.error]

    def run(self):
        self.iterate(100)
        self.plot()
        print(self.output_list)
        print("[info] iterate times: ", self.iterate_times)

    def iterate(self, epoch):
        """ iterate to update current, error """
        for i in range(epoch):
            # 加水量u
            u = self.kp * self.error
            self.current += u
            self.output_list.append(self.current)
            self.error_list.append(self.error)
            self.error = self.ex - self.current
            if self.current >= self.ex:
                self.iterate_times = i
                return
            self.iterate_times = epoch

    def plot(self):
        l1, = plt.plot(list(range(len(self.output_list))), self.output_list, label='output')
        l2, = plt.plot(list(range(len(self.error_list))), self.error_list, label='error', linestyle='--', color='r')
        l3 = plt.plot(list(range(len(self.output_list))), [1] * len(self.output_list), linestyle='--', color='g'  )
        plt.xlabel('times / s')
        plt.ylabel('water volume / (m^3)')
        plt.legend(handles=[l1, l2],
                   labels = ['output', 'error'])
        plt.show()

app = ApplicationWithKp()
app.run()


可以看到,当kp=0.5时,需要迭代53次才能形成稳态,接下来我们把kp设为0.9,看看要迭代多少次。

app_2 = ApplicationWithKp(kp=0.9)
app_2.run()


可以看到,kp=0.9时迭代16次就收敛了,可以看出kp起着一个放大控制作用。

像上述的例子,根据kp取值不同,系统最后都会达到1米,只不过kp大了到达的快,kp小了到达的慢一些。不会有稳态误差。但是,考虑另外一种情况,假设这个水缸在加水的过程中,存在漏水的情况,假设每次加水的过程,都会漏掉0.1米高度的水。仍然假设kp取0.5,那么会存在着某种情况,假设经过几次加水,水缸中的水位到0.8时,水位将不会再变换。因为水位为0.8,则误差error=0.2. 所以每次往水缸中加水的量为u=0.5*0.2=0.1.同时,每次加水,缸里又会流出去0.1米的水。加入的水和流出的水相抵消,水位将不再变化。

我们仅需要把刚才iterate函数中current += u的代码改成current += u - 0.1 ,就能得到以下结果。

也就是说,我的目标是1米,但是最后系统达到0.8米的水位就不再变化了,且系统已经达到稳定。由此产生的误差就是稳态误差了。

在实际情况中,这种类似水缸漏水的情况往往更加常见,比如控制汽车运动,摩擦阻力就相当于是“漏水”,控制机械臂、无人机的飞行,各类阻力和消耗都可以理解为本例中的“漏水”。所以,单独的比例控制,在很多时候并不能满足要求。

积分控制算法

通过上面的例子我们可以发现,**如果仅仅使用比例控制算法,就会存在稳态误差的问题。**因此,当前我们再引入一个分量,该分量与误差的积分是正比关系,加入积分控制,公式变为:u = kp * error + ki * ∫error

还是用上面的例子来说明,第一次的误差error是0.8,第二次的误差是0.4,至此,误差的积分(离散情况下积分其实就是做累加),∫error=0.8+0.4=1.2. 这个时候的控制量,除了比例的那一部分,还有一部分就是一个系数ki乘以这个积分项。由于这个积分项会将前面若干次的误差进行累计,所以可以很好的消除稳态误差(假设在仅有比例项的情况下,系统卡在稳态误差了,即上例中的0.8,由于加入了积分项的存在,会让输入增大,从而使得水缸的水位可以大于0.8,渐渐到达目标的1.0.)这就是积分项的作用。

KI的Python实现,我们只需要在刚才ApplicationWithKp类的基础上稍作修改,就可以得到ApplicationWithKpKi的实现,代码如下:

import matplotlib.pyplot as plt

class ApplicationWithKpKi:
    def __init__(self, ex=1, current=0.2, kp=0.5, ki=0.05):
        self.ex = ex
        self.current = current
        self.kp = kp
        self.ki = ki
        self.error = self.ex - self.current
        self.error_acc = self.error # error accumulation
        self.iterate_times = 0

        self.output_list = [self.current]
        self.error_list = [self.error]

    def run(self):
        self.iterate(50)
        self.plot()
        print(self.output_list)
        print("[info] iterate times: ", self.iterate_times)

    def iterate(self, epoch):
        """ iterate to update current, error """
        for i in range(epoch):
            # 加水量u
            u = self.kp * self.error + self.ki * self.error_acc
            self.current += u
            self.output_list.append(self.current)
            self.error_list.append(self.error)
            self.error = self.ex - self.current
            self.error_acc += self.error
            # if self.current >= self.ex:
            #     self.iterate_times = i
            #     return
            self.iterate_times = epoch

    def plot(self):
        l1, = plt.plot(list(range(len(self.output_list))), self.output_list, label='output')
        l2, = plt.plot(list(range(len(self.error_list))), self.error_list, label='error', linestyle='--', color='r')
        l3 = plt.plot(list(range(len(self.output_list))), [1] * len(self.output_list), linestyle='--', color='g'  )
        plt.xlabel('times / s')
        plt.ylabel('water volume / (m^3)')
        plt.legend(handles=[l1, l2],
                   labels = ['output', 'error'])
        plt.show()

if __name__ == '__main__':
    app = ApplicationWithKpKi(kp=0.5, ki=0.05)
    app.run()

运行结果如下所示:

我们可以看到,事实上,因为error的积累导致的超调,即在装水的过程中装了比1L还多的水!当然,在当前这个例子中,水桶中的水大于1L的情况是不可能存在的,但是在其他场景下允许该中情况的出现,因此,关于Ki我们就需要调整到一个合适的值。

微分控制算法

换一个另外的例子,考虑刹车情况。平稳的驾驶车辆,当发现前面有红灯时,为了使得行车平稳,基本上提前几十米就放松油门并踩刹车了。当车辆离停车线非常近的时候,则使劲踩刹车,使车辆停下来。整个过程可以看做一个加入微分的控制策略。

微分,说白了在离散情况下,就是error的差值,就是t时刻和t-1时刻error的差,即u=kd*(error(t)-error(t-1)),其中的kd是一个系数项。可以看到,在刹车过程中,因为error是越来越小的,所以这个微分控制项一定是负数,在控制中加入一个负数项,他存在的作用就是为了防止汽车由于刹车不及时而闯过了线。从常识上可以理解,越是靠近停车线,越是应该注意踩刹车,不能让车过线,所以这个微分项的作用,就可以理解为刹车,当车离停车线很近并且车速还很快时,这个微分项的绝对值(实际上是一个负数)就会很大,从而表示应该用力踩刹车才能让车停下来。
切换到上面给水缸加水的例子,就是当发现水缸里的水快要接近1的时候,加入微分项,可以防止给水缸里的水加到超过1米的高度,说白了就是减少控制过程中的震荡。

有前面两次的代码迭代,我们最后要实现kd的累加也很简单,只需要再之前的代码的基础上记录下两次error的差值就可以了,即记录下e(t) - e(t-1)

import matplotlib.pyplot as plt

class ApplicationWithKpKiKd:
    def __init__(self, ex=1, current=0.2, kp=0.5, ki=0.05, kd=0.1):
        self.ex = ex
        self.current = current
        self.kp = kp
        self.ki = ki
        self.kd = kd
        self.error = self.ex - self.current
        self.error_acc = self.error # error accumulation
        self.delta_error = self.error # d_e = e(t) - e(t-1)
        self.iterate_times = 0

        self.output_list = [self.current]
        self.error_list = [self.error]

    def run(self):
        self.iterate(50)
        self.plot()
        print(self.output_list)
        print("[info] iterate times: ", self.iterate_times)

    def iterate(self, epoch):
        """ iterate to update current, error """
        for i in range(epoch):
            # 加水量u
            u = self.kp * self.error + self.ki * self.error_acc + self.kd * self.delta_error
            self.current += u
            self.error = self.ex - self.current
            self.error_acc += self.error
            self.delta_error = self.error - self.error_list[-1]

            self.output_list.append(self.current)
            self.error_list.append(self.error)
            self.iterate_times = epoch

    def plot(self):
        l1, = plt.plot(list(range(len(self.output_list))), self.output_list, label='output')
        l2, = plt.plot(list(range(len(self.error_list))), self.error_list, label='error', linestyle='--', color='r')
        l3 = plt.plot(list(range(len(self.output_list))), [1] * len(self.output_list), linestyle='--', color='g'  )
        plt.xlabel('times / s')
        plt.ylabel('water volume / (m^3)')
        plt.legend(handles=[l1, l2],
                   labels = ['output', 'error'])
        plt.show()

if __name__ == '__main__':
    app = ApplicationWithKpKiKd(kp=0.5, ki=0.1, kd=0.3)
    app.run()


我们可以看到,相对于只有kp和ki,加了kd之后收敛速度会更快一些,但事实上,如果kd调节地过大,一些噪音信号会被严重放大造成震荡,因此选择合适的PID参数特别重要!下图为kd过大的结果。

在真正的工程实践中,最难的是如果确定三个项的系数,这就需要大量的实验以及经验来决定了。通过不断的尝试和正确的思考,就能选取合适的系数,实现优良的控制器。

快速上手使用PID

事实上,如果你想要Python快速上手PID,你完全没必要自己写一个PID实现,因为已经有人把PID给封装好了,你只需要传入一些简单的参数,就能很好的实现PID!这个库就是simple-pid,你可以使用pip install simple-pid来安装该库,现在我们借由simple-pid中的example来快速上手一次。

import os
import sys
import time
import matplotlib.pyplot as plt
from simple_pid import PID


class WaterBoiler:
    """
    Simple simulation of a water boiler which can heat up water
    and where the heat dissipates slowly over time
    """

    def __init__(self):
        self.water_temp = 20

    def update(self, boiler_power, dt):
        if boiler_power > 0:
            # Boiler can only produce heat, not cold
            self.water_temp += 1 * boiler_power * dt

        # Some heat dissipation
        self.water_temp -= 0.02 * dt
        return self.water_temp


if __name__ == '__main__':
    boiler = WaterBoiler()
    water_temp = boiler.water_temp

    pid = PID(5, 0.01, 0.1, setpoint=water_temp)
    pid.output_limits = (0, 100)

    start_time = time.time()
    last_time = start_time

    # Keep track of values for plotting
    setpoint, y, x = [], [], []

    while time.time() - start_time < 10:
        current_time = time.time()
        dt = current_time - last_time

        power = pid(water_temp)
        water_temp = boiler.update(power, dt)

        x += [current_time - start_time]
        y += [water_temp]
        setpoint += [pid.setpoint]

        if current_time - start_time > 1:
            pid.setpoint = 100

        last_time = current_time

    plt.plot(x, y, label='measured')
    plt.plot(x, setpoint, label='target')
    plt.xlabel('time')
    plt.ylabel('temperature')
    plt.legend()
    if os.getenv('NO_DISPLAY'):
        # If run in CI the plot is saved to file instead of shown to the user
        plt.savefig(f"result-py{'.'.join([str(x) for x in sys.version_info[:2]])}.png")
    else:
        plt.show()

接着,你就会得到一条优美的弧线。

这里我想说一下,为什么和simple-pid相比,笔者上面绘制的曲线更折更生硬一点,主要的原因是迭代次数的问题,笔者在迭代的时候只迭代了几十次,但是在一些实际问题上,PID算法需要基于时间去做积分,而不仅仅只是做离散的迭代,因此你在simple-pid的example中也可以看到,他的迭代是通过time的积分微分来构建的。

最后附上一些关于PID的其他观点:

如果一个系统的机理模型建立的比较准确,PID控制也是有严格的数学依据的,可以通过严格的传递函数的闭环零极点分析得到;
微分的微分为什么一般不用呢?因为微分能够严重放大噪声信号,而实际测得的输出量肯定含有噪声,因此高次微分很难用;
一般由于PID控制只关心输入输出,而一般不关心系统的内部特性,所以对于建模不准确的系统PID是最理想的控制器之一,这也导致了PID控制器的参数一般采用经验法来整定。

我喜欢这样理解pid: p是控制现在,i是纠正曾经,d是管控未来!只有不忘过往,把握当前,规划未来才能让人生的轨迹按照既定的目标前进。讲真,理解了弹性阻尼系统,对pid的内涵会更加深刻。

那为啥不加入更进一步的,微分的微分或者微分的微分的微分呢。如果有其他因素,该如何使用PID呢 ——@荆慢慢2.0

一般来说微分环节相当于放大了反馈信号中的高频分量,如果取得系数不好会引起高频震荡。所以大部分应用都只采用PI(不影响稳态精度)或者双闭环PI。至于微分的微分等一些量在物理上并没有实际意义,比如调速中转速的微分是加速度,再次微分就基本不用了。当然如果学过自控理论则可以从系统传递函数来分析需要加入什么样的控制器来保持系统稳定收敛。—— @Lyn

References

  • PID模拟仿真实验 -知乎
  • PID控制算法原理(抛弃公式,从本质上真正理解PID控制) -知乎
  • https://github.com/m-lundberg/simple-pid -python -github

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/30953.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

慎投:这两本期刊被剔除SCI/SSCI, 11月WOS数据库已更新~

2022年11月22日, Clarivate更新了Journal List, 虽然影响因子每年仅更新一次&#xff0c;但是WOS数据库每个月都会不定期地进行调整&#xff0c;经过审查陆续将部分期刊剔除或新增。 本次更新&#xff0c;SCIE&SSCI期刊数据库剔除(Dropped)或停止检索(Ceased)了6本期刊&am…

运动装备品牌排行榜,运动爱好者必备好物分享

健身运动就像打游戏一样&#xff0c;如何区分你和其他玩家的差别呢&#xff1f;有时候靠身材&#xff0c;当然有时候也会拼装备&#xff0c;那么这些运动装备能否增加buff呢&#xff1f;是否值得入手呢&#xff1f;作为一名资深的运动爱好者&#xff0c;下面我就从实用角度聊一…

计算机组成原理4小时速成:硬件软件,编译,控制器,存储器,运算器,输入输出设备,存储字长

计算机组成原理4小时速成&#xff1a;硬件软件&#xff0c;编译&#xff0c;控制器&#xff0c;存储器&#xff0c;运算器&#xff0c;输入输出设备&#xff0c;存储字长 2022找工作是学历、能力和运气的超强结合体&#xff0c;遇到寒冬&#xff0c;大厂不招人&#xff0c;可能…

软件测试V模型

以“编码”为黄金分割线&#xff0c;将整个过程分为开发和测试&#xff0c;并且开发和测试之间是串行的关系 特点&#xff1a; 明确标注了测试的类型 明确标注了测试阶段和开发阶段之间的对应关系 缺点&#xff1a; 测试后置 V模型是基于瀑布模型的&#xff0c;将测试放在…

PowerShell 批量部署windows_exporter到所有Windows主机

前提条件 参考 批量拷贝脚本到远程主机 $local_path"D:\PowerShell\Powershell-Windows_Admin_Center-install\" #本地脚本存放目录$Destination"d:\" #本地拷贝的脚本到目标主机的目录Invoke-Command -filepath D:\powershell-install-windows_exporter-…

【构建ML驱动的应用程序】第 8 章 :部署模型时的注意事项

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

11个步骤完美排查服务器是否被入侵

随着开源产品的越来越盛行&#xff0c;作为一个Linux运维工程师&#xff0c;能够清晰地鉴别异常机器是否已经被入侵了显得至关重要&#xff0c;个人结合自己的工作经历&#xff0c;整理了几种常见的机器被黑情况供参考&#xff1a; 背景信息&#xff1a;以下情况是在CentOS 6.…

计算机的磁盘与中断介绍

磁盘 大多数计算机都有磁盘。这只是连接到I/O总线的另一个外围设备。磁盘的任务非常简单&#xff1b;它可以做两件事&#xff1a;存储你发给它的字节&#xff0c;它发送给你之前存储的字节。 大多数计算机都有磁盘有两个原因。首先&#xff0c;它们能够存储大量字节&#xff0c…

微信小程序实现一些优惠券/卡券

背景 &#x1f44f; 前几周有小伙伴问我如何用css实现一些优惠券/卡券&#xff0c;今天就来分享一波吧&#xff01;速速来Get吧~ &#x1f947;文末分享源代码。记得点赞关注收藏&#xff01; 1.实现效果 2.实现原理 2.1 实现内凹圆角 假设我们要实现这样的一个效果&#xf…

Java八股文

2022年接近年底了&#xff0c;想必绝大多数的小伙伴跳槽的心已经蠢蠢欲动。但一边又是互联网寒冬、大厂裁员&#xff0c;导致人心惶惶&#xff0c;想跳又不敢跳。但现在罡哥&#xff0c;给大家整理了八股文大厂面试真题和面试技巧。这里免费分享给大家。 资料包括&#xff1a;…

算法day29|491,46,47

491.递增子序列 class Solution:def findSubsequences(self, nums: List[int]) -> List[List[int]]:used [False]*len(nums)result []nums.sort()def backtracking(nums,path,startindex,used):nonlocal resultif len(path)>1:result.append(path[:])for i in range(s…

云原生系列 五【轻松入门容器基础操作】

✅作者简介&#xff1a; CSDN内容合伙人&#xff0c;全栈领域新星创作者&#xff0c;阿里云专家博主&#xff0c;华为云云享专家博主&#xff0c;掘金后端评审团成员 &#x1f495;前言&#xff1a; 最近云原生领域热火朝天&#xff0c;那么云原生是什么&#xff1f;何为云原生…

C<6.1>函数习题(函数内测整形数组大小,递归

目录 1&#xff0c;数组比较 2&#xff0c;勒让德多项式 3&#xff0c;查询数组&#xff08;sizeof问题 1&#xff0c;数组比较 1. 编写函数实现比较两个长度为 n&#xff08;n 可变&#xff09;的数组大小。比较逻 辑如下&#xff1a; 假设 a 和 b 为 n 个元素的整型数组&am…

Web(一)Web前端开发概述

第1关_Web前端开发相关的概念 相关知识 为了完成本关任务&#xff0c;你需要掌握&#xff1a;1.Web系统的组成&#xff1b;2.浏览器的概念&#xff1b;3.URL的概念&#xff1b;4.Web标准。 Web系统的组成&#xff1a;Web是Internet上最受欢迎的一种多媒体信息服务系统。 整个…

【LeetCode】string 类的几道简单题

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《阿亮爱刷题》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 &#x1f449;仅反转字母&a…

Java源代码到用户使用都经历了哪些阶段

1、测试好的代码是如何部署给用户的。 首先&#xff1a;写好的代码通过打包生成jar包放到一个服务器上运行&#xff0c;服务器上需要有Java虚拟机&#xff0c;当然可以在存放jar包的服务器上安装数据库&#xff0c;或者把服务器放到另外一台服务器上也可以&#xff0c;但是在代…

SpringCloud-04-Feign

一、Feign介绍 Feign是一个声明式web服务客户机。它使编写web服务客户机更容易。要使用Feign创建一个接口并对其进行注释。它具有可插入注释支持&#xff0c;包括Feign注释和JAX-RS注释。Feign还支持可插式编码器和解码器。Spring Cloud增加了对Spring MVC注释的支持&#xff…

10个全球最佳免费土地覆被/土地利用数据资源

不知道大家有没有想过&#xff0c;在我们来到地球的一生时间中&#xff0c;地球会有多大的变化呢? 是在空旷的草地新建了公园&#xff0c;还是低矮的平房变成了一座座大厦? 这些林林总总的变化&#xff0c;总是令人应接不暇。然而&#xff0c;在漫长的人类历史历程中&#xf…

2022亚太数学杯数学建模竞赛A题(思路分析......)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

Java数据类型:基本数据类型和引用数据类型

Java 语言是强类型语言&#xff0c;编译器存储在变量中的数值具有适当的数据类型。学习任何一种编程语言都要了解其数据类型&#xff0c;下面将详细介绍 Java 中的数据类型。 Java 语言支持的数据类型分为两种&#xff1a;基本数据类型&#xff08;Primitive Type&#xff09;…