Documentation
Tools for embedded systems
Loading...
Searching...
No Matches
Fuzzy Inference System Engine

A Fuzzy Inference System (FIS) is a key component of any fuzzy logic system. It uses fuzzy set theory, IF-THEN rules and fuzzy reasoning process to find the output corresponding to crisp inputs. Predicates in IF-THEN rules are connected using AND or OR logical connectives.

Fuzzy inference works by sending any process's crisp input to the fuzzifier, which applies a fuzzy membership function and maps the actual readings into fuzzy values. The inference engine applies fuzzy rules from the knowledge base and produces the fuzzy output. This output can not be used directly in any process or system. It needs to be mapped into the original domain. For this, the defuzzifier is used, which is the inverse process of fuzzification. It converts the fuzzy output into crisp output, which can be fed to the process.

The FIS Fuzzy Inference System engine provides an API for building and evaluation of type-1 fuzzy logic inference systems.

The types of inferences supported by FIS are listed in the qlibs::fis::type enum and are detailed below:

Mamdani

In a Mamdani system, the output of each rule is a fuzzy set. Since Mamdani systems have more intuitive and easier to understand rule bases, they are well-suited to expert system applications where the rules are created from human expert knowledge.

The output of each rule is a fuzzy set derived from the output membership function and the implication method of the FIS. These output fuzzy sets are combined into a single fuzzy set using the aggregation method of the FIS. Then, to compute a final crisp output value, the combined output fuzzy set is defuzzified using one of the methods described in Defuzzification Methods. To specify a FIS of this type use the qlibs::fis::Mamdani enum definition when calling qlibs::fis::instance::setup().

mamdanifis
Mamdani inference system

Sugeno

Sugeno fuzzy inference, also referred to as Takagi-Sugeno-Kang fuzzy inference, uses singleton output membership functions that are either constant or a linear function of the input values. The defuzzification process for a Sugeno system is more computationally efficient compared to that of a Mamdani system, since it uses a weighted average or weighted sum of a few data points rather than computing the centroid of a two-dimensional area.

Each rule generates two values:

\(u_i\) Rule output level, which is either a constant value or a linear function of the input values.

and \(w_i\), the rule firing strength, that is determined by the rule antecedent

The output of each rule is the weighted output level, which is the product of \(w_i\) and \(u_i\).

The final output of the system is the weighted average/sum over all rule outputs:

\(out= \frac{ \sum_{i=1}^{N}w_{i}u_{i} }{ \sum_{i=1}^{N}w_{i}} \)

where \(N\) is the number of rules.

Because of the linear dependence of each rule on the input variables, the Sugeno method is ideal for acting as an interpolating supervisor of multiple linear controllers that are to be applied, respectively, to different operating conditions of a dynamic nonlinear system.

To specificy a FIS of this type, use the qlibs::fis::Sugeno enum definition when calling qlibs::fis::instance::setup().

sugenofis
Sugeno inference system

Tsukamoto

In the Tsukamoto inference system, the consequent of each fuzzy if-then rule is represented by a fuzzy set with a monotonical membership function, As a result, the inferred output of each rule is defined as a crisp value induced by the rule's firing strength.

The overall output is taken as the weighted average of each rule's output. Since each rule infers a crisp output, the Tsukamoto fuzzy model aggregates each rule's output by the method of weighted average and thus avoids the time-consuming process of defuzzification.

To specify a FIS of this type, use the qlibs::fis::Tsukamoto enum definition when calling qlibs::fis::instance::setup() .

tsukamotofis
Tsukamoto inference system

Defuzzification Methods

FIS supports five different methods, as listed in the qlibs::fis::deFuzzMethod enum for computing a single crisp output value for such a fuzzy set.

  1. qlibs::fis::centroid (default): this method applies only to qlibs::fis::Mamdani systems and returns the center of gravity of the fuzzy set along the x-axis. If you think of the area as a plate with uniform thickness and density, the centroid is the point along the x-axis about which the fuzzy set would balance. The centroid is computed using the following formula, where \(\mu(x)\) is the membership value for point \(x_i\) in the universe of discourse.
