65.9K
CodeProject 正在变化。 阅读更多。
Home

C++ 模糊逻辑 API + 简单 DSL

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.59/5 (11投票s)

2012年1月18日

CPOL

8分钟阅读

viewsIcon

59458

downloadIcon

1721

使用 C++ 实现的模糊逻辑 API 和模糊逻辑 DSL。

什么是模糊逻辑?

在本文中,我将向您介绍我的模糊逻辑实现,称为 FuzzyLogic API。我相信这个实现是简单、有效且非常快速的。您知道什么是模糊逻辑吗?在这里我不会过多地谈论模糊逻辑理论,因为有很多很棒的关于模糊逻辑的文章(见下方的链接)。

模糊逻辑实现

在本节中,我将描述我的 FuzzyLogic API 实现。我试图使其清晰简单,以便每个人都能轻松理解。首先,我将尝试描述一些简单的类,这些类将在 FuzzyLogic API 中更复杂和更重要的类中使用。

CLinguisticVariable

UML_0.jpg

CLinguisticVariable 是用于表示语言变量的类。它有三个类变量。variableName 用于定义语言变量的名称,并且应该是唯一的,因为我们使用哈希映射来存储 CLinguisticVariable,因此我们可以在 O(1) 时间内找到特定的语言变量。下一个变量 b_output 声明该语言变量是否是输出变量。请注意,FuzzyLogic API 中只能有一个输出变量。最后一个变量 h_linguisticValuesHashMap 用于存储语言值。一个语言变量可以有一个或多个语言值。有几个类方法。AddLinguisticValue 向选定的 CLinguisticVariable 添加 LinguisticValue。在下一个图像中,您可以看到四个语言变量:DistanceApproachingSpeedSignal

UML_linguistic_variables.jpg

下一个方法将语言值添加到 hash_map

//Method add Linguistic value to hash map
void AddLinguisticValue(LinguisticValue* p_linguisticValue)
{
    h_linguisticValuesHashMap.insert(LinguisticValue_Pairs(
        p_linguisticValue->ToString(), p_linguisticValue));
}

其中 LinguisticValue_Pairs 是在以下位置声明的 typedef

//Typedef for linguistic values hash map.
typedef pair <string, LinguisticValue*> LinguisticValue_Pairs;

ResetLinguisticValues 方法只是将所有语言值重置为 -1。一个更有趣的方法是 FindLinguisticValueByName。该方法的输入参数是语言值的名称,返回值是 LinguisticValue 对象的指针。因为我们使用哈希映射,所以时间复杂度是 O(1)。

LinguisticValue* FindLinguisticValueByName(string name)
{
    //Define iterator
    hash_map <string, LinguisticValue*> :: const_iterator iterator;
    //Fint linguistic value by name
    iterator = h_linguisticValuesHashMap.find(name);
    if(iterator == h_linguisticValuesHashMap.end())
    {
        //SASO, this should never happends!!!!!
        assert(NULL);
        return NULL;
    }
    //Return LinguisticValue
    return (LinguisticValue*)iterator->second;
}

CalculateLinguisticValueByName 只是 CFuzzyReasonerLinguisticValue 之间用于计算语言值的桥梁。UpdateLinguisticValueByName 稍微复杂一些。首先,我们必须按名称查找 LinguisticValue。如果已经存储了一个值,我们将执行模糊 OR 操作,否则我们将只存储 newVal。让我们看看代码

//Update Linguistic value by name
void UpdateLinguisticValueByName(string name, double newVal)
{
    //Find LinguisticValue
    LinguisticValue* value = FindLinguisticValueByName(name);

    //If there is value, we should perform operator OR
    if(value->GetLinguisticValue() != -1)
        value->SetLinguisticValue(CFuzzyCalculator::OR(value->GetLinguisticValue(), newVal));
    else
        value->SetLinguisticValue(newVal); //There is no value, just set newVal
}

LinguisticValue

UML_linguistic_value.jpg

UML_linguistic_variables.jpg

