LCJS波形运行20分钟后抖动及X轴缩放异常排查求助
问题原因
- 浮点数精度累积误差:JavaScript的64位双精度浮点数无法精确表示所有小数(例如0.1),随着运行时间增加,
x = (pushedDataCount + iDp) * 0.1的累积计算会产生越来越大的精度偏差。正弦波对X轴的连续性和精度敏感,这种偏差会导致波形相位偏移,表现为抖动;而直线、方波因Y值变化特性,精度偏差的视觉影响不明显。 - X轴区间计算异常:X轴数值精度丢失后,LCJS内部的轴区间计算、缩放逻辑会出现误差,导致无法正常放大、轴起止范围偏离预期。
修复方案
方案1:避免浮点数累积,改用整数X基准+轴格式化
将X轴数据改为整数计数,通过轴的格式化函数将整数转换为时间显示,彻底避免浮点数累加误差。
修改代码示例:
const lcjs = require('@arction/lcjs'); const DATA_FREQUENCY_HZ = 10000 const { lightningChart, AxisTickStrategies, AxisScrollStrategies, UIOrigins, UIDraggingModes, SolidFill, ColorRGBA, SolidLine, Themes } = lcjs; const axisStyleHighlight = new SolidFill({ color: ColorRGBA(255, 255, 255, 0) }); const chart = lightningChart() .ChartXY({ theme: Themes.light }) .setPadding({ left: 0, right: 90, top: 20, bottom: 0 }) .setTitle('') .setBackgroundFillStyle(new SolidFill({ color: ColorRGBA(255, 255, 255) })); // 修改X轴配置:用整数基准+自定义格式化 const axisX = chart .getDefaultAxisX() .setAnimationsEnabled(false) .setOverlayStyle(axisStyleHighlight) .setNibOverlayStyle(axisStyleHighlight) .setScrollStrategy(AxisScrollStrategies.progressive) .setTitle('Time') .setTickStrategy(AxisTickStrategies.Numeric, (tickStrategy) => tickStrategy.setFormattingFunction((value) => { // 将整数X值转换为秒显示(对应原0.1的step逻辑) const seconds = (value * 0.1) / 1000; return `${seconds.toFixed(2)}s`; }) ) .setInterval({ start: 0, end: 20000, animate: false, stopAxisAfter: false }); const axisY = chart .getDefaultAxisY() .setAnimationsEnabled(false) .setOverlayStyle(axisStyleHighlight) .setNibOverlayStyle(axisStyleHighlight) .setScrollStrategy(AxisScrollStrategies.fitting) .setTitle('Amplitude') .setInterval({ start: -8, end: 8, animate: false, stopAxisAfter: false }); // 适配正弦波y值范围 const series = chart .addLineSeries({ dataPattern: { pattern: 'ProgressiveX' }, automaticColorIndex: 0 }) .setName(`Channel 1`) .setDataCleaning({ minDataPointCount: 10000 }) .setStrokeStyle(style => style.setThickness(2)); // 图例配置不变 const legend = chart .addLegendBox() .add(chart) .setDraggingMode(UIDraggingModes.notDraggable) .setPosition({ x: 100, y: 100 }) .setOrigin(UIOrigins.RightTop) .setMargin({ right: 5, top: 20.3 }) .setPadding({ left: 3, right: 0, top: 0, bottom: 0 }) .setEntries((entry, component) => entry .setButtonOnStrokeStyle( new SolidLine({ thickness: 1, fillStyle: new SolidFill({ color: ColorRGBA(0, 0, 0) }) }) ) .setTextFont(font => font.setSize(11)) ) .setTitle(''); // 数据集不变 const dataSets = [ { length: Math.ceil(400 * Math.PI), func: (x) => 8 * Math.sin(x / 100) }, ].map((config) => { const data = [] data.length = config.length for (let i = 0; i < config.length; i += 1) { const y = config.func(i) data[i] = y } return data }) const dataSet = dataSets[0] // 修改数据流逻辑:用整数X值 let tStart = window.performance.now(); let pushedDataCount = 0; const streamData = () => { const tNow = window.performance.now(); const shouldBeDataPointsCount = Math.floor((DATA_FREQUENCY_HZ * (tNow - tStart)) / 1000); const newDataPointsCount = Math.min(shouldBeDataPointsCount - pushedDataCount, DATA_FREQUENCY_HZ); const newDataPoints = []; for (let iDp = 0; iDp < newDataPointsCount; iDp++) { const x = pushedDataCount + iDp; // 整数X值,避免浮点数累积 const iData = (pushedDataCount + iDp) % dataSet.length; const y = dataSet[iData]; const point = { x, y }; newDataPoints.push(point); } series.add(newDataPoints) pushedDataCount += newDataPointsCount; requestAnimationFrame(streamData); }; streamData();
方案2:定期重置数据累积基准
当累积的数据点达到一定阈值时,重置计数基准并更新X轴偏移量,保证视觉上波形连续,避免数值过大导致精度丢失。
核心修改代码:
// 添加重置阈值和偏移量 const MAX_DATA_POINTS_BEFORE_RESET = 1000000; let xOffset = 0; // 初始化X轴区间 const axisX = chart .getDefaultAxisX() // ... 其他配置不变 .setInterval({ start: xOffset, end: xOffset + 2000, animate: false, stopAxisAfter: false }); const streamData = () => { const tNow = window.performance.now(); const shouldBeDataPointsCount = Math.floor((DATA_FREQUENCY_HZ * (tNow - tStart)) / 1000); const newDataPointsCount = Math.min(shouldBeDataPointsCount - pushedDataCount, DATA_FREQUENCY_HZ); const newDataPoints = []; for (let iDp = 0; iDp < newDataPointsCount; iDp++) { const x = xOffset + (pushedDataCount + iDp) * 0.1; // 叠加偏移量 const iData = (pushedDataCount + iDp) % dataSet.length; const y = dataSet[iData]; const point = { x, y }; newDataPoints.push(point); } series.add(newDataPoints) pushedDataCount += newDataPointsCount; // 达到阈值时重置 if (pushedDataCount >= MAX_DATA_POINTS_BEFORE_RESET) { pushedDataCount = 0; tStart = tNow; xOffset += MAX_DATA_POINTS_BEFORE_RESET * 0.1; // 更新X轴区间保持显示窗口一致 axisX.setInterval({ start: xOffset, end: xOffset + 2000, animate: false, stopAxisAfter: false }); } requestAnimationFrame(streamData); };
方案3:升级LCJS版本
当前使用的LCJS 4.2.0版本较旧,后续版本(v5.x及以上)针对大数值轴的精度处理、波形渲染做了优化,升级到最新稳定版可能直接解决该问题。
内容的提问来源于stack exchange,提问作者Calix
相关产品推荐
相关产品推荐

