MonitorHarmony 数据处理示例
metrics.mjs 是不依赖设备 API 的教学用 JavaScript 模块,解释本文涉及的单位、新鲜度、摘要窗口和 FPS 样本统计;它不包含 HDC 客户端、采集服务、完整 ArkTS UI,也不是可直接安装的监控应用。
import { summaryWindow, summarizeFps } from './metrics.mjs';
const window = summaryWindow(record.samples, 5000);
const summary = window.insufficient ? null : summarizeFps(window.samples);
record 来自实际会话 JSON。模块返回 null 表示没有有效指标;原应用内部使用 -1 哨兵,两者语义相同。
summaryWindow 不修改原数组;这里额外排序以便独立消费者安全使用。summarizeFps 统计采样窗口内的 FPS 值,而不是逐帧时长。低帧 5% 取 max(1, floor(N×0.05)) 个最低有效样本的算术平均,标准差使用总体公式。
电池功率输入单位为微伏与毫安,输出瓦;返回功率幅值,不含充放电方向。
文件
/** Educational helpers derived from MonitorHarmony's unit and window rules. */
export function batteryPowerWatts(voltageMicroV, currentMilliA) {
if (!Number.isFinite(voltageMicroV) || voltageMicroV <= 0 ||
!Number.isFinite(currentMilliA)) return null;
const watts = Math.abs(voltageMicroV * currentMilliA) / 1e9;
return Number.isFinite(watts) && watts <= 100 ? watts : null;
}
export function freshValue(value, updatedAt, now, maxAgeMs = 3500) {
if (![value, updatedAt, now, maxAgeMs].every(Number.isFinite)) return null;
if (value < 0 || updatedAt <= 0 || maxAgeMs < 0) return null;
const age = now - updatedAt;
return age >= 0 && age <= maxAgeMs ? value : null;
}
export function summaryWindow(samples, trimMs = 5000) {
if (!Number.isFinite(trimMs) || trimMs < 0) throw new RangeError('trimMs');
const ordered = samples.filter(s => Number.isFinite(s.timestamp))
.slice().sort((a, b) => a.timestamp - b.timestamp);
if (ordered.length < 2) return { samples: [], insufficient: true };
const startAt = ordered[0].timestamp + trimMs;
const endAt = ordered[ordered.length - 1].timestamp - trimMs;
const selected = endAt > startAt
? ordered.filter(s => s.timestamp >= startAt && s.timestamp <= endAt) : [];
return { startAt, endAt, samples: selected, insufficient: selected.length < 2 };
}
export function summarizeFps(samples) {
const values = samples.map(s => s.fps).filter(v => Number.isFinite(v) && v >= 0);
if (!values.length) return null;
const average = values.reduce((a, b) => a + b, 0) / values.length;
const variance = values.reduce((a, b) => a + (b - average) ** 2, 0) / values.length;
const sorted = values.slice().sort((a, b) => a - b);
const lowCount = Math.max(1, Math.floor(sorted.length * 0.05));
return {
count: values.length,
average,
min: sorted[0],
max: sorted[sorted.length - 1],
standardDeviation: Math.sqrt(variance),
atLeast45Percent: values.filter(v => v >= 45).length * 100 / values.length,
lowFivePercentSampleAverage: sorted.slice(0, lowCount).reduce((a, b) => a + b, 0) / lowCount
};
}