LinguisticValue 类用于存储语言值。变量 ABCD 是梯形(梯形)的“边界”。例如,语言变量 Distance 有三个语言值(LowAverageHeight),对于语言值“Low”,变量 ABCD 将是 A = 0、B = 0、C = 1、D = 2。每个 LinguisticValue 都有一个唯一的名称(就像在 CLinguisticVariable 中一样)。变量 linguisticValue 用于存储数值。默认值为 -1。此值表示输入值在多大程度上属于此 LinguisticValue 梯形。对于语言值 Average(语言变量 Speed,输入:0(km/h)),此值将等于 0.5(参见上图)。只有一个方法(除了构造函数、getter 和 setter)称为 CalculateLinguisticValue。我们必须注意输入的正确性,因此如果输入超出范围,我们应该对其进行归一化。然后,我们需要计算梯形函数。梯形函数的结果是特定变量的语言值。

double CalculateLinguisticValue(double input)
{
    //Normalize variables
    if(input < A)
        input = A;
    else if(input > D)
        input = D;
    //Calculating Trapezoid function
    if ((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;
    else 
        return (D - input) / (D - C);
}

CFuzzyCalculator

UML_calculator.jpg

可能是项目中类最简单的一个。只有两个静态方法。AND 方法实现了 AND 运算符,该运算符等于返回最小值。

//Operator AND
static double AND(double a, double b)
{
    if(a < b)
        return a;
    return b;
}

OR 方法实现了 OR 运算符,返回最大值。

//Operator OR
static double OR(double a, double b)
{
    if(a > b)
        return a;
    return b;

}

CFuzzyRule

UML_fuzzy_rule.jpg

模糊逻辑由语言变量和模糊规则组成。此类用于存储模糊规则。模糊规则由 CFuzzyToken 类对象组成。此类唯一的函数是向规则添加 CFuzzyRuleToken。例如,CFuzzyRule 可以是

"IF NOT SPEED = SLOW AND DISTANCE = CLOSE, SIGNAL = BRAKE"

每条模糊规则都应该有一个输出变量!

CFuzzyRuleToken

UML_fuzzy_rule_token.jpg

正如我之前所说,CFuzzyRuleToken 只是 CFuzzyRule 的一部分。让我们描述所有变量。operation 描述了前一个和当前的 CFuzzyRuleToken 之间的操作类型。支持的操作符是 OR、AND 和 EMPTY。EMPTY 表示没有操作符(“VOID”)。EMPTY 令牌仅用于规则中的第一个和最后一个令牌。令牌也可以被否定(变量 b_negation)。每个 CFuzzyToken 都有一个指向 CLinguisticVariable 的指针以及语言值的名称。让我们更仔细地看看 CFuzzyRule 示例。

"IF NOT SPEED = SLOW AND DISTANCE = CLOSE, SIGNAL = BRAKE"

什么是令牌?有三个令牌示例

Token_1
operation = EMPTY
b_Negate = true
p_linguisticVariable= SPEED
linguisticValueName = "SLOW"

Token_2 operation = AND
b_Negate = false
p_linguisticVariable= DISTANCE 
linguisticValueName = "CLOSE"

Token_3
operation =EMPTY
b_Negate = false
p_linguisticVariable= SIGNAL 
linguisticValueName = BRAKE"

请注意,TOKEN_3 是输出令牌!每条 CFuzzyRule 都必须有一个带有输出变量的令牌!!!

CalculateTokenOutputValue 方法用于从哈希映射 h_fuzzyInputHashMap 获取输入值并调用方法来计算语言值。输入变量 h_fuzzyInputHashMap 是一个填充了对象(CFuzzyInput 类)的 hash_map。在 CFuzzyInput 中存储了特定语言变量的输入值。稍后将解释 CFuzzyInput

//Calculate token value
double CalculateTokenOutputValue(hash_map <string, CFuzzyInput*> h_fuzzyInputHashMap)
{
    hash_map <string,> :: const_iterator iterator;
    //Find linguistic variable
    iterator = h_fuzzyInputHashMap.find(p_linguisticVariable->ToString());
    CFuzzyInput* temp = (CFuzzyInput*)iterator->second;
    double input = temp->GetInputValue();
    //Calculate linguistic value
    return p_linguisticVariable->CalculateLinguisticValueByName(linguisticValueName, input);
}

CFuzzyInput

UML_fuzzy_input.jpg

CFuzzyInput 只有两个变量,variableName 用于语言变量名称,inputValue(类型 double)用于值。例如,CFuzzyInput 可以是 variableName = "SPEED"inputValue = "43"(km/h)。

CFuzzyReasoner

UML_fuzzy_reasoner.jpg

CFuzzyReasoner 是 FuzzyLogic 系统的核心。它用于计算模糊规则的输出值和最终的去模糊化。CFuzzyReasoner 变量 v_fuzzyRulesVector 用于存储模糊规则(CFuzzyRule)。让我们看看 FuzzyLogic 中最重要的函数 FuzzyRuleReasoner。该函数以模糊规则和填充了模糊输入的哈希映射作为输入。检查每个模糊规则令牌是否为输出变量。如果不是,则输出变量是当前令牌变量的计算语言值。然后我们检查令牌是否被否定。如果语言变量不是模糊规则中的第一个变量,并且不是输出变量,那么我们应该有一个不同于 EMPTY 的操作符。只有模糊规则中的第一个变量必须具有 EMPTY 操作符(对于输出值,操作符不重要)。对于输出值,我们只设置一个新值(resetVal)并返回指向输出令牌的指针。

//Start fuzzy rule reasoner
CFuzzyRuleToken* 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 token
        CFuzzyRuleToken* token = fuzzyRule->GetFuzzyRuleTokens()[i];
            if(token->IsOutput())
        {
            //Update output object
            token->UpdateTokenValue(resultVal);
            //Return result token
            return token;
        }
        else
        {
            double tokenVal = token->CalculateTokenOutputValue(h_fuzzyInputs);
            token->UpdateTokenValue(tokenVal);
            if(token->IsNegated())
                tokenVal = 1 - tokenVal;    //Negate value
            if(i == 0)
                resultVal = tokenVal;        //Set value
            else if(token->IsOrOperator())
                resultVal = CFuzzyCalculator::OR(resultVal, tokenVal); //OR operator
            else if(token->IsAndOperator())
                resultVal = CFuzzyCalculator::AND(resultVal, tokenVal); //AND operator
        }
    }
    //This won't happends saso
    assert(NULL);
    return NULL;
}

