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 qFIS Fuzzy Inference System engine provides an API for building and evaluation of type-1 fuzzy logic inference systems.

The types of inferences supported by qFIS are listed in the qFIS_Type_t 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 Mamdani enum definition when calling qFIS_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 Sugeno enum definition when calling qFIS_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 Tsukamoto enum definition when calling qFIS_Setup().

tsukamotofis
Tsukamoto inference system

Defuzzification Methods

qFIS supports five different methods, as listed in the qFIS_DeFuzz_Method_t type for computing a single crisp output value for such a fuzzy set.

  1. centroid (default): this method applies only to 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. bisector : this method applies only for 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. mom : Middle of Maximum. Only for Mamdani systems.
  3. som : Smallest of Maximum. Only for Mamdani systems.
  4. lom : Largest of Maximum. Only for Mamdani systems.
  5. wtaver (default): Weighted average of all rule outputs. this method applies only for Sugeno and Tsukamoto systems.
  6. wtsum: Weighted sum of all rule outputs. This method applies only for Sugeno and Tsukamoto systems.
Note
The defuzzification method is selected by default when setting up the FIS instance with qFIS_Setup(). However, the user can later change the default method using the qFIS_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 qFIS_t 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 :

// FIS Object
static qFIS_t tipper;
// I/O Fuzzy Objects
static qFIS_Input_t tipper_inputs[ 2 ];
static qFIS_Output_t tipper_outputs[ 1 ];
// I/O Membership Objects
static qFIS_MF_t MFin[5], MFout[3];
// I/O Names
enum { service, food};
enum { tip};
// I/O Membership functions tags
enum { service_poor, service_good, service_excellent, food_rancid, food_delicious};
enum { tip_cheap, tip_average, tip_generous};
A FIS Input object.
Definition qfis.h:132
A FIS Membership Function.
Definition qfis.h:165
A FIS Output object.
Definition qfis.h:144
A FIS(Fuzzy Inference System) object.
Definition qfis.h:234
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 qFIS_Rules_t and the contents should be rules constructed with the provided statements:

  • QFIS_RULES_BEGIN to start the rules set
  • QFIS_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 qFIS_Rules_t 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
};
int16_t qFIS_Rules_t
Type definition to instantiate a set of fuzzy rules.
Definition qfis.h:219
#define END
Rule statement to end a rule sentence.
Definition qfis.h:330
#define OR
Rule statement to represent the OR connector.
Definition qfis.h:322
#define QFIS_RULES_END
Ends a Fuzzy rule set. The QFIS_RULES_END statement is used to finalize the declaration of a FIS rule...
Definition qfis.h:315
#define IF
Rule statement to begin a rule sentence.
Definition qfis.h:318
#define IS
Rule statement to represent a premise.
Definition qfis.h:326
#define THEN
Rule statement to represent the implication.
Definition qfis.h:324
#define QFIS_RULES_BEGIN
Start a Fuzzy rule set. The QFIS_RULES_BEGIN statement is used to declare the starting point of a FIS...
Definition qfis.h:295

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 float rulesStrength[ 3 ];

Once all the necessary elements have been defined, 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 qFIS_InputSetup() and qFIS_OutputSetup() functions as follows:

qFIS_InputSetup( tipper_inputs, service, 0.0f, 10.0f );
qFIS_InputSetup( tipper_inputs, food, 0.0f, 10.0f );
qFIS_OutputSetup( tipper_outputs, tip, 0.0f, 30.0f );
int qFIS_InputSetup(qFIS_Input_t *const v, const qFIS_Tag_t t, const float min, const float max)
Setup the input with the specified tag and set limits for it.
Definition qfis.c:269
int qFIS_OutputSetup(qFIS_Output_t *const v, const qFIS_Tag_t t, const float min, const float max)
Setup the output with the specified tag and set limits for it.
Definition qfis.c:285

Then, let's define the parameters of all the membership functions:

