void ControlLogic::updateTargetPwm()

in fboss/platform/fan_service/ControlLogic.cpp [112:243]


void ControlLogic::updateTargetPwm(Sensor* sensorItem) {
  bool accelerate, deadFanExists;
  float previousSensorValue, sensorValue, targetPwm;
  float value, lastPwm, kp, ki, kd, previousRead1, previousRead2, pwm;
  float minVal, maxVal, error, d;
  uint64_t dT;
  std::vector<std::pair<float, float>> tableToUse;
  switch (sensorItem->calculationType) {
    case fan_config_structs::SensorPwmCalcType::kSensorPwmCalcFourLinearTable:
      accelerate = true;
      previousSensorValue = sensorItem->fourCurves.previousSensorRead;
      sensorValue = sensorItem->processedData.adjustedReadCache;
      targetPwm = 0.0;
      deadFanExists = (numFanFailed_ > 0);
      accelerate =
          ((previousSensorValue == 0) || (sensorValue > previousSensorValue));
      if (accelerate && !deadFanExists) {
        tableToUse = sensorItem->fourCurves.normalUp;
      } else if (!accelerate && !deadFanExists) {
        tableToUse = sensorItem->fourCurves.normalDown;
      } else if (accelerate && deadFanExists) {
        tableToUse = sensorItem->fourCurves.failUp;
      } else {
        tableToUse = sensorItem->fourCurves.failDown;
      }
      // Start with the lowest value
      targetPwm = tableToUse[0].second;
      for (auto tableEntry = tableToUse.begin(); tableEntry != tableToUse.end();
           ++tableEntry) {
        if (sensorValue > tableEntry->first) {
          targetPwm = tableEntry->second;
        }
      }
      if (accelerate) {
        // If accleration is needed, new pwm should be bigger than old value
        if (targetPwm < sensorItem->processedData.targetPwmCache) {
          targetPwm = sensorItem->processedData.targetPwmCache;
        }
      } else {
        // If deceleration is needed, new pwm should be smaller than old one
        if (targetPwm > sensorItem->processedData.targetPwmCache) {
          targetPwm = sensorItem->processedData.targetPwmCache;
        }
      }
      sensorItem->fourCurves.previousSensorRead = sensorValue;
      sensorItem->processedData.targetPwmCache = targetPwm;
      XLOG(INFO) << "Control :: Sensor : " << sensorItem->sensorName
                 << " Value : " << sensorValue << " [4CUV] Pwm : " << targetPwm;
      break;

    case fan_config_structs::SensorPwmCalcType::kSensorPwmCalcIncrementPid:
      value = sensorItem->processedData.adjustedReadCache;
      lastPwm = sensorItem->incrementPid.previousTargetPwm;
      kp = sensorItem->incrementPid.kp;
      ki = sensorItem->incrementPid.ki;
      kd = sensorItem->incrementPid.kd;
      previousRead1 = sensorItem->incrementPid.previousRead1;
      previousRead2 = sensorItem->incrementPid.previousRead2;
      pwm = lastPwm + (kp * (value - previousRead1)) +
          (ki * (value - sensorItem->incrementPid.setPoint)) +
          (kd * (value - 2 * previousRead1 + previousRead2));
      // Even though the previous Target Pwm should be the zone pwm,
      // the best effort is made here. Zone should update this value.
      sensorItem->incrementPid.previousTargetPwm = pwm;
      sensorItem->processedData.targetPwmCache = pwm;
      sensorItem->incrementPid.previousRead2 = previousRead1;
      sensorItem->incrementPid.previousRead1 = value;
      XLOG(INFO) << "Control :: Sensor : " << sensorItem->sensorName
                 << " Value : " << value << " [IPID] Pwm : " << pwm;
      XLOG(INFO) << "           Prev1  : " << previousRead1
                 << " Prev2 : " << previousRead2;

      break;

    case fan_config_structs::SensorPwmCalcType::kSensorPwmCalcPid:
      value = sensorItem->processedData.adjustedReadCache;
      lastPwm = sensorItem->incrementPid.previousTargetPwm;
      pwm = lastPwm;
      kp = sensorItem->incrementPid.kp;
      ki = sensorItem->incrementPid.ki;
      kd = sensorItem->incrementPid.kd;
      previousRead1 = sensorItem->incrementPid.previousRead1;
      previousRead2 = sensorItem->incrementPid.previousRead2;
      dT = pBsp_->getCurrentTime() - lastControlUpdateSec_;
      minVal = sensorItem->incrementPid.minVal;
      maxVal = sensorItem->incrementPid.maxVal;

      if (value < minVal) {
        sensorItem->incrementPid.i = 0;
        sensorItem->incrementPid.previousTargetPwm = 0;
      }
      if (value > maxVal) {
        error = maxVal - value;
        sensorItem->incrementPid.i = sensorItem->incrementPid.i + error * dT;
        d = (error - sensorItem->incrementPid.last_error);
        pwm = kp * error + ki * sensorItem->incrementPid.i + kd * d;
        sensorItem->processedData.targetPwmCache = pwm;
        sensorItem->incrementPid.previousTargetPwm = pwm;
        sensorItem->incrementPid.last_error = error;
      }
      sensorItem->incrementPid.previousRead2 = previousRead1;
      sensorItem->incrementPid.previousRead1 = value;
      XLOG(INFO) << "Control :: Sensor : " << sensorItem->sensorName
                 << " Value : " << value << " [PID] Pwm : " << pwm;
      XLOG(INFO) << "               dT : " << dT
                 << " Time : " << pBsp_->getCurrentTime()
                 << " LUD : " << lastControlUpdateSec_ << " Min : " << minVal
                 << " Max : " << maxVal;
      break;

    case fan_config_structs::SensorPwmCalcType::kSensorPwmCalcDisable:
      // Do nothing
      XLOG(WARN) << "Control :: Sensor : " << sensorItem->sensorName
                 << "Do Nothing ";
      break;
    default:
      facebook::fboss::FbossError(
          "Invalid PWM Calculation Type for sensor", sensorItem->sensorName);
      break;
  }
  // No matter what, PWM should be within
  // predefined upper and lower thresholds
  if (sensorItem->processedData.targetPwmCache >
      pConfig_->getPwmUpperThreshold()) {
    sensorItem->processedData.targetPwmCache = pConfig_->getPwmUpperThreshold();
  } else if (
      sensorItem->processedData.targetPwmCache <
      pConfig_->getPwmLowerThreshold()) {
    sensorItem->processedData.targetPwmCache = pConfig_->getPwmLowerThreshold();
  }
  return;
}