diff --git a/chart-realtime/build.gradle.kts b/chart-realtime/build.gradle.kts index 908aff5..4a35215 100644 --- a/chart-realtime/build.gradle.kts +++ b/chart-realtime/build.gradle.kts @@ -7,7 +7,7 @@ plugins { } group = "dev.dtrentin" -version = "0.4.1-SNAPSHOT" +version = "0.5.0-SNAPSHOT" kotlin { androidTarget { diff --git a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/LodDecimator.kt b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/LodDecimator.kt index 3dd02ba..b2aa3bc 100644 --- a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/LodDecimator.kt +++ b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/LodDecimator.kt @@ -44,25 +44,11 @@ class LodDecimator( } return when (mode) { - LodMode.MEAN -> decimateMean(n, pixelWidth, outX, outY) LodMode.MIN_MAX -> decimateMinMax(n, pixelWidth, outX, outY) LodMode.LTTB -> decimateLttb(n, pixelWidth, outX, outY) } } - private fun decimateMean(n: Int, pixelWidth: Int, outX: FloatArray, outY: FloatArray): Int { - for (col in 0 until pixelWidth) { bucketSumY[col] = 0.0; bucketCountArr[col] = 0 } - for (i in 0 until n) { bucketSumY[colArr[i]] += valArr[i]; bucketCountArr[colArr[i]]++ } - var outIdx = 0 - for (col in 0 until pixelWidth) { - if (bucketCountArr[col] == 0) continue - outX[outIdx] = col + 0.5f - outY[outIdx] = (bucketSumY[col] / bucketCountArr[col]).toFloat() - outIdx++ - } - return outIdx - } - private fun decimateMinMax(n: Int, pixelWidth: Int, outX: FloatArray, outY: FloatArray): Int { for (col in 0 until pixelWidth) { colMin[col] = Float.MAX_VALUE; colMax[col] = -Float.MAX_VALUE; colHit[col] = false } for (i in 0 until n) { diff --git a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/TieredBuffer.kt b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/TieredBuffer.kt index 1f0079e..12e9d8c 100644 --- a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/TieredBuffer.kt +++ b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/buffer/TieredBuffer.kt @@ -7,12 +7,12 @@ class TieredBuffer { private val tier2 = CircularBuffer(TIER2_CAPACITY) private var tier1BinStartMs = -1L - private var tier1BinSum = 0.0 - private var tier1BinCount = 0 + private var tier1BinMin = Float.MAX_VALUE + private var tier1BinMax = -Float.MAX_VALUE private var tier2BinStartMs = -1L - private var tier2BinSum = 0.0 - private var tier2BinCount = 0 + private var tier2BinMin = Float.MAX_VALUE + private var tier2BinMax = -Float.MAX_VALUE private val t0Ts = LongArray(TIER0_CAPACITY) private val t0Vs = FloatArray(TIER0_CAPACITY) @@ -32,15 +32,17 @@ class TieredBuffer { tier1BinStartMs = (ts / TIER1_BIN_MS) * TIER1_BIN_MS } if (ts >= tier1BinStartMs + TIER1_BIN_MS) { - if (tier1BinCount > 0) { - tier1.push(tier1BinStartMs + TIER1_BIN_MS / 2L, (tier1BinSum / tier1BinCount).toFloat()) + if (tier1BinMin != Float.MAX_VALUE) { + val midTs = tier1BinStartMs + TIER1_BIN_MS / 2L + tier1.push(midTs, tier1BinMin) + tier1.push(midTs, tier1BinMax) } tier1BinStartMs = (ts / TIER1_BIN_MS) * TIER1_BIN_MS - tier1BinSum = value.toDouble() - tier1BinCount = 1 + tier1BinMin = value + tier1BinMax = value } else { - tier1BinSum += value - tier1BinCount++ + if (value < tier1BinMin) tier1BinMin = value + if (value > tier1BinMax) tier1BinMax = value } } @@ -49,15 +51,17 @@ class TieredBuffer { tier2BinStartMs = (ts / TIER2_BIN_MS) * TIER2_BIN_MS } if (ts >= tier2BinStartMs + TIER2_BIN_MS) { - if (tier2BinCount > 0) { - tier2.push(tier2BinStartMs + TIER2_BIN_MS / 2L, (tier2BinSum / tier2BinCount).toFloat()) + if (tier2BinMin != Float.MAX_VALUE) { + val midTs = tier2BinStartMs + TIER2_BIN_MS / 2L + tier2.push(midTs, tier2BinMin) + tier2.push(midTs, tier2BinMax) } tier2BinStartMs = (ts / TIER2_BIN_MS) * TIER2_BIN_MS - tier2BinSum = value.toDouble() - tier2BinCount = 1 + tier2BinMin = value + tier2BinMax = value } else { - tier2BinSum += value - tier2BinCount++ + if (value < tier2BinMin) tier2BinMin = value + if (value > tier2BinMax) tier2BinMax = value } } @@ -115,8 +119,8 @@ class TieredBuffer { fun clear() { tier0.clear(); tier1.clear(); tier2.clear() - tier1BinStartMs = -1L; tier1BinSum = 0.0; tier1BinCount = 0 - tier2BinStartMs = -1L; tier2BinSum = 0.0; tier2BinCount = 0 + tier1BinStartMs = -1L; tier1BinMin = Float.MAX_VALUE; tier1BinMax = -Float.MAX_VALUE + tier2BinStartMs = -1L; tier2BinMin = Float.MAX_VALUE; tier2BinMax = -Float.MAX_VALUE } companion object { @@ -132,8 +136,8 @@ class TieredBuffer { const val TIER2_BIN_MS = 1000L / TIER2_HZ val TIER0_CAPACITY = ((TIER0_DURATION_MS / 1000L) * TIER0_MAX_HZ).toInt() - val TIER1_CAPACITY = ((TIER1_DURATION_MS / 1000L) * TIER1_HZ).toInt() - val TIER2_CAPACITY = ((TIER2_DURATION_MS / 1000L) * TIER2_HZ).toInt() + val TIER1_CAPACITY = ((TIER1_DURATION_MS / 1000L) * TIER1_HZ).toInt() * 2 + val TIER2_CAPACITY = ((TIER2_DURATION_MS / 1000L) * TIER2_HZ).toInt() * 2 val TOTAL_CAPACITY = TIER0_CAPACITY + TIER1_CAPACITY + TIER2_CAPACITY } } diff --git a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/ChartConfig.kt b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/ChartConfig.kt index 5025657..5dcca9d 100644 --- a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/ChartConfig.kt +++ b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/ChartConfig.kt @@ -22,5 +22,5 @@ data class ChartConfig( val yLabelMode: AxisLabelMode = AxisLabelMode.INSIDE, val yLabelDecimals: Int = 2, val xLabelDecimals: Int = 1, - val lodMode: LodMode = LodMode.LTTB, + val lodMode: LodMode = LodMode.MIN_MAX, ) diff --git a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/LodMode.kt b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/LodMode.kt index 11fe8bd..10f777e 100644 --- a/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/LodMode.kt +++ b/chart-realtime/src/commonMain/kotlin/dev/dtrentin/chart/model/LodMode.kt @@ -1,3 +1,3 @@ package dev.dtrentin.chart.model -enum class LodMode { MEAN, MIN_MAX, LTTB } +enum class LodMode { MIN_MAX, LTTB }