fix: a readout keeps its metric prefix when the stream declares no unit
The SI prefix ladder in format_measure() was gated on a non-empty unit, so two decimals of a small unitless value printed `0.00` -- the reading gone, not merely coarse. That is a whole class of channels rather than a corner: a CONFIG need not declare a unit, and a math channel never has one. Below 1e-12 the same loss happened even with a unit, so that range falls back to three significant digits. With no unit the prefix goes tight against the number (`585.24m`), since the space exists to separate the number from its unit and a spaced `m` alone reads as metres. The mock declared `unit="V"` for every data signal, which is why no probe could see this; it now takes `--unit ''`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
3d7e214295
commit
b505706d92
6 files changed
+66
-25
No files matched your search
+23
-18
@@ -922,6 +922,13 @@ const char* badge_markup(BadgePhase phase) {
|
||||
/// sample is an `f32` of a value the CONFIG may scale arbitrarily, so more digits would be
|
||||
/// noise dressed as precision. Trailing zeros go, so `1.50 V` reads `1.5 V` -- "at most
|
||||
/// two decimals", not exactly two.
|
||||
///
|
||||
/// The prefix is applied **whether or not a unit is declared**, and that is the point: two
|
||||
/// decimals of an unprefixed small value is `0.00`, i.e. the reading is simply gone. A signal
|
||||
/// whose CONFIG declares no unit is ordinary (and a *math* channel never has one), so the pane
|
||||
/// showed `0.00` for every value under 5 mV of an entire class of channels. A bare prefix is
|
||||
/// written tight against the number -- `1.34m`, not `1.34 m` -- because the space is there to
|
||||
/// separate the number from its unit, and with no unit to separate, a spaced `m` reads as metres.
|
||||
std::string format_measure(double v, const std::string& unit) {
|
||||
if (!std::isfinite(v)) return "--";
|
||||
static const struct {
|
||||
@@ -934,22 +941,22 @@ std::string format_measure(double v, const std::string& unit) {
|
||||
const double mag = std::fabs(v);
|
||||
const char* prefix = "";
|
||||
double scale = 1.0;
|
||||
// No unit, no prefix: `10.52 m` is a prefix with nothing to prefix, which reads as
|
||||
// metres. A bare number stays a bare number and simply keeps its decimals.
|
||||
if (!unit.empty()) {
|
||||
for (const auto& p : kPrefixes) {
|
||||
if (mag >= p.scale) {
|
||||
prefix = p.prefix;
|
||||
scale = p.scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mag > 0.0 && mag < 1.0e-12) { // below the ladder: keep it in plain digits
|
||||
prefix = "";
|
||||
scale = 1.0;
|
||||
for (const auto& p : kPrefixes) {
|
||||
if (mag >= p.scale) {
|
||||
prefix = p.prefix;
|
||||
scale = p.scale;
|
||||
break;
|
||||
}
|
||||
}
|
||||
char buf[64];
|
||||
if (mag > 0.0 && mag < 1.0e-12) {
|
||||
// Below the ladder, where scaling cannot help and `%.2f` would print `0.00` again. Three
|
||||
// significant digits in whatever form fits, so the reading survives as a reading.
|
||||
std::snprintf(buf, sizeof(buf), "%.3g", v);
|
||||
std::string out = buf;
|
||||
if (!unit.empty()) out += " " + unit;
|
||||
return out;
|
||||
}
|
||||
std::snprintf(buf, sizeof(buf), "%.2f", v / scale);
|
||||
std::string num = buf;
|
||||
if (num.find('.') != std::string::npos) { // at most two decimals, not exactly two
|
||||
@@ -958,11 +965,9 @@ std::string format_measure(double v, const std::string& unit) {
|
||||
}
|
||||
if (num == "-0") num = "0";
|
||||
std::string out = num;
|
||||
if (prefix[0] != '\0') out += std::string(" ") + prefix;
|
||||
if (!unit.empty()) {
|
||||
if (prefix[0] == '\0') out += " ";
|
||||
out += unit;
|
||||
}
|
||||
if (!unit.empty()) out += " "; // the space separates the number from its unit, nothing else
|
||||
out += prefix;
|
||||
out += unit;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user