/*Parameters of the membership functions*/
static const float service_poor_p[] = { 1.5f, 0.0f };
static const float service_good_p[] = { 1.5f, 5.0f };
static const float service_excellent_p[] = { 1.5f, 10.0f };
static const float food_rancid_p[] = { 0.0f, 0.0f, 1.0f, 3.0f };
static const float food_delicious_p[] = { 7.0f, 9.0f, 10.0f, 10.0f };
static const float tip_cheap_p[] = { 0.0f, 5.0f, 10.0f };
static const float tip_average_p[] = { 10.0f, 15.0f, 20.0f };
static const float tip_generous_p[] = { 20.0f, 25.0f, 30.0f }
Note
The number of parameters may vary depending on the shape of the membership function.

the next step is to configure the membership functions by relating I/O, tags, shape and parameters one by one by using the qFIS_SetMF() API as follows:

/* setup membership functions for the inputs */
qFIS_SetMF( MFin, service, service_poor, gaussmf, NULL, service_poor_p, 1.0f );
qFIS_SetMF( MFin, service, service_good, gaussmf, NULL, service_good_p, 1.0f );
qFIS_SetMF( MFin, service, service_excellent, gaussmf, NULL, service_excellent_p, 1.0f );
qFIS_SetMF( MFin, food, food_rancid, trapmf, NULL, food_rancid_p, 1.0f );
qFIS_SetMF( MFin, food, food_delicious, trapmf, NULL, food_delicious_p, 1.0f );
/* setup membership functions for the outputs */
qFIS_SetMF( MFout, tip, tip_cheap, trimf, NULL, tip_cheap_p, 1.0f );
qFIS_SetMF( MFout, tip, tip_average, trimf, NULL, tip_average_p, 1.0f );
qFIS_SetMF( MFout, tip, tip_generous, trimf, NULL, tip_generous_p, 1.0f );
int qFIS_SetMF(qFIS_MF_t *const m, const qFIS_Tag_t io, const qFIS_Tag_t mf, const qFIS_MF_Name_t s, qFIS_MF_Fcn_t custom_mf, const float *cp, const float h)
Set the IO tag and points for the specified membership function.
Definition qfis.c:336
@ trapmf
Definition qfis.h:32
@ trimf
Definition qfis.h:31
@ gaussmf
Definition qfis.h:34

Finally, we only have to configure the instance that represents the fuzzy system using the qFIS_Setup() API:

/*Parameters of the membership functions*/
qFIS_Setup( &tipper, Mamdani,
tipper_inputs, sizeof(tipper_inputs),
tipper_outputs, sizeof(tipper_outputs),
MFin, sizeof(MFin), MFout, sizeof(MFout),
rules, rStrength, 3u );
int qFIS_Setup(qFIS_t *const f, const qFIS_Type_t t, qFIS_Input_t *const inputs, const size_t ni, qFIS_Output_t *const outputs, const size_t no, qFIS_MF_t *const mf_inputs, const size_t nmi, qFIS_MF_t *const mf_outputs, const size_t nmo, const qFIS_Rules_t *const r, float *wi, const size_t n)
Setup and initialize the FIS instance.
Definition qfis.c:217
@ Mamdani
Definition qfis.h:104

Evaluating a Fuzzy Inference System