\(\text{centroid}= \frac{ \sum_{i=1}\mu(x_{i})x_{i} }{ \sum_{i=1}\mu(x_{i})} \)
  1. qlibs::fis::bisector : this method applies only for qlibs::fis::Mamdani systems and finds the vertical line that divides the fuzzy set into two sub-regions of equal area. It is sometimes, but not always, coincident with the centroid line.
  2. qlibs::fis::mom : Middle of Maximum. Only for qlibs::fis::Mamdani systems.
  3. qlibs::fis::som : Smallest of Maximum. Only for qlibs::fis::Mamdani systems.
  4. qlibs::fis::lom : Largest of Maximum. Only for qlibs::fis::Mamdani systems.
  5. qlibs::fis::wtaver (default): Weighted average of all rule outputs. This method applies only for qlibs::fis::Sugeno and qlibs::fis::Tsukamoto systems.
  6. qlibs::fis::wtsum : Weighted sum of all rule outputs. This method applies only for qlibs::fis::Sugeno and qlibs::fis::Tsukamoto systems.
Note
The defuzzification method is selected by default when setting up the FIS instance with qlibs::fis::instance::setup(). However, the user can later change the default method using the qlibs::fis::instance::setDeFuzzMethod() function.

Building a Mamdani FIS

To carry out the FIS building process in a more friendly manner, we will explain it using a specific example. The goal is to solve the tipping problem, which is described as follows:

Given a number from 0 through 10 that represents the quality of service at a restaurant, where 10 is excellent, and another number from 0 through 10 that represents the quality of the food, where 10 is delicious, what should the tip be? Tipping behavior varies depending on local traditions and personal preferences. In this example, the problem is based on tipping as it is typically practiced in the United States. An average tip for a meal in the US is 15%. A generous tip could be as high as 25% and a cheap tip could be 5%.

The actual amount of the tip can vary depending on the quality of the service and food. For this problem, tipping behavior is defined using the following three rules.

  1. IF the service IS poor OR the food IS rancid, THEN the tip IS cheap.
  2. IF the service IS good, THEN the tip IS average.
  3. IF the service IS excellent OR the food IS delicious, THEN the tip IS generous.

This leads to a system with 2 inputs : service and food and 1 output: tip

fistipper
Tipper FIS

5 membership functions for the inputs

  1. (service)poor : A gaussian membership function with spread of 1.5 and center on 0
  2. (service)good : A gaussian membership function with spread of 1.5 and center on 5
  3. (service)excelent : A gaussian membership function with spread of 1.5 and center on 10
  4. (food)rancid : A trapezoidal membership function with points located on [0 0 1 3]
  5. (food)delicious : A trapezoidal membership function with points located on [7 9 10 10]

and 3 membership functions for the output

  1. (tip)cheap : A triangular membership function with points located on [0 5 10]
  2. (tip)average : A triangular membership function with points located on [10 15 20]
  3. (tip)generous : A triangular membership function with points located on [20 25 30]
tippermfs
Membership functions for the tipper FIS

To build the fuzzy system, you must first instantiate an abstract object of type qlibs::fis::instance that represents the fuzzy inference system, then the input and output vectors, fuzzy set vectors for inputs and outputs, and enumerations with the tags for all of them. Let's take a look :

// I/O Names
enum : fis::tag { service, food};
enum : fis::tag { tip};
// I/O Membership functions tags
enum : fis::tag { service_poor, service_good, service_excellent, food_rancid, food_delicious};
enum : fis::tag { tip_cheap, tip_average, tip_generous};
// FIS Object
static fis::instance tipper;
// I/O Fuzzy Objects
static fis::input tipper_inputs[ 2 ];
static fis::output tipper_outputs[ 1 ];
// I/O Membership Objects
static fis::mf MFin[5], MFout[3];
Attention
Please note that all tag names are unique.

Then, we will define the rules of the fuzzy system using the previously defined tags. Rules should be defined as an array of type qlibs::fis::rules and the contents should be rules constructed with the provided statements:

  • FIS_RULES_BEGIN to start the rules set
  • FIS_RULES_END to end the rules set
  • IF to start a rule sentence
  • END to end a rule sentence
  • AND and OR fuzzy connectors
  • IS and IS_NOT to represent a premise and a negated premise respectively.
  • THEN to represent the implication

Let's apply some of these statements to build the rule set.

