模糊逻辑并不需要特别的硬件或新的编程语言,只是要求有一种不同的设置隶属关系(membership)的方法。从电梯到电饭煲,大量的物理系统都可受益于模糊逻辑编程。本文探讨了对一个商用DSP芯片编程来创建一个基本的模糊逻辑控制器。
你可以采用现成的标准微处理器来构建模糊逻辑系统。传统的微处理器对于大多数应用来说是足够的,即使是模糊逻辑,但对于需要可预测且非常快速响应时间的高安全性系统来说则未必。当传统处理器不够快时,数字信号处理器(DSP)可能正是你的系统所需要的。
图1:“高”的布尔变量。
DSP是具有指令集和面向算术运算特性的专用微处理器,其最初只是用在信号处理应用。现在,随着DSP软件开发工具种类的增加和质量的提升,这种处理器变得越来越流行。DSP如今在成本上与通用微处理器也能竞争。今天,任何可以受益于高速乘法/累加 (MAC)运算的应用都可以考虑采用DSP。
本文将阐述模糊逻辑系统的组成部分,并给出如何采用DSP来实现的实例。
模糊逻辑基础
Lotfi Zadeh被认为是模糊逻辑的创立者,他在1965年的一篇文章中提出了布尔数学体系集合论的扩展,将二元扩展到多值。他的模糊逻辑集合论是一种广义的经典集合论,是对非精确性的极好表述。模糊逻辑的优势在于它可以在不采用数学方法的情况下使你能准确地描述一个过程或行为。
图2:“高”的模糊变量。
布尔数学体系集合既可以是真,也可以是假,而模糊集合可以具有部分的这种隶属关系。例如,图1给出了一个布尔变量。在布尔表中,对于6英尺来说“高”是真,而低于6英尺则为假,但在图2中,模糊变量的高既不是真也不是假,它具有可变的真假隶属关系。布尔变量通常被称为明确的集合(crisp set),模糊变量成为模糊集合。模糊集合行为类似于其对应的明确集合。举例来说,模糊逻辑采用“与”、“或”、“非”以及补数运算。“与”处理是取输入量中的小者,“或”处理是取输入量的较大者,补数运算是用1减去输入值。
控制器的组件
任何基于模糊逻辑的控制器具有三个组件:模糊化器(fuzzifier)、规则库和去模糊化器。在将一个明确(数字)输入转变成模糊值并对该值进行处理,然后再将模糊值转变成明确值输出的过程中,每个组件扮演着重要的角色。尽管模糊控制器的实现不尽相同,他们都具有这三个基本部分。
模糊化器获取一个明确输入值,并根据是否需要将其进行缩放来转换成模糊值,并转变为多值实体(entity)。缩放处理将输入域映射到所有变量都采用的一些内部格式。该多值实体是将输入值与其对应的输入集合进行比较的结果,并对该值进行映射处理以反应出其隶属关系特性。
列表1:去模糊化器:主函数的C代码。
规则库从前一级取得输入值,并将其与每个相关语句的区间相加。规则库由一系列一个或多个IF-THEN语句组成。每个语句依次组成了两个部分:条件(antecedent),在关键字then的左边;结果(consequent),在then的右边。一个语句可能具有一个或更多的antecedent和consequent。典型的规则语句看起来就像这样:
IF antecedent1 . . . antecedentN THEN
consequence1 . . . consequenceN
条件和结果都采用条件形式变量,这里的变量是条件的输入变量或结果的输出变量。结果的条件部分是一个模糊隶属函数,如“冷”、“暖和”、“热”。规则库对来自模糊化器的数据与规则进行比较。当它遇到一个条件是真,就触发语句的结果动作。
列表2:去模糊化器:GetData()函数的C代码。
以电梯为例,规则库可能就像:
IF门打开AND速度为零 AND距离可以忽略 THEN电机转速为0
IF 门关闭AND速度慢 AND 距离大THEN电机转速最大
IF 门关闭AND速度中等 AND距离一般 THEN电机转速一般
IF 门关闭AND 速度快AND 距离一般THEN电机转速一般
这个例子有四个规则,每个规则有四个变量:门、电机、速度、距离(到选定层)。每个规则有三个条件和一个结果,总共有十种情况组成了四个变量的隶属关系集合。例如,速度具有变量0、慢、中等和快速。可变距离具有以下四个值:忽略、很小、一般、大。门要么开要么就是关闭。对于各种隶属集合,电机转速具有0、最小、平均和最大四个变量。
举例来说,我们假设升降机门是关闭的,速度为10英尺每秒,这个速度定义在慢和中两种隶属关系区间的中间(所有的隶属关系区间互相重叠)。距离是42英尺,这个值同时被定义在大和中两个区间。这样一来规则库中的两个规则都被激发(第二个和第三个规则),结果就被平均了。
列表3:模糊化器部分的实现。
规则激发是控制器组件中的关键问题。当规则激发时将导致语句的条件部分变成有效。一旦有效,语句的结果部分就与所有被激发规则的结果累加起来。这样一来,该级的输出将产生一个所有激发结果的复合值。这看起来就像被激发结果的所有隶属集合的和。
模糊逻辑的第三个组件是去模糊化器。去模糊化器将来自前一级的输出转变为明确的输出值。当今有四种方法在执行去模糊化中比较流行,分别是重心法(Centroid)、最大化、单点(singleton)和权重平均。每种方法都有其优势和不足,重心法最流行。这里只讨论一下重心法。
重心法去模糊化是计算来自前一级的复合模糊集合的“重心”。这是一种数字密集型方法,需要计算集合的积分,还要求输出集合重叠以避免产生无效输出的情况,以及每个变量的隶属集合由一个奇数或区间组成。
代码转换
为在DSP上实现实时模糊逻辑控制器,你需要将模糊逻辑引擎设计转换到实际的代码。为了将每个组件转换为软件,你必须了解控制器、控制器的每部分以及它将控制的系统。
列表4:规则代码。
将主要的程序转换成代码是很简单的。本质上,它无外乎就是这样的无限循环:获得数据值并将他们转换成对等的模糊量,处理模糊数据,再将输出去模糊化形成明确值,最后将这个值输出到正确的输出端口。这些操作的每一个都对应着一个C函数,它们共同组成了模糊引擎。
在列表1中的GetData()函数从一个I/O器件重新获得数据点。这个函数只是一部分,仅用来测试,但是如果完全实现它,将访问物理I/O器件。在本例中,函数从一个阵列中提取存储数据点,每个循环提取一个数据点集合,并将提取的数据馈入到下一个函数,即模糊化器。
Fuzzifier()函数将数据转换为一个模糊表达,转换方法是通过一个结构将明确的数据值变换成规则库能使用的值。然后,Fuzzifier()必须为每次循环反复清除数据点。在每次反复后,另外一个内置函数来清除这个结构。一旦转换完成,规则库就可以使用这些数据点。
RuleBase得到模糊化器的结果(数据点),然后将这些点与内部规则库表进行比较。当产生一个匹配,RuleBase就获取对应的结果值,并将这个值用于每个被触发的规则。之后,RuleBase将所有的触发规则相加产生一个最后的模糊结果,最后将这个结果应用到Defuzzifier()函数。
Defuzzifier()函数将模糊数据转换回一个明确的量,这个量可以为数模转换器或其它的物理器件所用。通常,一个输出片段将这个输出转变成一个外部世界可以处理的值。然而,由于我们通过采用阵列使系统受到限制,去模糊化器组件仅简单地将结果存储到输出阵列。列表1和2显示了主函数和GetData()函数的C代码。
列表5:去模糊化器。
为了将模糊程序编写成代码,让我们回到模糊化器的介绍以确保我们了解模糊化器是如何工作的。模糊化器是将明确的输入数据转换成可以操作的模糊数据,这意味着这个数据被转换成了一个多值量。而且这个量还是该特定输入数据的隶属集合的一个函数。一个C结构是用来存储模糊化数据单元的理想结构,因为它可以具有多个值。这种结构的每一个单元对应着一个隶属区间。例如模糊输入变量Deflection具有“小”、“中”、“大”三个区间。假设区间定义如下:
0 <“小” < 25
10<“中”< 55
20 <“大”< 90
如果这个变量的明确输入具有13这个值,其对等的模糊化量就由一个多值变量组成,这个变量具有三个布尔值:“小”、“中”和“大”。这三个单元是根据明确输入数据来设置的。每个域都是一个布尔量,初始值设置为“假”。13这个值落入到两个类别,因此小和中两个单元都设置为真。同样,23这个输入值将所有三个组件集合设置为真。在代码中实现模糊化器这个概念需要由下面的步骤组成:创建一个C结构、将其范围与输入数据比较,根据比较来指定一个适当的域。列表3给出了模糊化器部分的实现。如果有需要的话,模糊化器通常执行缩放处理。
图3: FuzzyLevel系统。
控制器的规则库部分执行输入数据的处理。由于这部分处理大部分的工作,因此规则库是最复杂的。前面讲过,规则库将表中所有触发规则值进行求和,然后将和除以这些规则的数量。表中包含了每个输入变量的隶属区间值。例如“Position”变量有三个区间,变量“Error”有5个区间。表总共有15(5*3)个单元。表的列和行的交叉点对应IF-THEN语句中的条件部分中的两个条件的AND。矩阵中的值从左向右增加,从上向下增加。例如,如果“Position”的区间为“近”、“邻近”、“远”。近对应着矩阵中的0列,邻近对应着第一列,依次类推。类似地,如果变量“Error”具有“很小”、“小”、“一般、”“大”、“很大”五个量,“很小”对应第一行,“小”为第二行,依次类推。因此,矩阵中的交叉点就对应条件语句中的AND处理。例如第0列和第0行对应为真:
IF Position 为近 AND Error很小 THEN . . .
列表4给出了规则库的代码。注意到单元都为序数,在模型定义和调整后,这些单元都被填满。另外,这个表的大小是规则数的函数,因此表的大小随应用而变。如果表改变,与阵列相关的变量必须也改变以反映它的大小改变。
去模糊化器模块将模糊化的输出转换成明确的输出。通常,去模糊化器将模糊输出转变为明确输出,然后再将其缩放到变量的外部域。该引擎在两方面与传统的去模糊化器相背离:第一,实际的明确数值存储在规则表中,故不必对它们进行转换。在大部分真实场景中,模拟输入和输出通常由在0-5伏之间随时变化的电压构成。一个例子就是常用于控制马达和伺服电机的PWM。列表5给出了去模糊化器的代码。注意,通过使它经过一个阵列来访问,这部分还简化了外部接口。这使我们可以专注于逻辑调试。一旦逻辑调试完,真正的I/O被加进来。使用一个阵列用于测试的另一个好处就是可使过程更容易移植。
应用实例
FuzzyLevel是基于DSP控制器的一个实例,用来控制一个工业控制应用的液体槽中流体的高度和压强。这种控制器通常用在炼油厂。
表1:FuzzyLevel模型表。
FuzzyLevel保持槽中液体在一个确定的高度,同时保证其中的气压不会达到危险的程度。槽中的液体高度和压强是相关联的,液体越多压强越大。同样,液体以某个恒定的速度流入槽中。图3给出了FuzzyLevel系统的简化框图。采用传感器来监测气压和液体高度,一个电机用来控制输出阀门打开的程度。
了解了系统如何动作之后,现在需要将这个动作转换为能通过仿真来得到其最佳工作点的设计。为实现这种转换,首先需要确定系统的输入、输出以及将进行的处理。从前面的描述中我们知道系统的输入来自传感器,因此,压强和高度是输入变量。此外,电机是系统中的唯一输出。因此,“阀门”是系统唯一的输出变量。紧接着需要定义变量的范围。对于本例,我们假设每个变量有三个区间。例如,压强的区间为“小”、“中”、“大”;“高度”的区间为“低”、“一般”、“高”;唯一的输出变量阀门的区间为“全关”、“部分开”、“全开”。
定义了变量和它们的区间之后就可以描述系统处理了。正如前面提到的,输入和输出之间存在一定关系,描述这种关系也就定义了系统的行为。而且这种行为使用系统本身的规则来描述的,规则的数量与输入变量的区间相关。由于每个规则有三个区间,因此该系统有9个规则。现在就完成了大致的模型。
图4: FuzzyLevel应用拷屏图。
接着需要仿真这个模型来产生进入模糊引擎矩阵的去模糊化的点。本例将采用来自Impatiens Publications 的TeachFuzz模糊逻辑仿真器。在将设计转换为仿真器能理解的格式之前,必须设置输入和输出变量的实际值。仿真器并不关心所有单位的类别,它唯一的要求就是一些正数。单位对仿真器并不重要(设计师为了方便而采用这些单位)。变量的范围如下:0<高< 80,0 <压强 <1,600和0<阀门 < 240。这些变量的单位分别为英尺、磅/平方英寸和转矩的英尺*磅。
运行仿真器将产生关于模型的可视数据,你通常必须对模型进行修改,因为模型的动作并不像所期望的那样。对模型参数的修改也称为调整过程。调整使我们能找到控制器最佳的工作点。通常,调整包括区间数的修改以及改变这些区间的形状。这里的模型也不例外。在完成调整后,就可以将规则矩阵载入。我们可以通过找到只触发一个规则的数据集合来确定去模糊化值。这个值被放入到矩阵中相应输入变量区间的交叉点。例如,下面的规则是某个给定输入数据集合触发的唯一规则:IF高度为“低”且压强为“中”THEN阀门为“部分开”。
30这个值被放入到矩阵中,对应“高度”为“低”和“压强”为“中”的交叉点。这对应的是那个结果的重心点。对所有的规则反复进行这个过程不断,直到矩阵完全填满为止。表1显示了FuzzyLevel模型表完全填满的结果。当表矩阵满时,控制器就可以进行测试了。图4和图5显示了一个在十次代码反复之后的编译/调试片段,这里采用TI的Code Composer仿真C5402 DSP芯片。插入的printfs在这里用来简化I/O验证。仿真统计表显示了第一次反复占用了722个周期,十次反复占用7,100个周期,平均每次反复为710个周期。在一个100MHz的C5402芯片上,FuzzyLevel从输入到输出的每一个反复需要0.71毫秒。对于大多数应用来说,这个速度可能太大材小用了,但对于安全很关键的应用来说,这又是很合理的,例如前面的流体槽。
快速模糊
当采用一般的微处理器不能满足快速系统响应要求时,采用模糊逻辑的DSP加速将非常有效,当前很多应用采用这种方法,例如一些医学麻醉系统或伺服电机控制器。Fuzzy Level的例子也是一种类似于一些当前在炼油厂中所用的简化控制系统。你可以修改引擎来提供更多的输入和输出。特别是,通过修改阵列将引擎修改成N输入×M输出的控制器。可以通过改变阵列为输入的函数来增加额外的输入,例如三个输入--三维规则矩阵。多个输出可以通过几种方法来处理,例如矩阵的交叉单元可以包含多个值。反过来,交叉点单元可以包含一个指向保持所有去模糊化数值的数据结构的指针。另一个改进就是使不同的条件只触发特定的结果。然而,这涉及到多控制器的重构以及指针的广泛间接应用。如果你决定这样做,请确保最后的响应时间能够足够快来响应系统的输入。
图5:Code Composer Studio仿真FuzzyLevel应用的结果。
作者简介:Byron Miller是一位独立的固件工程师,专注于微处理器、DSP的设计和硬件调试、移植,以及针对控制数据获取、模糊逻辑、互联网设备的固件开发。他具有计算机科学学士学位和软件工程硕士学位。