Program Listing for File fuzzy_pd_rule_table.cpp

Return to documentation for file (src/tap/algorithms/fuzzy_pd_rule_table.cpp)

/*
 * Copyright (c) 2022 Advanced Robotics at the University of Washington <robomstr@uw.edu>
 *
 * This file is part of Taproot.
 *
 * Taproot is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Taproot is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Taproot.  If not, see <https://www.gnu.org/licenses/>.
 */

#include "fuzzy_pd_rule_table.hpp"

using namespace std;

namespace tap::algorithms
{
void FuzzyPDRuleTable::performFuzzification(float e, float d)
{
    performSingleValueFuzzification(e, errorFuzzificationMemberValues);
    performSingleValueFuzzification(d, derivativeFuzzificationMemberValues);
}

void FuzzyPDRuleTable::updateFuzzyMatrix()
{
    // Insert elements into the fuzzy matrix
    // Fuzzy multiply the 2 3x1 fuzzy vectors together to product the single matrix
    for (size_t i = 0; i < NUM_FUZZY_MEMBERS; i++)
    {
        for (size_t j = 0; j < NUM_FUZZY_MEMBERS; j++)
        {
            fuzzyMatrix[i][j] =
                min(errorFuzzificationMemberValues[i], derivativeFuzzificationMemberValues[j]);
        }
    }
}

inline float computeGain(
    const array<float, FuzzyPDRuleTable::NUM_FUZZY_MEMBERS> &weights,
    const array<float, FuzzyPDRuleTable::NUM_FUZZY_MEMBERS> &values)
{
    float weightSum = 0;
    for (size_t i = 0; i < weights.size(); i++)
    {
        weightSum += weights[i];
    }

    if (weightSum > 0)
    {
        float gain = 0;
        for (size_t i = 0; i < weights.size(); i++)
        {
            gain += weights[i] * values[i];
        }

        return gain / weightSum;
    }
    else
    {
        return 0;
    }
}

void FuzzyPDRuleTable::performDefuzzification()
{
    // Choosen based on what "feels" right (very experimental)
    // In general, the following rules are followed when selecting which weight is associated with
    // which gain:
    // - the P gain should be small when error & derivative is small
    // - the P gain should be large when the error is large and the derivative indicates the error
    //   is increasing
    // - otherwise the P gain should be medium
    // - the D gain should be small when the error is large and the derivative is increasing the
    //   error or if the error and derivative are close to 0
    // - the D gain should be large when the error is 0 but the derivative is large (either negative
    //   or positive)
    // - otherwise the D gain should be medium

    array<float, NUM_FUZZY_MEMBERS> kpWeights;

    // small weight
    kpWeights[0] = fuzzyMatrix[Z][Z];

    // medium weight
    kpWeights[1] = max(
        max(max(fuzzyMatrix[Z][N], fuzzyMatrix[N][Z]), max(fuzzyMatrix[P][Z], fuzzyMatrix[Z][P])),
        max(fuzzyMatrix[N][N], fuzzyMatrix[P][P]));

    // large weight
    kpWeights[2] = max(fuzzyMatrix[N][P], fuzzyMatrix[P][N]);

    fuzzyGains[0][0] = computeGain(kpWeights, kpArray);

    array<float, NUM_FUZZY_MEMBERS> kdWeights;

    // small weight
    kdWeights[0] = max(max(fuzzyMatrix[N][P], fuzzyMatrix[P][N]), fuzzyMatrix[Z][Z]);
    // kdWeights[0] = max(max(fuzzyMatrix[Z][P], fuzzyMatrix[Z][N]), fuzzyMatrix[Z][Z]);

    // medium weight
    kdWeights[1] =
        max(max(fuzzyMatrix[N][N], fuzzyMatrix[N][Z]), max(fuzzyMatrix[P][Z], fuzzyMatrix[P][P]));

    // large weight
    kdWeights[2] = max(fuzzyMatrix[Z][N], fuzzyMatrix[Z][P]);

    fuzzyGains[1][0] = computeGain(kdWeights, kdArray);
}

modm::Matrix<float, 2, 1> FuzzyPDRuleTable::performFuzzyUpdate(float e, float d)
{
    performFuzzification(e, d);
    updateFuzzyMatrix();
    performDefuzzification();
    return fuzzyGains;
}
}  // namespace tap::algorithms