If we already have a fuzzy system configured with qFIS_Setup(), we can evaluate it by using qFIS_Fuzzify(), qFIS_Inference() and qFIS_DeFuzzify(). Input values can be set with qFIS_SetInput() and output values can be obtained with qFIS_GetOutput()

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 "qfis.h"
// FIS Object
static qFIS_t tipper;
// I/O Fuzzy Objects
static qFIS_Input_t tipper_inputs[ 2 ];
static qFIS_Output_t tipper_outputs[ 1 ];
// I/O Membership Objects
static qFIS_MF_t MFin[ 5 ], MFout[ 3 ];
// I/O Names
enum { service, food };
enum { tip };
// I/O Membership functions tags
enum { service_poor, service_good, service_excellent, food_rancid, food_delicious };
enum { tip_cheap, tip_average, tip_generous };
// Rules of the inference system
static const qFIS_Rules_t 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
float rStrength[ 3 ] = { 0.0f };
// Parameters of the membership functions
static const float service_poor_p[] = { 1.5f, 0.0f };
static const float service_good_p[] = { 1.5f, 5.0f };
static const float service_excellent_p[] = { 1.5f, 10.0f };
static const float food_rancid_p[] = { 0.0f, 0.0f, 1.0f, 3.0f };
static const float food_delicious_p[] = { 7.0f, 9.0f, 10.0f, 10.0f };
static const float tip_cheap_p[] = { 0.0f, 5.0f, 10.0f };
static const float tip_average_p[] = { 10.0f, 15.0f, 20.0f };
static const float tip_generous_p[] = { 20.0f, 25.0f, 30.0f };
void tipper_init( void )
{
// Set inputs
qFIS_InputSetup( tipper_inputs, service, 0.0f, 10.0f );
qFIS_InputSetup( tipper_inputs, food, 0.0f, 10.0f );
qFIS_OutputSetup( tipper_outputs, tip, 0.0f, 30.0f );
// Set membership functions for the inputs
qFIS_SetMF( MFin, service, service_poor, gaussmf, NULL, service_poor_p, 1.0f );
qFIS_SetMF( MFin, service, service_good, gaussmf, NULL, service_good_p, 1.0f );
qFIS_SetMF( MFin, service, service_excellent, gaussmf, NULL, service_excellent_p, 1.0f );
qFIS_SetMF( MFin, food, food_rancid, trapmf, NULL, food_rancid_p, 1.0f );
qFIS_SetMF( MFin, food, food_delicious, trapmf, NULL, food_delicious_p, 1.0f );
// Set membership functions for the outputs
qFIS_SetMF( MFout, tip, tip_cheap, trimf, NULL, tip_cheap_p, 1.0f );
qFIS_SetMF( MFout, tip, tip_average, trimf, NULL, tip_average_p, 1.0f );
qFIS_SetMF( MFout, tip, tip_generous, trimf, NULL, tip_generous_p, 1.0f );
// Configure the Inference System
qFIS_Setup( &tipper, Mamdani,
tipper_inputs, sizeof(tipper_inputs),
tipper_outputs, sizeof(tipper_outputs),
MFin, sizeof(MFin), MFout, sizeof(MFout),
rules, rStrength, 3u );
}
void tipper_run( float *inputs, float *outputs )
{
// Set the crips inputs
qFIS_SetInput( tipper_inputs, service, inputs[ service ] );
qFIS_SetInput( tipper_inputs, food, inputs[ food ] );
qFIS_Fuzzify( &tipper );
if ( qFIS_Inference( &tipper ) > 0 ) {
qFIS_DeFuzzify( &tipper );
}
else {
// Error!
}
// Get the crips outputs
outputs[ tip ] = qFIS_GetOutput( tipper_outputs, tip );
}
float qFIS_GetOutput(const qFIS_Output_t *const v, const qFIS_Tag_t t)
Get the de-fuzzified crisp value from the the output with the specified tag.
Definition qfis.c:323
int qFIS_Inference(qFIS_t *const f)
Perform the inference process on the requested FIS object.
Definition qfis.c:859
int qFIS_DeFuzzify(qFIS_t *const f)
Perform the de-Fuzzification operation to compute the crisp outputs.
Definition qfis.c:792
int qFIS_SetInput(qFIS_Input_t *const v, const qFIS_Tag_t t, const float value)
Set a crisp value of the input with the specified tag.
Definition qfis.c:309
int qFIS_Fuzzify(qFIS_t *const f)
Perform the fuzzification operation over the crisp inputs on the requested FIS object.
Definition qfis.c:426

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 qFIS engine does not provide such a tool, a well-known tool, MATLAB's Fuzzy Logic Toolbox, can be used to build the fuzzy system and generate qFIS-compatible C code. qLibs provides a MATLAB command that can be used to take a FIS object generated by that tool and generate C code based on the qFIS engine.

Download the C-Code generator here: