2014-12-19 14:30:46 +01:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
// Code generated by jFuzzyLogic
|
2022-05-23 11:43:42 +02:00
|
|
|
// jFuzzyLogic Version : JFuzzyLogic 4.0 (build 2022-05-12), by Pablo Cingolani
|
|
|
|
// jFuzzyLogic created by Pablo Cingolani
|
2014-12-19 14:30:46 +01:00
|
|
|
//--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
double ruleAccumulationMethod_max(double defuzzifierValue, double valueToAggregate) { return ( defuzzifierValue > valueToAggregate ? defuzzifierValue : valueToAggregate ); }
|
|
|
|
|
|
|
|
double ruleActivationMethod_min(double degreeOfSupport, double membership) { return (degreeOfSupport < membership ? degreeOfSupport : membership); }
|
|
|
|
|
|
|
|
double ruleConnectionMethod_and(double antecedent1, double antecedent2) { return (antecedent1 < antecedent2 ? antecedent1 : antecedent2); }
|
|
|
|
|
|
|
|
double ruleConnectionMethod_or(double antecedent1, double antecedent2) { return (antecedent1 > antecedent2 ? antecedent1 : antecedent2); }
|
|
|
|
|
|
|
|
class FunctionBlock_tipper {
|
|
|
|
|
|
|
|
public:
|
|
|
|
// VAR_INPUT
|
|
|
|
double food;
|
|
|
|
double service;
|
|
|
|
|
|
|
|
// VAR_OUTPUT
|
|
|
|
double tip;
|
|
|
|
|
|
|
|
private:
|
|
|
|
// FUZZIFY food
|
|
|
|
double food_delicious;
|
|
|
|
double food_rancid;
|
|
|
|
|
|
|
|
// FUZZIFY service
|
|
|
|
double service_excellent;
|
|
|
|
double service_good;
|
|
|
|
double service_poor;
|
|
|
|
|
|
|
|
|
|
|
|
// DEFUZZIFY tip
|
|
|
|
double defuzzify_tip[1000];
|
|
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
FunctionBlock_tipper();
|
|
|
|
void calc();
|
|
|
|
void print();
|
|
|
|
|
|
|
|
private:
|
|
|
|
void defuzzify();
|
|
|
|
void fuzzify();
|
|
|
|
void reset();
|
|
|
|
double membership_food_delicious(double x);
|
|
|
|
double membership_food_rancid(double x);
|
|
|
|
double membership_service_excellent(double x);
|
|
|
|
double membership_service_good(double x);
|
|
|
|
double membership_service_poor(double x);
|
|
|
|
double membership_tip_average(double x);
|
|
|
|
double membership_tip_cheap(double x);
|
|
|
|
double membership_tip_generous(double x);
|
|
|
|
void calc_No1();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
// Constructor
|
|
|
|
FunctionBlock_tipper::FunctionBlock_tipper() {
|
|
|
|
tip = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Calculate function block
|
|
|
|
void FunctionBlock_tipper::calc() {
|
|
|
|
reset();
|
|
|
|
fuzzify();
|
|
|
|
calc_No1();
|
|
|
|
defuzzify();
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULEBLOCK No1
|
|
|
|
void FunctionBlock_tipper::calc_No1() {
|
|
|
|
// RULE 1 : IF (service IS poor) OR (food IS rancid) THEN tip IS cheap;
|
|
|
|
double degreeOfSupport_1 = 1.0 * ( ruleConnectionMethod_or(service_poor , food_rancid) );
|
|
|
|
if( degreeOfSupport_1 > 0 ) {
|
|
|
|
for (int i = 0 ; i < 1000 ; i++ ) {
|
|
|
|
double x = 0.0 + i * 0.03;
|
|
|
|
double membership = membership_tip_cheap(x);
|
|
|
|
double y = ruleActivationMethod_min( degreeOfSupport_1 , membership );
|
2022-05-12 11:15:49 +02:00
|
|
|
defuzzify_tip[i] = ruleAccumulationMethod_max( defuzzify_tip[i], y );
|
2014-12-19 14:30:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULE 2 : IF service IS good THEN tip IS average;
|
|
|
|
double degreeOfSupport_2 = 1.0 * ( service_good );
|
|
|
|
if( degreeOfSupport_2 > 0 ) {
|
|
|
|
for (int i = 0 ; i < 1000 ; i++ ) {
|
|
|
|
double x = 0.0 + i * 0.03;
|
|
|
|
double membership = membership_tip_average(x);
|
|
|
|
double y = ruleActivationMethod_min( degreeOfSupport_2 , membership );
|
2022-05-12 11:15:49 +02:00
|
|
|
defuzzify_tip[i] = ruleAccumulationMethod_max( defuzzify_tip[i], y );
|
2014-12-19 14:30:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// RULE 3 : IF (service IS excellent) AND (food IS delicious) THEN tip IS generous;
|
|
|
|
double degreeOfSupport_3 = 1.0 * ( ruleConnectionMethod_and(service_excellent , food_delicious) );
|
|
|
|
if( degreeOfSupport_3 > 0 ) {
|
|
|
|
for (int i = 0 ; i < 1000 ; i++ ) {
|
|
|
|
double x = 0.0 + i * 0.03;
|
|
|
|
double membership = membership_tip_generous(x);
|
|
|
|
double y = ruleActivationMethod_min( degreeOfSupport_3 , membership );
|
2022-05-12 11:15:49 +02:00
|
|
|
defuzzify_tip[i] = ruleAccumulationMethod_max( defuzzify_tip[i], y );
|
2014-12-19 14:30:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// Defuzzify
|
|
|
|
void FunctionBlock_tipper::defuzzify() {
|
|
|
|
double sum_tip = 0.0;
|
|
|
|
double wsum_tip = 0.0;
|
|
|
|
for (int i = 0; i < 1000 ; i++ ) {
|
|
|
|
double x = 0.0 + i * 0.03;
|
|
|
|
sum_tip += defuzzify_tip[i];
|
|
|
|
wsum_tip += x * defuzzify_tip[i];
|
|
|
|
}
|
|
|
|
tip = wsum_tip / sum_tip;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fuzzify all variables
|
|
|
|
void FunctionBlock_tipper::fuzzify() {
|
|
|
|
food_delicious = membership_food_delicious(food);
|
|
|
|
food_rancid = membership_food_rancid(food);
|
|
|
|
service_excellent = membership_service_excellent(service);
|
|
|
|
service_good = membership_service_good(service);
|
|
|
|
service_poor = membership_service_poor(service);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Membership functions
|
|
|
|
double FunctionBlock_tipper::membership_food_delicious(double x) {
|
|
|
|
if ( x <= 7.0 ) return 0.0;
|
|
|
|
if ( x > 9.0 ) return 1.0;
|
|
|
|
if ( x <= 9.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 7.0 ) / ( 9.0 - 7.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_food_rancid(double x) {
|
|
|
|
if ( x <= 0.0 ) return 1.0;
|
|
|
|
if ( x > 3.0 ) return 0.0;
|
|
|
|
if ( x <= 1.0 ) return 1.0 + ( 1.0 - 1.0 ) * ( ( x - 0.0 ) / ( 1.0 - 0.0 ) );
|
|
|
|
if ( x <= 3.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 1.0 ) / ( 3.0 - 1.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_service_excellent(double x) {
|
|
|
|
if ( x <= 6.0 ) return 0.0;
|
|
|
|
if ( x > 9.0 ) return 1.0;
|
|
|
|
if ( x <= 9.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 6.0 ) / ( 9.0 - 6.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_service_good(double x) {
|
|
|
|
if ( x <= 1.0 ) return 0.0;
|
|
|
|
if ( x > 9.0 ) return 0.0;
|
|
|
|
if ( x <= 4.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 1.0 ) / ( 4.0 - 1.0 ) );
|
|
|
|
if ( x <= 6.0 ) return 1.0 + ( 1.0 - 1.0 ) * ( ( x - 4.0 ) / ( 6.0 - 4.0 ) );
|
|
|
|
if ( x <= 9.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 6.0 ) / ( 9.0 - 6.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_service_poor(double x) {
|
|
|
|
if ( x <= 0.0 ) return 1.0;
|
|
|
|
if ( x > 4.0 ) return 0.0;
|
|
|
|
if ( x <= 4.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 0.0 ) / ( 4.0 - 0.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_tip_average(double x) {
|
|
|
|
if ( x <= 10.0 ) return 0.0;
|
|
|
|
if ( x > 20.0 ) return 0.0;
|
|
|
|
if ( x <= 15.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 10.0 ) / ( 15.0 - 10.0 ) );
|
|
|
|
if ( x <= 20.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 15.0 ) / ( 20.0 - 15.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_tip_cheap(double x) {
|
|
|
|
if ( x <= 0.0 ) return 0.0;
|
|
|
|
if ( x > 10.0 ) return 0.0;
|
|
|
|
if ( x <= 5.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 0.0 ) / ( 5.0 - 0.0 ) );
|
|
|
|
if ( x <= 10.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 5.0 ) / ( 10.0 - 5.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
double FunctionBlock_tipper::membership_tip_generous(double x) {
|
|
|
|
if ( x <= 20.0 ) return 0.0;
|
|
|
|
if ( x > 30.0 ) return 0.0;
|
|
|
|
if ( x <= 25.0 ) return 0.0 + ( 1.0 - 0.0 ) * ( ( x - 20.0 ) / ( 25.0 - 20.0 ) );
|
|
|
|
if ( x <= 30.0 ) return 1.0 + ( 0.0 - 1.0 ) * ( ( x - 25.0 ) / ( 30.0 - 25.0 ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Print
|
|
|
|
void FunctionBlock_tipper::print() {
|
|
|
|
printf("Function block tipper:\n");
|
|
|
|
printf(" Input %20s : %f\n", "food" , food);
|
|
|
|
printf(" %20s : %f\n", "food_delicious" , food_delicious);
|
|
|
|
printf(" %20s : %f\n", "food_rancid" , food_rancid);
|
|
|
|
printf(" Input %20s : %f\n", "service" , service);
|
|
|
|
printf(" %20s : %f\n", "service_excellent" , service_excellent);
|
|
|
|
printf(" %20s : %f\n", "service_good" , service_good);
|
|
|
|
printf(" %20s : %f\n", "service_poor" , service_poor);
|
|
|
|
printf(" Output %20s : %f\n", "tip" , tip);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Reset output
|
|
|
|
void FunctionBlock_tipper::reset() {
|
|
|
|
for( int i=0 ; i < 1000 ; i++ ) { defuzzify_tip[i] = 0.0; }
|
|
|
|
}
|
|
|
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
// Create function blocks
|
|
|
|
FunctionBlock_tipper tipper;
|
|
|
|
|
|
|
|
// Parse input
|
|
|
|
if( argc > 1 ) { tipper.food = atof(argv[1]); }
|
|
|
|
if( argc > 2 ) { tipper.service = atof(argv[2]); }
|
|
|
|
|
|
|
|
// Calculate
|
|
|
|
tipper.calc();
|
|
|
|
|
|
|
|
// Show results
|
|
|
|
tipper.print();
|
|
|
|
}
|