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;
}