fix(resample): 重采样间隔/频率按真实值显示(次级单位与频率保留三位小数)
问题(用户实测 MF4-Record.MF4 / m_MOT_Current_DCom[0]): - 最小数据间隔真实值 0.003696631s,却被显示成 3ms 700us(us 部分被向上截取); - 对应频率真实值 270.516586589Hz,却被显示成 270.27Hz; - 最大数据间隔 0.016182614s 显示成 16ms 200us、频率显示成 61.7284Hz,同样不准。 根因(两个,同一个坑): 1. RoundIntervalForDisplay() 把间隔先舍入到 3 位有效数字(0.003696631 -> 0.0037), 次级单位因此变成 700us,真实尾数被抹掉; 2. 频率用舍入后的 3.70ms 换算得 270.27Hz,而输入框用原值得 270.517Hz,两处不一致。 修法(一律使用真实值,舍入只发生在输出文本的最后一步): - Utf8Util 新增 FormatDecimalFixed(value, decimals=3):固定小数位、保留尾随 0、 绝不出现科学计数法; - Utf8Util 新增 FormatSubUnit(value, maxDecimals):带小数才补到 3 位,整数不加小数点 (5.06s -> 5s 60ms,而不是 5s 60.000ms); - FormatDurationCompound 的两处次级单位(s+ms、ms/us/ns)改用它; - FormatFrequency 改为 FormatDecimalFixed(scaled, 3);若保留 3 位后变成 0.000 (超低频,如 1/3662s ≈ 0.27mHz)则退回 FormatDecimal,避免有意义的值显示成 0; - PlotViewInternal.hpp 删除 RoundIntervalForDisplay,FormatIntervalText 直接用真实值; - PlotViewPaint.cpp 的统计行尾缀与频率输入框都用真实 interval 换算。 修复后的显示: min interval 0.003696631s -> 3ms 696.631us frequency 1/0.003696631 -> 270.517 Hz max interval 0.016182614s -> 16ms 182.614us frequency 1/0.016182614 -> 61.795 Hz 同时撤销了此前两次仅修改 agent_mem.md 的提交(47b1213 / caa035a,内容为乱码且无有效信息), 并按正确编码重新整理本轮记忆章节。 面板仍为四行(最大间隔 / 最小间隔 / 重采样间隔 / 重采样频率),未改动任何 UI 布局。 make release 零 warning。
This commit is contained in:
1 parent
9fdbf49841
commit
c4300bd0e1
6 files changed
+260
-43
No files matched your search
@@ -31,6 +31,48 @@ namespace jdi
|
||||
double scale = 1.0; /**< 1 个该单位等于多少秒。 */
|
||||
const wchar_t* name = L"s"; /**< 单位名称。 */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 复合单位时间文本里**次级单位最多保留的小数位数**。
|
||||
*
|
||||
* 用户 2026-11-03 明确要求:`0.003696631s` 必须显示为 `3ms 696.631us`
|
||||
* (次级单位 ms/us/ns 保留三位小数,能看到真实尾数),
|
||||
* 而不是四舍五入到 `3ms 700us`(旧实现舍入到 3 位**有效数字**,把尾数抹掉了)。
|
||||
*
|
||||
* ⚠️ 这是**上限**,不是强制的固定位数:整数次级单位仍写成整数
|
||||
* (`5.06s` → `5s 60ms`,而不是 `5s 60.000ms`),只有真的带小数时才补零到 3 位。
|
||||
*/
|
||||
constexpr int kDurationSubUnitDecimals = 3;
|
||||
|
||||
/**
|
||||
* @brief 频率文本保留的小数位数(用户 2026-11-03 要求)。
|
||||
*
|
||||
* `270.516586...Hz` 必须显示为 `270.517 Hz`(真实值保留三位小数),
|
||||
* 而不是"先把间隔舍入到 3 位有效数字再换算"得到的 `270.27 Hz`。
|
||||
*/
|
||||
constexpr int kFrequencyDecimals = 3;
|
||||
|
||||
/**
|
||||
* @brief 格式化次级单位数值:带小数则保留 `maxDecimals` 位,整数则原样输出。
|
||||
*
|
||||
* `696.6314` → `696.631`;`60.0` → `60`;`0.0158` → `0.016`。
|
||||
* 这样既满足"次级单位保留三位小数"(看得到真实尾数),
|
||||
* 又不会把整数次级单位写成 `60.000` 这种噪音。
|
||||
*/
|
||||
inline std::wstring FormatSubUnit(double value, int maxDecimals)
|
||||
{
|
||||
if (!std::isfinite(value))
|
||||
{
|
||||
return L"—";
|
||||
}
|
||||
const double rounded = std::round(value * std::pow(10.0, maxDecimals)) /
|
||||
std::pow(10.0, maxDecimals);
|
||||
if (rounded == std::floor(rounded))
|
||||
{
|
||||
return FormatDecimal(rounded); // 整数:不加小数点
|
||||
}
|
||||
return FormatDecimalFixed(rounded, maxDecimals);
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring Utf8ToWide(const char* text, int length)
|
||||
@@ -412,8 +454,38 @@ namespace jdi
|
||||
return text;
|
||||
}
|
||||
|
||||
std::wstring FormatDurationCompound(double seconds)
|
||||
std::wstring FormatDecimalFixed(double value, int decimals)
|
||||
{
|
||||
if (std::isnan(value))
|
||||
{
|
||||
return L"NaN";
|
||||
}
|
||||
if (std::isinf(value))
|
||||
{
|
||||
return (value > 0.0) ? L"+Inf" : L"-Inf";
|
||||
}
|
||||
if (decimals < 0)
|
||||
{
|
||||
decimals = 0;
|
||||
}
|
||||
if (decimals > 12)
|
||||
{
|
||||
decimals = 12;
|
||||
}
|
||||
// ⚠️ 固定小数位数 + **保留尾随 0**(与 `FormatDecimal` 的"去尾随 0"语义相反):
|
||||
// 用户 2026-11-03 明确要求「次级单位保留三位小数」,例如 696.631us / 700.000us。
|
||||
wchar_t buffer[160];
|
||||
swprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), L"%.*f", decimals, value);
|
||||
std::wstring text(buffer);
|
||||
if (text == L"-0" || (text.size() > 1 && text[0] == L'-' &&
|
||||
text.find_first_not_of(L"0-.") == std::wstring::npos))
|
||||
{
|
||||
text.erase(0, 1); // -0.000 → 0.000
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
std::wstring FormatDurationCompound(double seconds) {
|
||||
if (!std::isfinite(seconds))
|
||||
{
|
||||
return L"—";
|
||||
@@ -477,7 +549,9 @@ namespace jdi
|
||||
if (remainderMs >= 1.0e-6)
|
||||
{
|
||||
text += L" ";
|
||||
text += FormatDecimal(remainderMs);
|
||||
// ⚠️ 次级单位(ms)**最多保留三位小数**(用户 2026-11-03 要求:`3ms 696.631us`
|
||||
// 这类显示要能看到真实尾数);整数则不加小数点(`5.06s` → `5s 60ms`)。
|
||||
text += FormatSubUnit(remainderMs, kDurationSubUnitDecimals);
|
||||
text += L"ms";
|
||||
}
|
||||
return text;
|
||||
@@ -522,7 +596,9 @@ namespace jdi
|
||||
if (inNext >= 1.0e-6)
|
||||
{
|
||||
text += L" ";
|
||||
text += FormatDecimal(inNext);
|
||||
// ⚠️ 次级单位**最多保留三位小数**(用户 2026-11-03 要求):
|
||||
// `0.003696631s` → 顶级 `3ms` + 次级 `696.631us`(而不是 `3ms 700us`)。
|
||||
text += FormatSubUnit(inNext, kDurationSubUnitDecimals);
|
||||
text += subUnits[index + 1].name;
|
||||
}
|
||||
return text;
|
||||
@@ -563,7 +639,16 @@ namespace jdi
|
||||
}
|
||||
// ⚠️ 频率同样不得出现科学计数法(用户 2026-11-03 要求):
|
||||
// `FormatValue` 的 `%.6g` 在 1e-5 Hz 这类量级会输出 “1e-06”,改为十进制形式。
|
||||
return FormatDecimal(scaled) + L" " + unit;
|
||||
// ⚠️ 并且**基于真实值保留三位小数**(用户 2026-11-03 要求:`270.517 Hz` 而不是
|
||||
// `270.27 Hz`)—— 旧实现把间隔先舍入到 3 位有效数字再换算,把真实尾数抹掉了。
|
||||
// ⚠️ 但若保留 3 位后整串变成 `0.000`(超低频,例如 1/3662s ≈ 0.27mHz),
|
||||
// 则退回按「有效数字」显示,避免把有意义的数值显示成 0(用户 2026-11-03)。
|
||||
const std::wstring fixedText = FormatDecimalFixed(scaled, kFrequencyDecimals);
|
||||
if (std::fabs(scaled) > 0.0 && std::fabs(scaled) < 0.5 * std::pow(10.0, -kFrequencyDecimals))
|
||||
{
|
||||
return FormatDecimal(scaled) + L" " + unit;
|
||||
}
|
||||
return fixedText + L" " + unit;
|
||||
}
|
||||
|
||||
std::wstring FormatByteSize(unsigned long long bytes)
|
||||
|
||||
Reference in new issue
Block a user