以下方法仅为 FuzzyLogic API 中的每个模糊规则调用推理。

//Start reasoner for fuzzy rulles
CFuzzyRuleToken* CalculateFuzzyRules(hash_map <string, CFuzzyInput*> h_fuzzyInputs)
{
    //Reset all values
    CFuzzyRuleToken* outputObject;
    //Calculate all fuzzy rules
    for(unsigned int i = 0; i < v_fuzzyRulesVector.size(); i++)
    {
        //Glede na izhodno vrednost izhodne spremeljivke naredi update izhodnega objekta
        outputObject = FuzzyRuleReasoner((CFuzzyRule*)v_fuzzyRulesVector[i], h_fuzzyInputs);
    }
    //Return output object
    return outputObject;
}

模糊逻辑推理的最后一步是去模糊化。它在接下来的两个方法中实现。

//Defuzzyfication
double Defuzzy(CFuzzyRuleToken *outputToken)
{
    //For every output value
    CLinguisticVariable* lVar = outputToken->GetLinguisticVariable();
    vector<LinguisticValue*> valuesList = lVar->GetLinguisticValuesList();

    double upEqualation = 0;
    double downEqualation = 0;
    //Calculating defuzzy value
    for(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 system
    if(downEqualation == 0)
        return 0;
    return upEqualation / downEqualation;
}

//Calculating surface of trapezoid 
double 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));
}

如何使用它?

