any fuzzy real example in C around ? - Page 1
Forum section: electronics / general

author: legacy
author_rank: Super Contributor
timestamp: October 14, 2013, 05:56:00 pm
content: hi guysi am trying to learn something about fuzzy logic, but unfortunately i can't find any example of real implementation in C about the fuzzy controller.could you suggest me something ?thanks

author: npnlamp
author_rank: Contributor
timestamp: October 14, 2013, 07:05:53 pm
content: Maybe will help.http://www.chebucto.ns.ca/Science/AIMET/archive/ddj/fuzzy_logic_in_C/

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 07:14:53 pm
content: Brubaker, David I. Introduction to Fuzzy Logic Systems. Menlo Park, CA: The Huntington Group, 1991.Kosko, Bart. Neural Networks and Fuzzy Systems. Englewood Cliffs., NJ: Prentice-Hall, 1990.Self, Kevin. "Designing with Fuzzy Logic." IEEE Spectrum (November, 1990).Sibigtroth, James M. "Creating Fuzzy Micros." Embedded Systems Programming (December, 1991).Sibigtroth, James M. "Implementing Fuzzy Expert Rules." AI Expert (April, 1992).Williams, Tom. "Fuzzy Logic is Anything but Fuzzy." Computer Design (April, 1992).

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 07:16:07 pm
content: See Microchip App Noes re: Fuzzy Logic --double pendulumAlso see:http://ww1.microchip.com/downloads/en/AppNotes/00600b.pdf

