Journal Articles

CVu Journal Vol 12, #3 - May 2000 + Programming Topics
Browse in : All > Journals > CVu > 123 (22)
All > Topics > Programming (877)
Any of these categories - All of these categories

Note: when you create a new publication type, the articles module will automatically use the templates user-display-[publicationtype].xt and user-summary-[publicationtype].xt. If those templates do not exist when you try to preview or display a new article, you'll get this warning :-) Please place your own templates in themes/yourtheme/modules/articles . The templates will get the extension .xt there.

Title: An Introduction to Fuzzy Logic

Author: Administrator

Date: 03 May 2000 13:15:36 +01:00 or Wed, 03 May 2000 13:15:36 +01:00

Summary: 

Body: 

One of the Cambridge colleges has a relationship with a college in Japan, and as a result has a building partly owned by the Japanese college. This building contains a very modern, air-conditioned concert hall, which like many concert halls has numerous lights. During the course of a concert, these lights were frequently adjusted in a continuous manner, never suddenly jumping from one level to another. Naturally I imagined a skilled operator sitting behind a bank of variable resistors, but it turned out to be computer-controlled - the computer would gently slide the lighting into whatever configuration was requested at a small touch-sensitive console. But the rate of change was never constant - someone had obviously designed a complex mathematical model for it. Or had they?

Fuzzy logic is a method of quickly designing classification systems by capturing the intuition of the designer. It was made popular in embedded control systems in Japan because "classification" can be interpreted as "deciding what to do next" (you classify the inputs into sets that correspond to best actions), and it is also possible to have continuous output variables (like "rate of change"). But fuzzy logic is not limited to control systems - it can be used anywhere where there are rules of the form "if this condition holds then that output is preferred" and where it is unclear how to resolve conflicts of interest between the rules.

Consider a single continuous input variable. Sometimes different actions should be taken depending on whether it is large or small (or near to certain values), and the traditional means of doing this (apart from working out complex equations) is by thresholding, ie.

void decide(int input) {
  if(input<threshold1) action1();
  else if (input<threshold2) action2();
  else action3();
}

The problem with this is that you have to decide where to put the thresholds, and the system might "change its mind" too often around those points; also it is difficult to reconcile with other conditions on other inputs that might have conflicting interests. In fuzzy logic, the code would look more like the following:

void decide(int input1, int input2) {
  int vote1=0, vote2=0, vote3=0;
  vote1 += functionA(input1);
  vote2 += functionB(input1);
  vote3 += functionC(input1);
  vote1 += functionD(input2);
  vote2 += functionE(input2);
  vote3 += functionF(input2);
  /* Other functions on other inputs go here */
  if(vote1>vote2 && vote1>vote3) action1();
  else if(vote2>vote3) action2();
  else action3();
}

Needless to say, it is a biased voting system - each function determines how many "votes" a particular action should get given the value of an input, and the action with the most votes wins. If the system is to be prevented from "changing its mind" too rapidly, the action previously taken could also be voted for (indeed, previous actions can be included with the inputs and any amount of logic done on them). In fuzzy logic theory, these "votes" are normalised so that all the numbers are between 0 and 1, but in an embedded system you would usually want to use integer arithmetic. (By the way, I'm not using standard fuzzy logic terminology because I think it's easier to think of as a voting system.) The functions themselves can be anything (and can of course take more than one of the inputs), but they are usually quite simple, for example:

int functionA(int i) {
  if (condition(i)) return 2;
  else return 0;
}
int functionB(int i) {
  int difference=i-midVal;
  if (difference<0) difference=-difference;
  if (difference>maxVote) return 0;
  else return maxVote-difference;
}

The first of these simply casts two votes if a certain condition is true (rules can be weighted by changing the number of votes they can cast). The second is a triangle function - it casts "maxVote" votes if the input is exactly "midVal", with a decreasing number of votes for inputs "around" that value; the sharpness of decrease can be adjusted by multiplying or dividing (or bit shifting) "difference" by a constant. It is usually easier to specify things this way than to choose thresholds, and other variations on it exist, for example:

