Add a modified median calculation
This is for virtual sensors added via D-Bus.
We use the median value if there is 3 or more valid values. If there
are only two valid values we used the biggest and if there is only one
valid value we use that.
Tested:
- Modified temperature values of sensors like this:
busctl set-property xyz.openbmc_project.HwmonTempSensor
/xyz/openbmc_project/sensors/temperature/Ambient_0_Temp
xyz.openbmc_project.Sensor.Value Value d 30
and expected changes were observed in the value of the Ambient Virtual
Temp value.
busctl get-property xyz.openbmc_project.VirtualSensor
/xyz/openbmc_project/sensors/temperature/Ambient_Virtual_Temp
xyz.openbmc_project.Sensor.Value Value
- Threshold alarms were asserted and deasserted when expected.
- Temperature values were not used when out of range.
Change-Id: I58ff7dcc17c6f87209434a754f91a99f483140aa
Signed-off-by: Rashmica Gupta <rashmica.g@gmail.com>
diff --git a/virtualSensor.cpp b/virtualSensor.cpp
index be9d78a..4e9f50a 100644
--- a/virtualSensor.cpp
+++ b/virtualSensor.cpp
@@ -16,7 +16,8 @@
static constexpr auto entityManagerBusName =
"xyz.openbmc_project.EntityManager";
static constexpr auto vsThresholdsIfaceSuffix = ".Thresholds";
-static constexpr std::array<const char*, 0> calculationIfaces = {};
+static constexpr std::array<const char*, 1> calculationIfaces = {
+ "xyz.openbmc_project.Configuration.ModifiedMedian"};
using namespace phosphor::logging;
@@ -384,12 +385,31 @@
ValueIface::value(value);
}
-double VirtualSensor::calculateValue()
+double VirtualSensor::calculateValue(const std::string& calculation,
+ const VirtualSensor::ParamMap& paramMap)
{
- // Placeholder until calculation types are added
+ auto itr = std::find(calculationIfaces.begin(), calculationIfaces.end(),
+ calculation);
+ if (itr == calculationIfaces.end())
+ {
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+ else if (calculation == "xyz.openbmc_project.Configuration.ModifiedMedian")
+ {
+ return calculateModifiedMedianValue(paramMap);
+ }
return std::numeric_limits<double>::quiet_NaN();
}
+bool VirtualSensor::sensorInRange(double value)
+{
+ if (value <= this->maxValidInput && value >= this->minValidInput)
+ {
+ return true;
+ }
+ return false;
+}
+
void VirtualSensor::updateVirtualSensor()
{
for (auto& param : paramMap)
@@ -408,8 +428,9 @@
}
auto itr =
std::find(calculationIfaces.begin(), calculationIfaces.end(), exprStr);
- auto val = (itr == calculationIfaces.end()) ? expression.value()
- : calculateValue();
+ auto val = (itr == calculationIfaces.end())
+ ? expression.value()
+ : calculateValue(exprStr, paramMap);
/* Set sensor value to dbus interface */
setSensorValue(val);
@@ -427,6 +448,47 @@
checkThresholds(val, hardShutdownIface);
}
+double VirtualSensor::calculateModifiedMedianValue(
+ const VirtualSensor::ParamMap& paramMap)
+{
+ std::vector<double> values;
+
+ for (auto& param : paramMap)
+ {
+ auto& name = param.first;
+ if (auto var = symbols.get_variable(name))
+ {
+ if (!sensorInRange(var->ref()))
+ {
+ continue;
+ }
+ values.push_back(var->ref());
+ }
+ }
+
+ size_t size = values.size();
+ std::sort(values.begin(), values.end());
+ switch (size)
+ {
+ case 2:
+ /* Choose biggest value */
+ return values.at(1);
+ case 0:
+ return std::numeric_limits<double>::quiet_NaN();
+ default:
+ /* Choose median value */
+ if (size % 2 == 0)
+ {
+ // Average of the two middle values
+ return (values.at(size / 2) + values.at(size / 2 - 1)) / 2;
+ }
+ else
+ {
+ return values.at((size - 1) / 2);
+ }
+ }
+}
+
void VirtualSensor::createThresholds(const Json& threshold,
const std::string& objPath)
{
diff --git a/virtualSensor.hpp b/virtualSensor.hpp
index ada20d9..b4fd815 100644
--- a/virtualSensor.hpp
+++ b/virtualSensor.hpp
@@ -122,6 +122,8 @@
void setSensorValue(double value);
/** @brief Update sensor at regular intrval */
void updateVirtualSensor();
+ /** @brief Check if sensor value is in valid range */
+ bool sensorInRange(double value);
/** @brief Map of list of parameters */
using ParamMap =
@@ -175,7 +177,11 @@
const std::string& calculationType);
/** @brief Returns which calculation function or expression to use */
- double calculateValue();
+ double calculateValue(const std::string& sensortype,
+ const VirtualSensor::ParamMap& paramMap);
+ /** @brief Calculate median value from sensors */
+ double
+ calculateModifiedMedianValue(const VirtualSensor::ParamMap& paramMap);
/** @brief create threshold objects from json config */
void createThresholds(const Json& threshold, const std::string& objPath);
/** @brief parse config from entity manager **/