author: legacy
author_rank: Super Contributor
timestamp: October 14, 2013, 07:40:56 pm
content: Thanks, but any C code around ?

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 08:07:23 pm
content: /* General-purpose fuzzy inference engine supporting any number of systeminputs and outputs, membership functions, and rules. Membership functions canbe any shape defineable by 2 points and 2 slopes--trapezoids, triangles,rectanlges, etc. Rules can have any number of antecedents and outputs, and canvary from rule to rule. "Min" method is used to compute rule strength, "Max"for applying rule strengths, "Center-of-Gravity" for defuzzification. Thisimplementation of Inverted Pendulum control problem has: System Inputs, 2(pendulum angle and velocity); System Outputs, 1 (force supplied to base ofpendulum); Membership Functions, 7 per system input/output; Rules, 15 (eachwith 2 antecedents & 1 output). If more precision is required, integers canbe changed to real numbers.*/#include <stdio.h>#define MAXNAME 10 /* max number of characters in names */#define UPPER_LIMIT 255 /* max number assigned as degree of membership */void PID();/* io_type structure builds a list of system inputs and a list of systemoutputs. After initialization, these lists are fixed, except for value fieldwhich is updated on every inference pass. */struct io_type{char name; /* name of system input/output */int value; /* value of system input/output */struct mf_type /* list of membership functions for */*membership_functions; /* this system input/output */struct io_type *next; /* pointer to next input/output */};/* Membership functions are associated with each system input and output. */struct mf_type{char name; /* name of membership function (fuzzy set) */int value; /* degree of membership or output strength */int point1; /* leftmost x-axis point of mem. function */int point2; /* rightmost x-axis point of mem. function */int slope1; /* slope of left side of membership function */int slope2; /* slope of right side of membership function */struct mf_type *next; /* pointer to next membership function */};/* Each rule has an if side and a then side. Elements making up if side arepointers to antecedent values inside mf_type structure. Elements making up thenside of rule are pointers to output strength values, also inside mf_typestructure. Each rule structure contains a pointer to next rule in rule base. */struct rule_element_type{int *value; /* pointer to antecedent/output strength value */struct rule_element_type *next; /* next antecedent/output element in rule */};struct rule_type{struct rule_element_type *if_side; /* list of antecedents in rule */struct rule_element_type *then_side; /* list of outputs in rule */struct rule_type *next; /* next rule in rule base */};struct rule_type *Rule_Base; /* list of all rules in rule base */main(){initialize_system();while(1){get_system_inputs();fuzzification();rule_evaluation();defuzzification();put_system_outputs();}}/* Fuzzification--Degree of membership value is calculated for each membershipfunction of each system input. Values correspond to antecedents in rules. */fuzzification(){struct io_type *si; /* system input pointer */struct mf_type *mf; /* membership function pointer */for(si=System_Inputs; si != NULL; si=si->next)for(mf=si->membership_functions; mf != NULL; mf=mf->next)compute_degree_of_membership(mf,si->value);}/* Rule Evaluation--Each rule consists of a list of pointers to antecedents(if side), list of pointers to outputs (then side), and pointer to next rulein rule base. When a rule is evaluated, its antecedents are ANDed together,using a minimum function, to form strength of rule. Then strength is appliedto each of listed rule outputs. If an output has already been assigned a rulestrength, during current inference pass, a maximum function is used todetermine which strength should apply. */rule_evaluation(){struct rule_type *rule;struct rule_element_type *ip; /* pointer of antecedents (if-parts) */struct rule_element_type *tp; /* pointer to consequences (then-parts) */int strength; /* strength of rule currently being evaluated */for(rule=Rule_Base; rule != NULL; rule=rule->next){strength = UPPER_LIMIT; /* max rule strength allowed *//* process if-side of rule to determine strength */for(ip=rule->if_side; ip != NULL; ip=ip->next)strength = min(strength,*(ip->value));/* process then-side of rule to apply strength */for(tp=rule->then_side; tp != NULL; tp=tp->next)*(tp->value) = max(strength,*(tp->value));}}/* Defuzzification */defuzzification(){struct io_type *so; /* system output pointer */struct mf_type *mf; /* output membership function pointer */int sum_of_products; /* sum of products of area & centroid */int sum_of_areas; /* sum of shortend trapezoid area */int area;int centroid;/* compute a defuzzified value for each system output */for(so=System_Outputs; so != NULL; so=so->next){sum_of_products = 0;sum_of_areas = 0;for(mf=so->membership_functions; mf != NULL; mf=mf->next){area = compute_area_of_trapezoid(mf);centroid = mf->point1 + (mf->point2 - mf->point1)/2;sum_of_products += area * centroid;sum_of_areas += area;}so->value = sum_of_products/sum_of_areas; /* weighted average */}}/* Compute Degree of Membership--Degree to which input is a member of mf iscalculated as follows: 1. Compute delta terms to determine if input is insideor outside membership function. 2. If outside, then degree of membership is 0.Otherwise, smaller of delta_1 * slope1 and delta_2 * slope2 applies.3. Enforce upper limit. */compute_degree_of_membership(mf,input)struct mf_type *mf;int input;{int delta_1;int delta_2;delta_1 = input - mf->point1;delta_2 = mf->point2 - input;if ((delta_1 <= 0) || (delta_2 <= 0)) /* input outside mem. function ? */mf->value = 0; /* then degree of membership is 0 */elsemf->value = min( (mf->slope1*delta_1),(mf->slope2*delta_2) );mf->value = min(mf->value,UPPER_LIMIT); /* enforce upper limit */}/* Compute Area of Trapezoid--Each inference pass produces a new set of outputstrengths which affect the areas of trapezoidal membership functions used incenter-of-gravity defuzzification. Area values must be recalculated with eachpass. Area of trapezoid is h*(a+b)/2 where h=height=output_strength=mf->valueb=base=mf->point2-mf->point1 a=top= must be derived from h,b, and slopes1&2 */compute_area_of_trapezoid(mf)struct mf_type *mf;{int run_1;int run_2;int base;int top;int area;base = mf->point2 - mf->point1;run_1 = mf->value/mf->slope1;run_2 = mf->value/mf->slope2;top = base - run_1 - run_2;area = mf->value * ( base + top)/2;return(area);}//PID code approximates fuzzy control#include <pic.h>#include <pic16f684.h>#include <math.h>#include <stdlib.h>void Init();void PID();void Set_Constants();bit flag1,do_PID,int_flag;signed char en0, en1, en2, en3, term1_char, term2_char, off_set;unsigned char temp;short int temp_int;unsigned short int ki, kd, kp;signed int SumE_Min, SumE_Max, SumE, integral_term, derivative_term, un;signed long Cn;// __CONFIG _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_ON & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _FCMEN_ON//***************************************************************************// Positional PID 256 Hz//***************************************************************************//***************************************************************************//Main() - Main Routine//***************************************************************************void main(){Init(); //Initialize 12F629 MicrocontrollerSet_Constants(); //Get PID coefficients ki, kp and kdwhile(1) //Loop Forever{if(do_PID){PID();}}}//***************************************************************************//Init - Initialization Routine//***************************************************************************void Init(){PORTA = 0;TRISA = 0b00101101; // Set RA4 and RA2 as outputsPORTC = 0;TRISC = 0b00000011; // Set RC0 and RC1 as inputs, rest outputsCMCON0 = 0x07; // Disable the comparatorIRCF0 = 1; // Used to set intrc speed to 8 MHzIRCF1 = 1; // Used to set intrc speed to 8 MHzIRCF2 = 1; // Used to set intrc speed to 8 MHzCCP1CON = 0b01001100; // Full bridge PWM forwardECCPAS = 0; // Auto_shutdown is disabled for nowPR2 = 0x3F; // Sets PWM Period at 31.2 kHzT2CON = 0; // TMR2 Off with no prescaleCCPR1L = 0; // Sets Duty Cycle to zeroTMR2ON = 1; // Start Timer2ANSEL = 0b00110101; // Configure AN0,AN2,AN4 and AN5 as analogVCFG = 0; // Use Vdd as RefADFM = 1; // Right justified A/D resultADCS0 = 1; // 16 TOSC prescaleADCS1 = 0;ADCS2 = 1;CHS0 = 0; // Channel select AN0CHS1 = 0;CHS2 = 0;ADON = 1; //Turn A/D onen0 = en1 = en2 = en3 = term1_char = term2_char =0;ki = kd = 0;kp = off_set = 0;temp_int = integral_term = derivative_term = un =0;SumE_Max = 30000;SumE_Min = 1 - SumE_Max;do_PID = 1; // Allowed to do PID functionT0CS = 0; // Timer0 as timer not a counterTMR0 = 10; // Preload valuePSA = 0; // Prescaler to Timer0PS0 = 0; // Prescale to 32 => 256 HzPS1 = 0;PS2 = 1;INTCON = 0;PIE1 = 0;T0IE = 1; // Enable Timer0 intGIE = 1;return;}void PID() // The from of the PID is C(n) = K(E(n) + (Ts/Ti)SumE + (Td/Ts)[E(n) - E(n-1)]){integral_term = derivative_term = 0;// Calculate the integral termSumE = SumE + en0; // SumE is the summation of the error termsif(SumE > SumE_Max){ // Test if the summation is too bigSumE = SumE_Max;}if(SumE < SumE_Min){ // Test if the summation is too smallSumE = SumE_Min;} // Integral term is (Ts/Ti)*SumE where Ti is Kp/Ki// and Ts is the sampling period// Actual equation used to calculate the integral term is// Ki*SumE/(Kp*Fs*X) where X is an unknown scaling factor// and Fs is the sampling frequencyintegral_term = SumE / 256; // Divide by the sampling frequencyintegral_term = integral_term * ki; // Multiply Kiintegral_term = integral_term / 16; // combination of scaling factor and Kp// Calculate the derivative termderivative_term = en0 - en3;if(derivative_term > 120){ // Test if too largederivative_term = 120;}if(derivative_term < -120){ // test if too smallderivative_term = -120;} // Calculate derivative term using (Td/Ts)[E(n) - E(n-1)]// Where Td is Kd/Kp// Actual equation used is Kd(en0-en3)/(Kp*X*3*Ts)derivative_term = derivative_term * kd; // Where X is an unknown scaling factorderivative_term = derivative_term >> 5; // divide by 32 precalculated Kp*X*3*Tsif(derivative_term > 120){derivative_term = 120;}if(derivative_term < -120){derivative_term = -120;}// C(n) = K(E(n) + (Ts/Ti)SumE + (Td/Ts)[E(n) - E(n-1)])Cn = en0 + integral_term + derivative_term; // Sum the termsCn = Cn * kp / 1024; // multiply by Kp then scaleif(Cn >= 1000) // Used to limit duty cycle not to have punch through{Cn = 1000;}if(Cn <= -1000){Cn = -1000;}if(Cn == 0){ // Set the speed of the PWMDC1B1 = DC1B1 = 0;CCPR1L = 0;}if(Cn > 0){ // Motor should go forward and set the duty cycle to CnP1M1 = 0; // Motor is going forwardtemp = Cn;if(temp^0b00000001){DC1B0 = 1;}else{DC1B0 = 0;}if(temp^0b00000010){DC1B1 = 1;}else{DC1B1 = 0;}CCPR1L = Cn >> 2; // Used to stop the pendulum from continually going around in a circleoff_set = off_set +1; // the offset is use to adjust the angle of the pendulum to slightlyif(off_set > 55){ // larger than it actually isoff_set = 55;}}else { // Motor should go backwards and set the duty cycle to CnP1M1 = 1; // Motor is going backwardstemp_int = abs(Cn); // Returns the absolute int value of Cntemp = temp_int; // int to char of LS-Byteif(temp^0b00000001){DC1B0 = 1;}else{DC1B0 = 0;}if(temp^0b00000010){DC1B1 = 1;}else{DC1B1 = 0;}CCPR1L = temp_int >> 2; // Used to stop the pendulum from continually going around in a circleoff_set = off_set -1;if(off_set < -55){off_set = -55;}}en3 = en2; // Shift error signalsen2 = en1;en1 = en0;en0 = 0;do_PID = 0; // DoneRA4 = 0; // Test flag to measure the speed of the loopreturn;}void Set_Constants(){ANS2 = 1; // Configure AN2 as analogANS4 = 1; // Configure AN4 as analogANS5 = 1; // Configure AN5 as analogADFM = 1; // Right justified A/D resultCHS0 = 0; // Channel select AN4CHS1 = 0;CHS2 = 1;temp = 200; // Gives delaywhile(temp){temp--;}GODONE = 1;while(GODONE);{temp = 0; // Does nothing.....}ki = ADRESH << 8; // Store the A/D result to Integral Constantki = ki + ADRESL;CHS0 = 1; // Channel select AN5CHS1 = 0;CHS2 = 1;temp = 200; // Gives delaywhile(temp){temp--;}GODONE = 1;while(GODONE);{temp = 0; // Does nothing.....}kd = ADRESH << 8; // Store the A/D result to Differential Constantkd = kd + ADRESL;CHS0 = 0; // Channel select AN2CHS1 = 1;CHS2 = 0;temp = 200; // Gives delaywhile(temp){temp--;}GODONE = 1;while(GODONE);{temp = 0; // Does nothing.....}kp = ADRESH << 8; // Store the A/D result to Proportional Constantkp = kp + ADRESL;CHS0 = 0; // Channel select AN0CHS1 = 0;CHS2 = 0;}void interrupt Isr(){if(T0IF&&T0IE){TMR0 = 10; // Preload valueT0IF = 0; // Clear Int Flag// flag1 = (!flag1);RA4 = 1;temp_int = 0;temp_int = ADRESH << 8; // Store the A/D result with offsettemp_int = temp_int + ADRESL - 512;en0 = temp_int + off_set/8; // Store to error function asuming no over-flowdo_PID = 1; // Allowed to do PID functionGODONE = 1; // Start next A/D cycle}else{PIR1 = 0;RAIF = 0;INTF = 0;}if(temp_int > 180){ //Check if error is too large (positive)DC1B0 = DC1B1 = 0; // Stop PWMCCPR1L = 0;en0 = en1 = en2 = en3 = term1_char = term2_char = off_set = 0; // Clear all PID constantsCn = integral_term = derivative_term = SumE = RA4 = 0;do_PID = 0; // Stop doing PID}if(temp_int < -180){ //Check if error is too large (negative)DC1B0 = DC1B1 = 0; // Stop PWMCCPR1L = 0;en0 = en1 = en2 = en3 = term1_char = term2_char = off_set = 0; // Clear all PID constantsCn = integral_term = derivative_term = SumE = RA4 = 0;do_PID = 0; // Stop doing PID}}

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 09:03:09 pm
content: /*C++ Fuzzy Logic API + Simple DSLCLinguisticVariable is the class used for representing the linguistic variables. There are three class variables. variableName is used for defining the linguistic variable name and should be unique, because we're using a hash map for storing CLinguisticVariable, so we can find specific linguistic variables in time O(1). The next variable, b_output declares if a linguistic variable is output or not. Please note, there can be only one output variable in the FuzzyLogic API. The last variable, h_linguisticValuesHashMap is used for storing linguistic values. One linguistic variable can have one or more linguistic values. There are several class methods. AddLinguisticValue adds LinguisticValue to the selected CLinguisticVariable. In the next image, you can see four linguistic variables: Distance, Approaching, Speed, and Signal.The next method adds the linguistic value to a hash_map.*///Method add Linguistic value to hash mapvoid AddLinguisticValue(LinguisticValue* p_linguisticValue){h_linguisticValuesHashMap.insert(LinguisticValue_Pairs(p_linguisticValue->ToString(), p_linguisticValue));}//where LinguisticValue_Pairs is a typedef declared in://Typedef for linguistic values hash map.typedef pair <string, LinguisticValue*> LinguisticValue_Pairs;*/The method ResetLinguisticValues just resets all linguistic values to -1. A more interesting method is FindLinguisticValueByName. The input parameter of the method is the linguistic value name and the return value is a pointer to the object of the LinguisticValue. Because we are using a hash map, the time complexity is O(1).*/LinguisticValue* FindLinguisticValueByName(string name){//Define iteratorhash_map <string, LinguisticValue*> :: const_iterator iterator;//Fint linguistic value by nameiterator = h_linguisticValuesHashMap.find(name);if(iterator == h_linguisticValuesHashMap.end()){//SASO, this should never happends!!!!!assert(NULL);return NULL;}//Return LinguisticValuereturn (LinguisticValue*)iterator->second;}/* CalculateLinguisticValueByName is just a bridge between CFuzzyReasoner and LinguisticValue for calculating the linguistic value. A little bit more complicated is UpdateLinguisticValueByName. At first we have to find LinguisticValue by name. If there is a value stored already, we will perform the fuzzy operation OR, else we will just store newVal. Let's see the code:*///Update Linguistic value by namevoid UpdateLinguisticValueByName(string name, double newVal){//Find LinguisticValueLinguisticValue* value = FindLinguisticValueByName(name);//If there is value, we should perform operator ORif(value->GetLinguisticValue() != -1)value->SetLinguisticValue(CFuzzyCalculator::OR(value->GetLinguisticValue(), newVal));elsevalue->SetLinguisticValue(newVal); //There is no value, just set newVal}/*LinguisticValueThe class LinguisticValue is used for storing linguistic values. Variables A, B, C, and D are "borders" of the trapezium (trapezoid). For example, the linguistic variable Distance has three linguistic values (Low, Average, and Height) and for the linguistic value "Low", the variables A, B, C, and D would be A = 0, B = 0, C = 1, D = 2. Every LinguisticValue has a unique name (like in CLinguisticVariable). The variable linguisticValue is used for storing a numeric value. The default value is -1. This value means, how much input value belongs to this LinguisticValue trapezium. For the linguistic value Average (linguistic variable Speed, input: 0 (km/h)), this value would be equal to 0.5 (see image above). There is only one method (except the constructor, getters, and setters) called CalculateLinguisticValue. We have to take care of the correctness of the inputs, so if inputs are out of range, we should normalize them. Then we need to calculate the trapezoidal function. The result of the trapezoidal function is the linguistic value for a specific variable.*/double CalculateLinguisticValue(double input){//Normalize variablesif(input < A)input = A;else if(input > D)input = D;//Calculating Trapezoid functionif ((input <= A)|| (input > D ))return 0;else if ((A < input) && (input < B))return (input - A) / (B - A);else if ((B <= input) && (input <= C))return 1;elsereturn (D - input) / (D - C);}/*Probably the simplest class in the project. There are only two static methods. The method AND implements the operator AND, which is equal to returning the minimal value.*///Operator ANDstatic double AND(double a, double b){if(a < b)return a;return b;}/* and method OR implements operator OR, returning the maximal value.*///Operator ORstatic double OR(double a, double b){if(a > b)return a;return b;}/*CFuzzyRuleFuzzy Logic consists of linguistic variables and fuzzy rules. This class is used for storing a fuzzy rule. A fuzzy rule consists of objects of the class CFuzzyToken. The only functionality of the class is adding CFuzzyRuleToken to a rule. For example, CFuzzyRule could be:*/"IF NOT SPEED = SLOW AND DISTANCE = CLOSE, SIGNAL = BRAKE"/* Every fuzzy rule should have an output variable!CFuzzyRuleTokenCFuzzyRuleToken is just one part of a CFuzzyRule. Let's describe all variables. operation describes what kind of operation is between the previous and current CFuzzyRuleToken. Supported operators are OR, AND, and EMPTY. EMPTY means there isn't any operator ("VOID"). The EMPTY token is just used in the first and last tokens in the rule. Also tokens can be negated (variable b_negation). Every CFuzzyToken has a pointer to CLinguisticVariable and the name of the linguistic value. Let's see the CFuzzyRule example a little bit closer."IF NOT SPEED = SLOW AND DISTANCE = CLOSE, SIGNAL = BRAKE"What are tokens? There are three token examples:Token_1operation = EMPTYb_Negate = truep_linguisticVariable= SPEEDlinguisticValueName = "SLOW"Token_2 operation = ANDb_Negate = falsep_linguisticVariable= DISTANCElinguisticValueName = "CLOSE"Token_3operation =EMPTYb_Negate = falsep_linguisticVariable= SIGNALlinguisticValueName = BRAKE"Please note, TOKEN_3 is the output token! Every CFuzzyRule must have a token with an output variable!!!The method CalculateTokenOutputValue is used for getting an input value from the hash map h_fuzzyInputHashMap and calling a method for calculating the linguistic value. The input variable h_fuzzyInputHashMap is a hash_map filled with objects (class CFuzzyInput). In CFuzzyInput is stored input values for specific linguistic variables. CFuzzyInput will be explained later.Collapse | Copy Code*///Calculate token valuedouble CalculateTokenOutputValue(hash_map <string, CFuzzyInput*> h_fuzzyInputHashMap){hash_map <string,> :: const_iterator iterator;//Find linguistic variableiterator = h_fuzzyInputHashMap.find(p_linguisticVariable->ToString());CFuzzyInput* temp = (CFuzzyInput*)iterator->second;double input = temp->GetInputValue();//Calculate linguistic valuereturn p_linguisticVariable->CalculateLinguisticValueByName(linguisticValueName, input);}/*CFuzzyInputCFuzzyInput has only two variables, variableName for the linguistic variable name and inputValue (type double) for the value. For example, CFuzzyInput could be variableName = "SPEED" and inputValue = "43" (km/h).CFuzzyReasonerCFuzzyReasoner is the heart of the FuzzyLogic system. It's used for calculating fuzzy rule output values and the final defuzzyfication. The CFuzzyReasoner variable v_fuzzyRulesVector is used for storing fuzzy rules (CFuzzyRule). Let's see the most important method in FuzzyLogic, FuzzyRuleReasoner. The method takes as inputs a fuzzy rule and a hash map filled with fuzzy inputs. Every fuzzy rule token is checked if it is an output variable or not. If not, output variables are calculated linguistic values of the current token variable. Then we check if the token is negated or not. If the linguistic variable is not first in the fuzzy rule and it's not an output variable then we should have an operator different than EMPTY. Only the first variable in the fuzzy rule must have the operator EMPTY (for the output value, operator isn't important). For the output value we just set a new value (resetVal) and return a pointer to the output token.*///Start fuzzy rule reasonerCFuzzyRuleToken* FuzzyRuleReasoner(CFuzzyRule* fuzzyRule,hash_map <string, CFuzzyInput*> h_fuzzyInputs){double resultVal = 0;for(unsigned int i = 0; i < fuzzyRule->GetFuzzyRuleTokens().size(); i++){//Get fuzzy rule tokenCFuzzyRuleToken* token = fuzzyRule->GetFuzzyRuleTokens();if(token->IsOutput()){//Update output objecttoken->UpdateTokenValue(resultVal);//Return result tokenreturn token;}else{double tokenVal = token->CalculateTokenOutputValue(h_fuzzyInputs);token->UpdateTokenValue(tokenVal);if(token->IsNegated())tokenVal = 1 - tokenVal; //Negate valueif(i == 0)resultVal = tokenVal; //Set valueelse if(token->IsOrOperator())resultVal = CFuzzyCalculator::OR(resultVal, tokenVal); //OR operatorelse if(token->IsAndOperator())resultVal = CFuzzyCalculator::AND(resultVal, tokenVal); //AND operator}}//This won't happends sasoassert(NULL);return NULL;}// The following method just calls reasoning for every fuzzy rule in the FuzzyLogic API.//Start reasoner for fuzzy rullesCFuzzyRuleToken* CalculateFuzzyRules(hash_map <string, CFuzzyInput*> h_fuzzyInputs){//Reset all valuesCFuzzyRuleToken* outputObject;//Calculate all fuzzy rulesfor(unsigned int i = 0; i < v_fuzzyRulesVector.size(); i++){//Glede na izhodno vrednost izhodne spremeljivke naredi update izhodnega objektaoutputObject = FuzzyRuleReasoner((CFuzzyRule*)v_fuzzyRulesVector, h_fuzzyInputs);}//Return output objectreturn outputObject;}The last step in Fuzzy Logic reasoning is Defuzzyfication. It's implemented in the next two methods.Collapse | Copy Code//Defuzzyficationdouble Defuzzy(CFuzzyRuleToken *outputToken){//For every output valueCLinguisticVariable* lVar = outputToken->GetLinguisticVariable();vector<LinguisticValue*> valuesList = lVar->GetLinguisticValuesList();double upEqualation = 0;double downEqualation = 0;//Calculating defuzzy valuefor(unsigned int i = 0; i < valuesList.size(); i++){LinguisticValue* val = valuesList.at(i);upEqualation += val->GetLinguisticValue()* CalculateTrapezoidBalance(val->GetA(), val->GetB(), val->GetC(), val->GetD());downEqualation += val->GetLinguisticValue();}//Return output value of systemif(downEqualation == 0)return 0;return upEqualation / downEqualation;}//Calculating surface of trapezoiddouble CalculateTrapezoidBalance(double A, double B, double C, double D){return ((1 / (B - A)) * (2 * pow(B,3) - 3 * A * pow(B,2) + pow(A,3)) +3 * (pow(C,2) - pow(B,2)) + (1 / (D-C)) * (2 * pow(C,3) - 3 * D * pow(C,2) + pow(D,3)))/ (3 * (B - A) + 6 * (C - B) + 3 * (D - C));}

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 09:03:36 pm
content: /*How to use it?Probably you are wondering how to use this FuzzyLogic API. It's not so complicated. For making your life easier, I have made three simple examples. The first one is for a Fuzzy Cruise Control, the second for a basketball player, and the last one for a ski jumper. All examples are in the class called CExperiments. Let's see the simple basketball player example. We create three linguistic variables, then we add linguistic values to the linguistic variables. With the linguistic variables, we create two rules and add the rules to FuzzyLogic.*/void BuildBasketballPlayersRules(){//Method for building necessary rules for Basketball playersCLinguisticVariable *height = new CLinguisticVariable(false,"Height");CLinguisticVariable *age = new CLinguisticVariable(false,"Age");CLinguisticVariable *basketball_player =new CLinguisticVariable(true,"Basketball_player");//Add linguistic values to variableheight->AddLinguisticValue(new LinguisticValue("Low_height",150,150,170,180));height->AddLinguisticValue(new LinguisticValue("Average_height",170,180,185,190));height->AddLinguisticValue(new LinguisticValue("Tall",185,195,210,210));age->AddLinguisticValue(new LinguisticValue("Young",10,10,25,30));age->AddLinguisticValue(new LinguisticValue("Average_young",25,35,40,45));age->AddLinguisticValue(new LinguisticValue("Old",50,60,80,80));age->AddLinguisticValue(new LinguisticValue("Average_old",40,45,50,55));basketball_player->AddLinguisticValue(new LinguisticValue("Suitable",0.5,0.6,1,1));basketball_player->AddLinguisticValue(new LinguisticValue("Unsuitable ",0,0,0.4,0.5));//Rule1//IF age = Young AND height = Tall THEN basketball_player = "Suitable"CFuzzyRule* rule1 = new CFuzzyRule();rule1->AddTokenToRule(new CFuzzyRuleToken(false,EMPTY, age,"Young"));rule1->AddTokenToRule(new CFuzzyRuleToken(false,AND, height,"Tall"));rule1->AddTokenToRule(new CFuzzyRuleToken(false,EMPTY, basketball_player,"Suitable"));//Rule2//IF age = "Old" THEN basketball_player = "Unsuitable"CFuzzyRule* rule2 = new CFuzzyRule();rule2->AddTokenToRule(new CFuzzyRuleToken(false,EMPTY, age,"Old"));rule2->AddTokenToRule(new CFuzzyRuleToken(false,EMPTY,basketball_player,"Unsuitable "));//Add rulesfr->AddFuzzyRule(rule1);fr->AddFuzzyRule(rule2);//Add linguistic variables, if you want to obtain//more informations about fuzzy calculationsAddLinguisticVariables(height);AddLinguisticVariables(age);AddLinguisticVariables(basketball_player);}/*How to execute the exampleWith the next sample you should understand how to use the class CExperiment.*/int _tmain(int argc, _TCHAR* argv[]){//Create instance of CExperiments.CExperiments* experiment = new CExperiments();//Create rulesexperiment->BuildCruiseControlRules();//Hash_map for storing inputshash_map <string, CFuzzyInput*> h_fuzzyInputs;//Put some values to inputsCFuzzyInput* inputRazdalja = new CFuzzyInput("Distance", 1.;CFuzzyInput* inputPriblizevanje = new CFuzzyInput("Approaching", 15);CFuzzyInput* inputHitrost = new CFuzzyInput("Speed", -8);//Insert inputs to the hash_maph_fuzzyInputs.insert(CFuzzyInput_Pairs(inputRazdalja->GetVariableName(), inputRazdalja));h_fuzzyInputs.insert(CFuzzyInput_Pairs(inputPriblizevanje->GetVariableName(), inputPriblizevanje));h_fuzzyInputs.insert(CFuzzyInput_Pairs(inputHitrost->GetVariableName(), inputHitrost));//Calculate fuzzy Logic output signaldouble outputSignal = experiment->CalculateFuzzyRules(h_fuzzyInputs);//Get some additional informations from fuzzy logicdouble t = experiment->GetC_ByName("Distance","Average");double v1 = experiment->GetLinguisticVariableValue("Signal","Brake");double v2 = experiment->GetLinguisticVariableValue("Signal","Maintain");double v3 = experiment->GetLinguisticVariableValue("Signal","Accelerate");double v4 = experiment->GetLinguisticVariableValue("Distance","Low");double v5 = experiment->GetLinguisticVariableValue("Distance","Average");double v6 = experiment->GetLinguisticVariableValue("Distance","High");double v7 = experiment->GetLinguisticVariableValue("Approaching","Slow");double v8 = experiment->GetLinguisticVariableValue("Approaching","Average");double v9 = experiment->GetLinguisticVariableValue("Approaching","Fast");double v10 = experiment->GetLinguisticVariableValue("Speed","Slow");double v11 = experiment->GetLinguisticVariableValue("Speed","Acceptable");double v12 = experiment->GetLinguisticVariableValue("Speed","Fast");//YOU HAVE TO RESET TOKEN VALUES BEFORE NEW CALCULATIONS!!!experiment->ResetTokenValues();delete experiment;return 0;}/*Linguistic_Variable_Name Input/Output ValueName_0 (A,B,C,D) ValueName_N (A,B,C,D)and rules:*/IF Linguistic_Variable_Name = Linguistic_Value_Name AND ...AND Linguistic_Variable_Name NOT Linguistic_Value_Name THENLinguistic_Variable_Name = Linguistic_Value_Namevoid Parse(char* filePath){ifstream ifs(filePath);string line;while( getline( ifs, line ) ){vector<string> tokens = SplitBy(line,' ');//Skip lines without textif(tokens.size() > 0){//Skip commentsif(!IsComment(tokens)){if(IsRule(tokens))ParseFuzzyRule(tokens);elseParseFuzzyAtribute(tokens);}}}//Close streamifs.close();}bool IsRule(string token){//Return true if is ruleif(token == "IF")return true;return false;}/*How do we parse rules and attributes? Check the next two simple methods. ParseFuzzyRule just goes over all tokens (we don't need to process the first token, its should be "IF") and check if it is an operator token (AND / OR) and set the appropriate operation. Then we check if there is negation or we are on the "set" (token "="). If this condition is true, we just have to set the previous and next token, create a new CFuzzyRuleToken, and add it to the rule.*/void ParseFuzzyRule(vector<string> ruleTokens){//Rule example//IF distance = low AND approaching NOT slow THEN signal=breake//SKIP IF tokenbool negated = false;string leftSide;string rightSide;Operation operation = EMPTY;CFuzzyRule* rule = new CFuzzyRule();for(unsigned int i = 1; i < ruleTokens.size(); i++){//Check for operator//OPERATORS =, Operator(AND, OR), NOT, THENif((ruleTokens== "AND") || (ruleTokens== "OR")){if(ruleTokens== "AND")operation = AND;elseoperation = OR;}else if((ruleTokens== "=") || (ruleTokens== "NOT")){leftSide = ruleTokens[i - 1];//Next token is right sideif(ruleTokens== "NOT")negated = true;rightSide = ruleTokens[++i];//ADD TOKEN TO RULECLinguisticVariable* linVar =fuzzyInterface->FindLinguisticVariableByName(leftSide);assert(linVar != NULL);rule->AddTokenToRule(new CFuzzyRuleToken(negated,operation,linVar,rightSide));//RESEToperation = EMPTY;negated = false;}}fuzzyInterface->AddFuzzyRule(rule);}/*Now, parsing the attributes. The first token is always the linguistic variable name, the second token should be information of the attribute. There can be N linguistic values. We have to go over all tokens and parsing is Input or Output. With that information, we can create CLinguisticVariable. Then we can start to parse the linguistic values. We have to go over all the remaining tokens. The next token has to be the linguistic value name, followed by the linguistic values (method ParseLinguisticValues). When all linguistic values are parsed, we can add LinguisticVariable to the list (in CExperiment).*/void ParseFuzzyAtribute(vector<string> attTokens){//Distance Input Low (0,0,1,2) Average (1,2,3,4) High (3,4,5,5)//Linguistic variable name//Input or output//Linguistic value name//Values A,B,C,Dstring linguisticVariableName = attTokens.at(0);bool output = true;if(attTokens.at(1) == "Input")output = false;//Creating new linguistic variableCLinguisticVariable *linguisticVariable =new CLinguisticVariable(output,linguisticVariableName);//Adding linguistic values to variablefor(unsigned int i = 2; i < attTokens.size(); i++){string linguisticValueName = attTokens.at(i++);vector<double> linguisticValues = ParseLinguisticValues(attTokens.at(i));//Check for error!assert(linguisticValues.size() == 4);LinguisticValue* linValue = new LinguisticValue(linguisticValueName,linguisticValues,linguisticValues,linguisticValues,linguisticValues);linguisticVariable->AddLinguisticValue(linValue);}fuzzyInterface->AddLinguisticVariables(linguisticVariable);}vector<double> ParseLinguisticValues(string token){vector<double> linguisticValues;//Remove first and last chartoken = token.erase(0,1);token = token.erase(token.size() - 1, 1);vector<string> values = SplitBy(token, ',');//Values size should be 4!for(unsigned int i = 0; i < values.size(); i++)linguisticValues.push_back(strtod(values.at(i).c_str(),NULL));return linguisticValues;}//Input file example%ATTRIBUTESDistance Input Low (0,0,1,2) Average (1,2,3,4) High (3,4,5,5)Approaching Input Slow (0,0,10,20) Average (10,20,30,40) Fast (30,40,50,50)Speed Input Slow (-50,-50,-10,0) Acceptable (-10,0,0,10) Fast (0,10,50,50)Signal Output Brake (-5,-5,-2,-1) Maintain (-2,-1,1,2) Accelerate (1,2,5,5)%RULES/*IF Distance = Low AND Approaching NOT Slow THEN Signal = BrakeIF Distance = Average AND Approaching = Fast THEN Signal = BrakeIF Speed = Fast THEN Signal = BrakeIF Distance NOT Low AND Approaching = Average THEN Signal = MaintainIF Distance = High AND Approaching NOT Fast AND Speed = Acceptable THEN Signal = MaintainIF Distance = Average AND Speed = Slow THEN Signal = MaintainIF Distance = High AND Speed = Slow THEN Signal = Acc*/

author: Paul Price
author_rank: Super Contributor
timestamp: October 14, 2013, 09:21:22 pm
content: Downlload: Microchip app note AN964 --Inverted Double Pendulum Fuzzy logic. Full C-Code/*C CODEWhen the approximation was made for the derivativeterm, it stated that the approximation would be:EQUATION 7:By reviewing the code in Figure 6, one can determinethat the approximation, shown in Equation 7, is not theapproximation used. The actual equation that was usedfor calculating the derivative term is as follows:EQUATION 8:Equation 8 more accurately written would be:EQUATION 9:C(n) = KPE(n) + KITs ??0E(n) + KD[E(n)- E(n-1)]/TSC(n) = K(E(n) + (1/TI) ??0E(n) + TD[E(n)- E(n-1)]/TSORWhere KP = K, KI = K/TI & KD = K TD*///Calculate the differential termderivative_term = en0 - en3;if(derivative_term > 120){derivative_term = 120;}if(derivative_term < -120){derivative_term = -120;}derivative_term = derivative_term * kd;derivative_term =derivative_term>>5;//divide by 32}if(derivative_term > 120){derivative_term = 120;}if(derivative_term> -120){derivative_term = -120;}/*KDdE(t)/dt = TD [E(n)- E(n-1)]/TsWhere TD = KD/KPKDdE(t)/dt = KD [E(n)- E(n-3)]/32KDdE(t) = TD[E(n)- E(n-3)]/(X•3•Ts)=KD[E(n) -E(n-3)]/(KP•X•3•TS)/* The X term allows for a fractionalrepresentation of KD, not just a integer. (Similar scalingfactors are also used when calculating the integral andproportional terms). The 3*TS comes from the fact thatwe are tripling our sampling period by using E(n) – E(n-3) not E(n) – E(n-1). Why use E(n) – E(n-3) instead ofE(n) – E(n-1)? The main reason for doing this is to limitthe variation in the error angle measurement. There willalways be an amount of uncertainty associated with theerror measurement, some of which can be attributed toA/D error, Bessel filter throughput, mechanical vibration,etc. Since the uncertainty of the error measurementswill be the same for all error terms, thisuncertainty can be decreased by effectively tripling thesampling period. The real key is that the derivative termis still updated at 256 Hz rate. Doing so gives the benefitof the slower rate a more accurate derivative term,but at the desired faster sampling rate. The side affectof doing this is adding approximately 4 milliseconds oflag to the derivative term, which in this case is acceptable.KP*X*3*TS has been precalculated to be 32 toincrease the speed of the PID loop.TUNING THE PID CONTROLLERUse the following steps to tune the PID constants:1. Turn the KP, KI and KD potentiometers counterclockwise as far as they will turn. This sets all theconstants to zero.2. Power the device using a 12V (minimum of a 3amp) power supply.3. Holding the Reset button down, lift the pendulumto the vertical position and release theReset button and pendulum at the same time.4. The pendulum should free fall and the base willnot move. This verifies that all constants areproperly read as zeros.5. Increase the KP constant by turning the potentiometercounter clockwise and repeat step 3.6. Keep repeating steps 3-5 until there is a littleoscillation in the base. If the KP term is too small,the base platform will chase the top of the pendulumwhile ? continues to increase. KP will betoo large if the drive wheel breaks free or thebase oscillates at a high rate of speed.7. Start increasing the KI the same way as KP untilthe pendulum can be balanced for several secondsunder a constant oscillating condition.When the KI is added, the base will now acceleratefaster than the pendulum causing ? tochange from a positive angle to a negative angle(or vice versa). The pendulum will begin to fallbackwards. The base should change directionsand, again, accelerate faster than the pendulumuntil ? changes signs and the whole cyclerepeats. This is known as the Overshootcondition.8. Increase KD in the same manner as KP and Kiuntil the Overshoot condition is gone and thependulum remains balanced.9. Once all overshoot is gone, the PID controller istuned.*/

author: David_AVD
author_rank: Super Contributor
timestamp: October 14, 2013, 09:32:24 pm
content: Paul, there is a CODE button (# symbol ) you can use when posting that keeps code in a nice scrolling box.

author: legacy
author_rank: Super Contributor
timestamp: October 15, 2013, 01:14:12 am
content: also looking for general-purpose fuzzy-based inference engine written in C =P