您可能想知道如何使用此 FuzzyLogic API。这并不复杂。为了让您生活更轻松,我制作了三个简单的示例。第一个是用于模糊巡航控制,第二个是用于篮球运动员,最后一个是用于滑雪跳跃者。所有示例都在名为 CExperiments 的类中。让我们看看简单的篮球运动员示例。我们创建三个语言变量,然后将语言值添加到语言变量中。使用语言变量,我们创建两个规则并将规则添加到 FuzzyLogic 中。

void BuildBasketballPlayersRules()
{
    //Method for building necessary rules for Basketball players
    CLinguisticVariable *height = new CLinguisticVariable(false,"Height");
    CLinguisticVariable *age = new CLinguisticVariable(false,"Age");
    CLinguisticVariable *basketball_player = 
              new CLinguisticVariable(true,"Basketball_player");

    //Add linguistic values to variable
    height->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 rules
    fr->AddFuzzyRule(rule1);
    fr->AddFuzzyRule(rule2);

    //Add linguistic variables, if you want to obtain
    //more informations about fuzzy calculations
    AddLinguisticVariables(height);
    AddLinguisticVariables(age);
    AddLinguisticVariables(basketball_player);
}

如何执行示例

通过下一个示例,您应该了解如何使用 CExperiment 类。

int _tmain(int argc, _TCHAR* argv[])
{
    //Create instance of CExperiments.
    CExperiments* experiment = new CExperiments();
    //Create rules
    experiment->BuildCruiseControlRules();

    //Hash_map for storing inputs
    hash_map <string, CFuzzyInput*> h_fuzzyInputs;
    
    //Put some values to inputs
    CFuzzyInput* inputRazdalja = new CFuzzyInput("Distance", 1.8);
    CFuzzyInput* inputPriblizevanje = new CFuzzyInput("Approaching", 15);
    CFuzzyInput* inputHitrost = new CFuzzyInput("Speed", -8);
    
    //Insert inputs to the hash_map
    h_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 signal
    double outputSignal = experiment->CalculateFuzzyRules(h_fuzzyInputs);
    
    //Get some additional informations from fuzzy logic 
    double 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;
}

太复杂了?

为了更轻松地定义规则和属性,我制作了一个简单的 DSL(领域特定语言)。

CFuzzyLanguageParser

项目 CFuzzyLogicDSL 的唯一类是 CFuzzyLanguageParser。此类用于解析模糊规则和属性。输入值是包含模糊规则/属性的文件的路径,输出值是 CExperiment 中更新的规则和属性(您必须将 CExperiment* 指针放入 CFuzzyLanguageParser 构造函数)。让我们看看输入文件的格式。请,请非常准确地处理空格。如果您忘记空格,解析器将无法工作(我已尝试保持一个简单的实现)。您可以使用以下格式定义属性

Linguistic_Variable_Name Input/Output ValueName_0 (A,B,C,D) ValueName_N (A,B,C,D)

和规则

IF Linguistic_Variable_Name = Linguistic_Value_Name AND ... 
  AND Linguistic_Variable_Name NOT Linguistic_Value_Name THEN 
  Linguistic_Variable_Name = Linguistic_Value_Name

还可以使用以下方法写注释:

% This is comment

下一步是代码解释。“main”方法是 Parse。逐行简单读取,按空格分割令牌,然后检查它是注释、空行、规则还是属性。

void Parse(char* filePath)
{
    ifstream ifs(filePath);
    string line;
    while( getline( ifs, line ) )
    {
        vector<string> tokens = SplitBy(line,' ');
        //Skip lines without text
        if(tokens.size() > 0)
        {
            //Skip comments
            if(!IsComment(tokens[0]))
            {
                if(IsRule(tokens[0]))
                    ParseFuzzyRule(tokens);
                else
                    ParseFuzzyAtribute(tokens);
            }
        }
    }
    //Close stream
    ifs.close();
}

以下是检查一行是否为注释或规则的方法

//Check is line is comment
bool IsComment(string token)
{
    //Return true if is comment
    if(token.at(0) == '%')
        return true;
    return false;
}

