Search code examples
lightningchart

Waveform jitter occurs after a certain time


My expectation is that the waveform to remain stable for a long time without jitter when the project runs for a long time.

My problem is that after running my project for about 20 minutes, a waveform jitter appears, as shown below.

Run for a few minutes.

Run for about twenty minutes.

But only sine waves seem to wobble, not straight lines and square waves.

Another problem that happens at the same time is that the X-axis doesn't scale properly, and at a certain range you can't zoom in anymore, and you can see that the X-axis starts and ends quite a long way off. And I'm not putting any restrictions on the interaction properties.

My environment: Chrome(version 113.0.5672.127), windows 10, lcjs(4.2.0), node(14.21.3)

I tried different frequencies(dataPointsPerSecond). I found that the jitter appeared later at lower frequencies.

After the waveform wobbled, I tried to store the X-axis coordinates of the current data and reset it to start at 0. Then the waveform returns to normal, and so does the X-axis scale. But when I restored the stored X-axis, the problem reappeared.

I tried different "AxisTickStrategies" like "Numeric" and "Time".

I also tried these properties:

.ChartXY({
  container: `${this.chartId}`,
  theme: this.$myTheme,
  antialias: true,
  lineAntiAlias: true,
  webgl: {
    version: "webgl2"
  }
})

The code I use in this example is as follows.


const lcjs = require('@arction/lcjs');
const DATA_FREQUENCY_HZ = 10000
const {
    lightningChart,
    AxisTickStrategies,
    AxisScrollStrategies,
    synchronizeAxisIntervals,
    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) }));

const axisX = chart
    .getDefaultAxisX()
    .setAnimationsEnabled(false)
    .setOverlayStyle(axisStyleHighlight)
    .setNibOverlayStyle(axisStyleHighlight)
    .setScrollStrategy(AxisScrollStrategies.progressive)
    .setTitle('Time')
    .setTickStrategy(AxisTickStrategies.Time)
    .setInterval({ start: 0, end: 2000, animate: false, stopAxisAfter: false }); // 0, this.xIntervalDefault

const axisY = chart
    .getDefaultAxisY()
    .setAnimationsEnabled(false)
    .setOverlayStyle(axisStyleHighlight)
    .setNibOverlayStyle(axisStyleHighlight)
    .setScrollStrategy(AxisScrollStrategies.fitting)
    .setTitle('Amplitude')
    .setInterval({ start: -1, end: 1, animate: false, stopAxisAfter: false });

const series = chart
    .addLineSeries({
        dataPattern: { pattern: 'ProgressiveX' },
        automaticColorIndex: 0
    })
    .setName(`Channel 1`)
    .setDataCleaning({ minDataPointCount: 10000 })
    .setStrokeStyle(style => style.setThickness(2));

// Add legend
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('');

// Generate data sets that are repeated for each channel for demonstration purposes.
const dataSets = [
    { length: Math.ceil(400 * Math.PI), func: (x) => 8 * Math.sin(x / 100) },  // sine wave
    // { length: Math.ceil(400 * Math.PI), func: (x) => 1 }, // Straight line
    // { length: Math.ceil(400 * Math.PI), func: (x) =>  Math.sign(Math.sin(x/10)) }, // Square wave
].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]

// Stream data into series.
let tStart = window.performance.now();
let pushedDataCount = 0;
let step = 0.1
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); // Add max 1000 data points per frame into a series. This prevents massive performance spikes when switching tabs for long times

    const newDataPoints = [];
    for (let iDp = 0; iDp < newDataPointsCount; iDp++) {
        const x = (pushedDataCount + iDp) * step;
        const iData = (pushedDataCount + iDp) % dataSet.length;
        const y = dataSet[iData];
        const point = { x, y };
        newDataPoints.push(point);
    }
    // console.log(newDataPoints);
    series.add(newDataPoints)
    pushedDataCount += newDataPointsCount;
    requestAnimationFrame(streamData);
};
streamData();

I would appreciate it if someone could tell me why this problem is happening and how to fix it. Thank you all!


Solution

  • Well, It seems that the following property when creating ChartXY solved this problem. defaultAxisX: {type: 'linear-highPrecision'} in AxisOptions.