static const fis::rules rules[] = {
IF service IS service_poor OR food IS food_rancid THEN tip IS tip_cheap END
IF service IS service_good THEN tip IS tip_average END
IF service IS service_excellent OR food IS food_delicious THEN tip IS tip_generous END
};
#define FIS_RULES_END
Ends a Fuzzy rule set. The FIS_RULES_END statement is used to finalize the declaration of a FIS rule ...
Definition fis.hpp:476
#define END
Rule statement to end a rule sentence.
Definition fis.hpp:490
#define OR
Rule statement to represent the OR connector.
Definition fis.hpp:482
#define IF
Rule statement to begin a rule sentence.
Definition fis.hpp:478
#define FIS_RULES_BEGIN
Start a Fuzzy rule set. The FIS_RULES_BEGIN statement is used to declare the starting point of a FIS ...
Definition fis.hpp:457
#define IS
Rule statement to represent a premise.
Definition fis.hpp:486
#define THEN
Rule statement to represent the implication.
Definition fis.hpp:484

Additionally, we also need to define a vector where the firing strength of each rule will be stored. The size of the vector will be the number of rules. In this particular case, there will be only three.

static real_t rulesStrength[ 3 ];

First step is to configure the instance that represents the fuzzy system using the qlibs::fis::instance::setup() API:

tipper.setup( fis::Mamdani, tipper_inputs, tipper_outputs, MFin, MFout, rules, rulesStrength );

Then, we can proceed to the construction of the fuzzy system. First, we must configure the inputs and outputs by setting the ranges of each. For this, we will use the qlibs::fis::instance::setupInput() and qlibs::fis::instance::setupOutput() methods as follows:

tipper.setupInput( service, 0.0f, 1.0f );
tipper.setupInput( food, 0.0f, 10.0f );
tipper.setupOutput( tip, 0.0f, 30.0f );

The next step is to configure the membership functions by relating I/O, tags, shape and parameters one by one by using the qlibs::fis::instance::setupInputMF() and qlibs::fis::instance::setupOutputMF() methods as follows: Then, let's define the parameters of all the membership functions:

tipper.setupInputMF( service, poor, fis::gaussmf, (const real_t[]){ 1.5f, 0.0f } );
tipper.setupInputMF( service, good, fis::gaussmf, (const real_t[]){ 1.5f, 5.0f } );
tipper.setupInputMF( service, excellent, fis::gaussmf, (const real_t[]){ 1.5f, 10.0f } );
tipper.setupInputMF( food, rancid, fis::trapmf, (const real_t[]){ 0.0f, 0.0f, 1.0f, 3.0f } );
tipper.setupInputMF( food, delicious, fis::trapmf, (const real_t[]){ 7.0f, 9.0f, 10.0f, 10.0f } );
tipper.setupOutputMF( tip, cheap, fis::trimf, (const real_t[]){ 0.0f, 5.0f, 10.0f } );
tipper.setupOutputMF( tip, average, fis::trimf, (const real_t[]){10.0f, 15.0f, 20.0f } );
tipper.setupOutputMF( tip, generous, fis::trimf, (const real_t[]){ 20.0f, 25.0f, 30.0f } );
Note
The number of parameters may vary depending on the shape of the membership function.

Evaluating a Fuzzy Inference System

If we already have a fuzzy system configured with qlibs::fis::instance::setup(), we can evaluate it by using qlibs::fis::instance::fuzzify(), qlibs::fis::instance::inference() and qlibs::fis::instance::deFuzzify(). Input values can be set with qlibs::fis::instance::setInput() and output values can be obtained with qlibs::fis::instance::getOutput(). Also you can use the stream operator << to set the inputs and the index operator [] to get the outputs of the FIS system (see example bellow).

To show its use, first we are going to put everything together in a single code snippet and we are going to create two functions, tipper_init() and tipper_run() that will be in charge of setting up the fuzzy inference system and evaluating it respectively.