bool IsRule(string token)
{
    //Return true if is rule
    if(token == "IF")
        return true;
    return false;
}

我们如何解析规则和属性?查看接下来的两个简单方法。ParseFuzzyRule 仅遍历所有令牌(我们不需要处理第一个令牌,它应该是“IF”)并检查它是否是操作符令牌(AND/OR)并设置适当的操作。然后我们检查是否有否定,或者我们处于“set”(令牌“=”)状态。如果此条件为真,我们只需设置前一个和后一个令牌,创建一个新的 CFuzzyRuleToken,然后将其添加到规则中。

void ParseFuzzyRule(vector<string> ruleTokens)
{
    //Rule example
    //IF distance = low AND approaching NOT slow THEN signal=breake
    //SKIP IF token
    bool 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, THEN
        if((ruleTokens[i] == "AND") || (ruleTokens[i] == "OR"))
        {
            if(ruleTokens[i] == "AND")
                operation = AND;
            else
                operation = OR;
        }
        else if((ruleTokens[i] == "=") || (ruleTokens[i] == "NOT"))
        {
            leftSide = ruleTokens[i - 1];
                //Next token is right side
            if(ruleTokens[i] == "NOT")
                negated = true;
            rightSide = ruleTokens[++i];
            
            //ADD TOKEN TO RULE
            CLinguisticVariable* linVar = 
              fuzzyInterface->FindLinguisticVariableByName(leftSide);
            assert(linVar != NULL);
            rule->AddTokenToRule(
              new CFuzzyRuleToken(negated,operation,linVar,rightSide));
            //RESET
            operation = EMPTY;
            negated = false;
        }
    }
    fuzzyInterface->AddFuzzyRule(rule);
}

现在,解析属性。第一个令牌始终是语言变量名,第二个令牌应该是属性信息。可以有 N 个语言值。我们必须遍历所有令牌,解析是输入还是输出。有了这些信息,我们就可以创建 CLinguisticVariable。然后我们可以开始解析语言值。我们必须遍历所有剩余的令牌。下一个令牌必须是语言值名称,后跟语言值(ParseLinguisticValues 方法)。解析完所有语言值后,我们可以将 LinguisticVariable 添加到列表中(在 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,D
    string linguisticVariableName = attTokens.at(0);
    bool output = true;
    if(attTokens.at(1) == "Input")
        output = false;
    //Creating new linguistic variable
    CLinguisticVariable *linguisticVariable = 
       new CLinguisticVariable(output,linguisticVariableName);

    //Adding linguistic values to variable
    for(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[0],
            linguisticValues[1],
            linguisticValues[2],
            linguisticValues[3]);
        linguisticVariable->AddLinguisticValue(linValue);
    }
    fuzzyInterface->AddLinguisticVariables(linguisticVariable);
}

vector<double> ParseLinguisticValues(string token)
{
    vector<double> linguisticValues;
    //Remove first and last char
    token = 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;
}

输入文件示例

%ATTRIBUTES 
Distance 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 = Brake
IF Distance = Average AND Approaching = Fast THEN Signal = Brake
IF Speed = Fast THEN Signal = Brake
IF Distance NOT Low AND Approaching = Average THEN Signal = Maintain
IF Distance = High AND Approaching NOT Fast AND Speed = Acceptable THEN Signal = Maintain
IF Distance = Average AND Speed = Slow THEN Signal = Maintain
IF Distance = High AND Speed = Slow THEN Signal = Accelerate

我想看看!

我的朋友 Jan Bezget 使用 OGRE 制作了一个非常酷的巡航控制示例 3D 可视化。您可以在此处找到他的可视化:点击我!

ScreenShot.jpg

摘要

您现在已经看到,模糊逻辑的实现可以非常简单且有效。令人印象深刻的是,像模糊逻辑这样简单的 AI 方法可以如此有用。佳能使用模糊逻辑进行自动对焦,它也常用于空调,甚至用于仙台地铁系统!我希望您喜欢我的文章和我的 FuzzyLogic API 实现。谢谢阅读 :)

© . All rights reserved.