int functionC(int i) {
  if (i>=minVal) return maxVote;
  else {
    int difference=minVal-i;
    if(difference>maxVote) return 0;
    else return maxVote-difference;
  }
}
int functionD(int i) {
  int difference;
  if (i>=minVal && i<=maxVal) return maxVote;
  else if(i<minVal) difference=minVal-i;
  else difference=i-maxVal;
  if (difference>maxVote) return 0;
  else return maxVote-difference;  
}

functionC is a "fuzzy" threshold (a maximum number of votes are cast if the input exceeds the threshold, but allowances are made for inputs just below it), and functionD is a trapezoid with two thresholds. More complex functions can occur, but there is rarely much point in going to the trouble of complex floating-point equations like Gaussians. Functions can of course overlap each other, so a particular input value might get 30 votes for one action and 20 for another, but it would help if there were no possible inputs that result in no votes for anything.

Sometimes functions of more than one input will be needed, with rules of the form "input 1 is in this region and input 2 is in that region". To do this as a single fuzzy function would be complex; instead, fuzzy functions could be written for each input, and their results combined, like someone saying "I'll vote for this if both my advisors say I should". Fuzzy logic usually accomplishes this by taking the minimum of the "advisors'" recommended votes, thus:

int someFunc(int i1,int i2) {
  int votes1=advice1(i1), votes2=advice2(i2);
  return MIN(votes1,votes2);
}

The AND logic can be changed to OR logic by taking the maximum instead of the minimum. This can be seen as a generalisation of single-bit Boolean logic (where AND is minimum and OR is maximum) to votes.

Negative votes are rarely used, since "prefer not to do action X" can be re-written as "prefer to do anything but action X". For this and other reasons, you may need functions that can distribute their votes across several actions; this can be achieved by keeping all the votes in an array and letting the functions change it.

If the application simply tells the user what category the inputs match, it may be useful to list a number of them with an indication of how many votes were given to each. If the application is supposed to be slightly non-deterministic, this can be achieved by giving out a small number of random votes.

Continuous outputs are also possible. Suppose that the "actions" in the above examples are not completely different, for example:

void action1() { set_value(20); }
void action2() { set_value(35); }
void action3() { set_value(50); }

In this case, it might be sensible to set the value to something in between the given points, depending on how many votes were cast for each one. For example, to take the arithmetic mean:

int chooseValue(int n,int* values,int* votes) {
  int sum=0,totalVotes=0,i;
  for(i=0; i<n; i++) {
    sum+=values[i]*votes[i];
    totalVotes+=votes[i];
  }
  return sum/totalVotes;
}

This explains why negative votes are avoided - strange things can happen if the above has to deal with them. The type of integer used should be sufficiently large to prevent overflow; implementing a running mean instead will be subject to rounding error.

Another function that is sometimes used adds extra weight to the first few votes a value gets, so the more votes it gets, the less each one counts (by a simple ramp function). This can be thought of as building a triangle around the value and cutting it off at the height of the number of votes; its effect is to reduce the dominance of values that tend to be voted for a lot, which may or may not be desirable.

Another method, Product-Max, is to draw appropriately-sized triangular distributions around the values voted for and take the centroid of the resulting shape, where overlaps are combined with OR rather than added. How this can be implemented in an embeddable way is left as an exercise to the reader!

The examples in this article are small, and can easily be done without fuzzy logic. Fuzzy logic comes into its own when you have perhaps hundreds of rules and have to find a compromise between all of them. As well as control and classification systems, it could conceivably be used in optimising algorithms for compromising between different optimisations, typesetting and layout algorithms for compromising between different constraints, and so on.

Fuzzy logic is probably not good enough for safety-critical systems. The rules are designed intuitively, but intuition can break down in more unusual cases. The Japanese concert hall had this problem - apparently, giving a certain input from a certain configuration causes the whole hall to be rapidly plunged into darkness, and this can trap the unwary (as it did several times during their 1998 concert). At least it wasn't a nuclear reactor cooling system.

Notes: 

More fields may be available via dynamicdata ..