#include "tipper_fis.h"
#include <qlibs.h>
using namespace qlibs;
// I/O Names
enum : fis::tag { service, food};
enum : fis::tag { tip};
// I/O Membership functions tags
enum : fis::tag { service_poor, service_good, service_excellent, food_rancid, food_delicious};
enum : fis::tag { tip_cheap, tip_average, tip_generous};
// FIS Object
static fis::instance tipper;
// I/O Fuzzy Objects
static fis::input tipper_inputs[ 2 ];
static fis::output tipper_outputs[ 1 ];
// I/O Membership Objects
static fis::mf MFin[5], MFout[3];
// Rules of the inference system
static const fis::rules rules[] = {
IF service IS service_poor OR food IS food_rancid THEN tip IS tip_cheap END
IF service IS service_good THEN tip IS tip_average END
IF service IS service_excellent OR food IS food_delicious THEN tip IS tip_generous END
};
//Rule strengths
real_t rStrength[ 3 ] = { 0.0f };
void tipper_init( void )
{
tipper.setup( fis::Mamdani, tipper_inputs, tipper_outputs, MFin, MFout, rules, rStrength );
tipper.setupInput( service, 0.0f, 1.0f );
tipper.setupInput( food, 0.0f, 10.0f );
tipper.setupOutput( tip, 0.0f, 30.0f );
tipper.setupInputMF( service, poor, fis::gaussmf, (const real_t[]){ 1.5f, 0.0f } );
tipper.setupInputMF( service, good, fis::gaussmf, (const real_t[]){ 1.5f, 5.0f } );
tipper.setupInputMF( service, excellent, fis::gaussmf, (const real_t[]){ 1.5f, 10.0f } );
tipper.setupInputMF( food, rancid, fis::trapmf, (const real_t[]){ 0.0f, 0.0f, 1.0f, 3.0f } );
tipper.setupInputMF( food, delicious, fis::trapmf, (const real_t[]){ 7.0f, 9.0f, 10.0f, 10.0f } );
tipper.setupOutputMF( tip, cheap, fis::trimf, (const real_t[]){ 0.0f, 5.0f, 10.0f } );
tipper.setupOutputMF( tip, average, fis::trimf, (const real_t[]){ 10.0f, 15.0f, 20.0f } );
tipper.setupOutputMF( tip, generous, fis::trimf, (const real_t[]){ 20.0f, 25.0f, 30.0f } );
}
void tipper_run( real_t *inputs, real_t *outputs )
{
// Set the crips inputs
tipper.setInput( service, inputs[ service ] );
tipper.setInput( food, inputs[ food ] );
tipper.fuzzify();
if ( tipper.inference() ) {
tipper.deFuzzify();
}
else {
// Error!
}
// Get the crips outputs
outputs[ tip ] = tipper[ tip ];
}
A FIS Input object.
Definition fis.hpp:149
A FIS(Fuzzy Inference System) object.
Definition fis.hpp:500
bool setupOutputMF(const tag io, const tag mf, const shapeMF s, const real_t *cp, const real_t h=1.0_re) noexcept
Setup the output tag and points for the specified membership function.
Definition fis.hpp:710
bool deFuzzify(void) noexcept
Perform the de-Fuzzification operation to compute the crisp outputs.
Definition fis.cpp:418
bool setupInputMF(const tag io, const tag mf, const shapeMF s, const real_t *cp, const real_t h=1.0_re) noexcept
Setup the input tag and points for the specified membership function.
Definition fis.hpp:659
bool setup(const type t, input *const inputs, const size_t ni, output *const outputs, const size_t no, mf *const mf_inputs, const size_t nmi, mf *const mf_outputs, const size_t nmo, const rules *const r, const size_t n, real_t *rWeights=nullptr) noexcept
Setup and initialize the FIS instance.
Definition fis.cpp:71
bool setupOutput(const tag t, const real_t Min, const real_t Max) noexcept
Setup the output with the specified tag and set limits for it.
Definition fis.cpp:136
bool fuzzify(void) noexcept
Perform the fuzzification operation over the crisp inputs on the requested FIS object.
Definition fis.cpp:234
bool inference(void) noexcept
Perform the inference process on the FIS object.
Definition fis.cpp:478
bool setInput(const tag t, const real_t value) noexcept
Set a crisp value of the input with the specified tag.
Definition fis.cpp:170
bool setupInput(const tag t, const real_t Min, const real_t Max) noexcept
Setup the input with the specified tag and set limits for it.
Definition fis.cpp:119
A FIS Membership Function.
Definition fis.hpp:335
A FIS Output object.
Definition fis.hpp:163
int16_t rules
Type definition to instantiate a set of fuzzy rules.
Definition fis.hpp:406
rules tag
Used to define an enum of fis tags.
Definition fis.hpp:421
The qLibs++ library namespace.
Definition fp16.cpp:4
float real_t
A type to instantiate a real variable double-precision of 64-bits IEEE 754.
Definition qlibs_types.hpp:43

Code generation

Building a fuzzy system in code can become tedious, especially when you want to tune membership function parameters. It would be appropriate to have a graphical tool that reflects the changes made by each tweak.

Although the FIS engine does not provide such a tool, a well-known tool, MATLAB's Fuzzy Logic Toolbox, can be used to design and build the fuzzy system. What qLibs++ does provide is a command-line tool that can be used to take a FIS file generated by MATLAB and generate C++ code based on the FIS engine.

Download the C++-Code generator here: