引言 在前面的一篇文章PID控制算法 简单说明了模糊控制算法的原理,本文用C++实现了一个通用性的模糊控制器。
fuzzy_controller.hpp文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #pragma once #include <functional> #include <map> #include <string> #include <vector> namespace control_algorithm {class FuzzySet { public : std::string name; std::function<double (double )> membershipFunction; FuzzySet (const std::string& setName, std::function<double (double )> func) : name (setName), membershipFunction (func) {} double calculateMembership (double x) const { return membershipFunction (x); } }; class Fuzzy { private : std::map<std::string, std::vector<FuzzySet>> inputVariables; std::vector<FuzzySet> outputVariable; std::map<std::string, std::string> ruleBase; public : Fuzzy (); void addInputVariable (const std::string& name, const std::vector<FuzzySet>& sets) ; void setOutputVariable (const std::vector<FuzzySet>& sets) ; void addRule (const std::string& inputCondition, const std::string& outputAction) ; double evaluate (const std::map<std::string, double >& inputs) ; private : std::map<std::string, double > fuzzify (const std::string& variableName, double value) ; std::map<std::string, double > applyRules ( const std::map<std::string, std::map<std::string, double >>& fuzzifiedInputs) ; double defuzzify (const std::map<std::string, double >& fuzzyOutput) ; }; }
fuzzy_controller.cpp文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 #include <cmath> #include <iostream> #include <numeric> #include <stdexcept> #include "fuzzy_controller.hpp" using namespace control_algorithm;Fuzzy::Fuzzy () {} void Fuzzy::addInputVariable (const std::string& name, const std::vector<FuzzySet>& sets) { inputVariables[name] = sets; } void Fuzzy::setOutputVariable (const std::vector<FuzzySet>& sets) { outputVariable = sets; } void Fuzzy::addRule (const std::string& inputCondition, const std::string& outputAction) { ruleBase[inputCondition] = outputAction; } std::map<std::string, double > Fuzzy::fuzzify (const std::string& variableName, double value) { std::map<std::string, double > memberships; if (inputVariables.find (variableName) == inputVariables.end ()) { throw std::invalid_argument ("Unknown input variable: " + variableName); } for (const auto & set : inputVariables[variableName]) { memberships[set.name] = set.calculateMembership (value); } return memberships; } std::map<std::string, double > Fuzzy::applyRules ( const std::map<std::string, std::map<std::string, double >>& fuzzifiedInputs) { std::map<std::string, double > aggregatedOutput; for (const auto & rule : ruleBase) { const std::string& inputCondition = rule.first; const std::string& outputAction = rule.second; double ruleActivation = 1.0 ; size_t start = 0 ; size_t end = inputCondition.find (" AND " ); while (end != std::string::npos) { std::string variableAndSet = inputCondition.substr (start, end - start); size_t splitPos = variableAndSet.find (" " ); std::string variable = variableAndSet.substr (0 , splitPos); std::string set = variableAndSet.substr (splitPos + 1 ); if (fuzzifiedInputs.count (variable) == 0 || fuzzifiedInputs.at (variable).count (set) == 0 ) { ruleActivation = 0.0 ; break ; } ruleActivation = std::min (ruleActivation, fuzzifiedInputs.at (variable).at (set)); start = end + 5 ; end = inputCondition.find (" AND " , start); } std::string variableAndSet = inputCondition.substr (start); size_t splitPos = variableAndSet.find (" " ); std::string variable = variableAndSet.substr (0 , splitPos); std::string set = variableAndSet.substr (splitPos + 1 ); if (fuzzifiedInputs.count (variable) == 0 || fuzzifiedInputs.at (variable).count (set) == 0 ) { ruleActivation = 0.0 ; } else { ruleActivation = std::min (ruleActivation, fuzzifiedInputs.at (variable).at (set)); } aggregatedOutput[outputAction] = std::max (aggregatedOutput[outputAction], ruleActivation); } return aggregatedOutput; } double Fuzzy::defuzzify (const std::map<std::string, double >& fuzzyOutput) { double numerator = 0.0 ; double denominator = 0.0 ; for (const auto & set : outputVariable) { double peak = 0.0 ; double lowerBound = -200 ; double upperBound = 200 ; peak = (lowerBound + upperBound) / 2.0 ; if (fuzzyOutput.find (set.name) != fuzzyOutput.end ()) { double membership = fuzzyOutput.at (set.name); numerator += peak * membership; denominator += membership; } } return denominator == 0 ? 0 : numerator / denominator; } double Fuzzy::evaluate (const std::map<std::string, double >& inputs) { std::map<std::string, std::map<std::string, double >> fuzzifiedInputs; for (const auto & input : inputs) { fuzzifiedInputs[input.first] = fuzzify (input.first, input.second); } auto fuzzyOutput = applyRules (fuzzifiedInputs); return defuzzify (fuzzyOutput); }