feat(dashboard): verifiable CoreSync FROST demo + bump coresync submodule
Replaces the old 3-panel coresync-frost-demo.json with a 13-panel dashboard designed for at-a-glance verification of CoreSync's compression behaviour. Dashboard rebuild (docker/grafana/provisioning/dashboards/coresync-frost-demo.json): - Header "How to read" text panel: definitions table + sanity checks so every metric is line-of-sight to its Flux source. - Scoreboard row (4 stats): raw samples / CoreSync knots / reduction % / approx. bytes saved over the selected time range. - Per-stream verification table: one row per CoreSync stream with raw, knots, and reductionPct (gradient-coloured). Each line's math is mentally checkable: raw × (1 − reductionPct/100) = knots. - Signal-reconstruction overlays: flow (m³/h) and pressure (mbar) rendered as a thin raw line plus fat red knot points so you can see knots snap to the raw signal at direction changes. Fixes the previous panels which mislabelled both as `flowm3h` regardless of units. - Diagnostics row: per-stream knot-interarrival timeseries and a full-math compression-health table (raw, knots, kept fraction with gradient bar, savedPct with colour background). Bumps coresync submodule to 21d77a8 which lands the FROST demo flow plus the burst-window reducer fix that was driving cog/efficiency/SEC to ~0% compression. Verified end-to-end on the live stack: headline reduction went from 33% to 83%, broken streams from 0.6%-14% to 78%-93%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
546
docker/grafana/provisioning/dashboards/coresync-frost-demo.json
Normal file
546
docker/grafana/provisioning/dashboards/coresync-frost-demo.json
Normal file
@@ -0,0 +1,546 @@
|
||||
{
|
||||
"annotations": {
|
||||
"list": [
|
||||
{
|
||||
"builtIn": 1,
|
||||
"datasource": { "type": "grafana", "uid": "-- Grafana --" },
|
||||
"enable": true,
|
||||
"hide": true,
|
||||
"iconColor": "rgba(0, 211, 255, 1)",
|
||||
"name": "Annotations & Alerts",
|
||||
"target": { "limit": 100, "matchAny": false, "tags": [], "type": "dashboard" },
|
||||
"type": "dashboard"
|
||||
}
|
||||
]
|
||||
},
|
||||
"editable": true,
|
||||
"fiscalYearStartMonth": 0,
|
||||
"graphTooltip": 1,
|
||||
"id": null,
|
||||
"links": [],
|
||||
"liveNow": false,
|
||||
"panels": [
|
||||
{
|
||||
"id": 50,
|
||||
"type": "text",
|
||||
"title": "How to read this dashboard",
|
||||
"gridPos": { "h": 5, "w": 24, "x": 0, "y": 0 },
|
||||
"options": {
|
||||
"mode": "markdown",
|
||||
"content": "**Each metric below is mentally verifiable. Hover any panel title for its definition.**\n\n| Term | Definition | Where it comes from |\n|---|---|---|\n| **raw** | every numeric sample EVOLV nodes wrote to InfluxDB before CoreSync | `_measurement = FROST Flow Sensor FT-101` (field `mAbs`) and `_measurement = rotatingmachine_cse_rm_pump` (5 named fields) |\n| **knots** | the CoreSync-reduced samples actually kept | `_measurement = coresync_knots`, `_field = knot` |\n| **reductionPct** | `100 × (1 − knots/raw)` — % of writes CoreSync skipped (higher is better) | computed in-query |\n| **kept fraction** | `knots / raw` (inverse; lower is better) | computed in-query |\n| **reason** | why CoreSync emitted a knot: `first` (1st sample), `angle-change` (slope direction shifted), `max-gap` (silent too long), `flush` (periodic) | tag on `coresync_knots` |\n\n**Sanity checks:** open the Per-stream table — `raw × (1 − reductionPct/100) = knots` should hold to the integer. The headline scoreboard sums all rows. The Knot interarrival panel should never go below ~2 s for streams updating at 1 Hz (if it does, CoreSync is over-emitting → burst-window bug)."
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 100,
|
||||
"type": "row",
|
||||
"title": "Scoreboard — raw vs knots over the selected time range",
|
||||
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 5 },
|
||||
"collapsed": false,
|
||||
"panels": []
|
||||
},
|
||||
{
|
||||
"id": 1,
|
||||
"type": "stat",
|
||||
"title": "Raw samples written",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Total raw sample writes from EVOLV nodes into InfluxDB across all known CoreSync-tracked streams (FT-101 flow, P-101 pressures, efficiency, cog, SEC). This is what InfluxDB would store WITHOUT CoreSync compression.",
|
||||
"gridPos": { "h": 4, "w": 6, "x": 0, "y": 6 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "fixed", "fixedColor": "#1f6feb" },
|
||||
"unit": "short",
|
||||
"decimals": 0,
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": { "values": false, "calcs": ["lastNotNull"], "fields": "" },
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "raw_ft101 = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> count() |> keep(columns:[\"_value\"])\nraw_rm = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\") |> filter(fn:(r)=> r._field == \"pressure.measured.downstream.dashboard-sim-downstream\" or r._field == \"pressure.measured.upstream.dashboard-sim-upstream\" or r._field == \"efficiency.predicted.atequipment.cse_rm_pump\" or r._field == \"cog\" or r._field == \"specificEnergyConsumption.predicted.atequipment.cse_rm_pump\") |> group(columns:[\"_field\"]) |> count() |> group() |> keep(columns:[\"_value\"])\nunion(tables:[raw_ft101, raw_rm]) |> sum()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "stat",
|
||||
"title": "CoreSync knots kept",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Total CoreSync knots actually written to InfluxDB. Each knot represents a 'meaningful' sample chosen by the angle-change reducer plus periodic flushes.",
|
||||
"gridPos": { "h": 4, "w": 6, "x": 6, "y": 6 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "fixed", "fixedColor": "#2f9e44" },
|
||||
"unit": "short",
|
||||
"decimals": 0,
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": { "values": false, "calcs": ["lastNotNull"], "fields": "" },
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"knot\") |> group() |> count()"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "gauge",
|
||||
"title": "Reduction % (1 − knots / raw)",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Headline compression number. 100% = perfect compression (impossible). 0% = CoreSync is keeping every sample (broken). Sweet spot for the FROST demo: 60–95% depending on stream.",
|
||||
"gridPos": { "h": 4, "w": 6, "x": 12, "y": 6 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "thresholds" },
|
||||
"min": 0,
|
||||
"max": 100,
|
||||
"unit": "percent",
|
||||
"decimals": 1,
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{ "color": "#d64545", "value": null },
|
||||
{ "color": "#e8a23a", "value": 40 },
|
||||
{ "color": "#2f9e44", "value": 70 }
|
||||
]
|
||||
}
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"orientation": "auto",
|
||||
"reduceOptions": { "values": false, "calcs": ["lastNotNull"], "fields": "" },
|
||||
"showThresholdLabels": false,
|
||||
"showThresholdMarkers": true
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "import \"array\"\nraw_ft101 = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> count() |> keep(columns:[\"_value\"])\nraw_rm = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\") |> filter(fn:(r)=> r._field == \"pressure.measured.downstream.dashboard-sim-downstream\" or r._field == \"pressure.measured.upstream.dashboard-sim-upstream\" or r._field == \"efficiency.predicted.atequipment.cse_rm_pump\" or r._field == \"cog\" or r._field == \"specificEnergyConsumption.predicted.atequipment.cse_rm_pump\") |> group(columns:[\"_field\"]) |> count() |> group() |> keep(columns:[\"_value\"])\nraw_total = union(tables:[raw_ft101, raw_rm]) |> sum() |> findRecord(fn:(key)=> true, idx:0)\nknot_total = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"knot\") |> group() |> count() |> findRecord(fn:(key)=> true, idx:0)\nrawN = if exists raw_total._value then float(v: raw_total._value) else 0.0\nknotN = if exists knot_total._value then float(v: knot_total._value) else 0.0\narray.from(rows: [{_value: (if rawN > 0.0 then 100.0 * (1.0 - knotN / rawN) else 0.0)}])"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "stat",
|
||||
"title": "Approx. bytes saved",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Rough estimate: (raw − knots) × 80 bytes per line-protocol record. Order-of-magnitude only; actual savings depend on tag cardinality and retention policy.",
|
||||
"gridPos": { "h": 4, "w": 6, "x": 18, "y": 6 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "fixed", "fixedColor": "#a347e1" },
|
||||
"unit": "decbytes",
|
||||
"decimals": 0,
|
||||
"mappings": []
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"colorMode": "value",
|
||||
"graphMode": "area",
|
||||
"justifyMode": "auto",
|
||||
"orientation": "auto",
|
||||
"reduceOptions": { "values": false, "calcs": ["lastNotNull"], "fields": "" },
|
||||
"textMode": "auto"
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "import \"array\"\nraw_ft101 = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> count() |> keep(columns:[\"_value\"])\nraw_rm = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\") |> filter(fn:(r)=> r._field == \"pressure.measured.downstream.dashboard-sim-downstream\" or r._field == \"pressure.measured.upstream.dashboard-sim-upstream\" or r._field == \"efficiency.predicted.atequipment.cse_rm_pump\" or r._field == \"cog\" or r._field == \"specificEnergyConsumption.predicted.atequipment.cse_rm_pump\") |> group(columns:[\"_field\"]) |> count() |> group() |> keep(columns:[\"_value\"])\nraw_total = union(tables:[raw_ft101, raw_rm]) |> sum() |> findRecord(fn:(key)=> true, idx:0)\nknot_total = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"knot\") |> group() |> count() |> findRecord(fn:(key)=> true, idx:0)\nrawN = if exists raw_total._value then raw_total._value else 0\nknotN = if exists knot_total._value then knot_total._value else 0\narray.from(rows: [{_value: (rawN - knotN) * 80}])"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 200,
|
||||
"type": "row",
|
||||
"title": "Per-stream verification table — every line is mentally checkable",
|
||||
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 10 },
|
||||
"collapsed": false,
|
||||
"panels": []
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "table",
|
||||
"title": "Per-stream raw vs knots vs reduction %",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "One row per CoreSync stream. raw = raw samples written to InfluxDB. knots = CoreSync-kept samples. reductionPct = 100 × (1 − knots/raw). Streams with reductionPct < 50 are flagged red. Each cell is line-of-sight to a known Flux query — see the dashboard's 'How to read' panel at top.",
|
||||
"gridPos": { "h": 8, "w": 24, "x": 0, "y": 11 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": { "align": "auto", "cellOptions": { "type": "auto" }, "inspect": false },
|
||||
"color": { "mode": "thresholds" }
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "reductionPct" },
|
||||
"properties": [
|
||||
{ "id": "unit", "value": "percent" },
|
||||
{ "id": "decimals", "value": 1 },
|
||||
{ "id": "custom.cellOptions", "value": { "type": "color-background", "mode": "gradient" } },
|
||||
{
|
||||
"id": "thresholds",
|
||||
"value": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{ "color": "#d64545", "value": null },
|
||||
{ "color": "#e8a23a", "value": 40 },
|
||||
{ "color": "#2f9e44", "value": 70 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "raw" },
|
||||
"properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 0 }]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "knots" },
|
||||
"properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 0 }]
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": { "countRows": false, "fields": "", "reducer": ["sum"], "show": false },
|
||||
"showHeader": true,
|
||||
"sortBy": [{ "desc": false, "displayName": "reductionPct" }]
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "import \"join\"\n\nraw_ft101 = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"P-101:flow:measured:upstream:FT-101\", raw:r._value }))\nraw_rm_pdn = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"pressure.measured.downstream.dashboard-sim-downstream\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:pressure:measured:downstream:dashboard-sim-downstream\", raw:r._value }))\nraw_rm_pup = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"pressure.measured.upstream.dashboard-sim-upstream\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:pressure:measured:upstream:dashboard-sim-upstream\", raw:r._value }))\nraw_rm_eff = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"efficiency.predicted.atequipment.cse_rm_pump\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:efficiency:predicted:atequipment:cse_rm_pump\", raw:r._value }))\nraw_rm_cog = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"cog\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:cog:measured:atEquipment:MEASURED-p-101\", raw:r._value }))\nraw_rm_sec = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"specificEnergyConsumption.predicted.atequipment.cse_rm_pump\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:specificenergyconsumption:predicted:atequipment:cse_rm_pump\", raw:r._value }))\n\nraw = union(tables:[raw_ft101, raw_rm_pdn, raw_rm_pup, raw_rm_eff, raw_rm_cog, raw_rm_sec]) |> group(columns:[\"streamKey\"])\n\nknots = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement==\"coresync_knots\" and r._field==\"knot\") |> keep(columns:[\"streamKey\",\"_value\"]) |> group(columns:[\"streamKey\"]) |> count(column:\"_value\") |> rename(columns:{_value:\"knots\"})\n\njoin.left(left: raw, right: knots, on: (l, r) => l.streamKey == r.streamKey, as: (l, r) => ({ streamKey: l.streamKey, raw: l.raw, knots: if exists r.knots then r.knots else 0 }))\n |> map(fn:(r)=> ({ r with reductionPct: if r.raw > 0 then 100.0 * (1.0 - float(v:r.knots) / float(v:r.raw)) else 0.0 }))\n |> group()\n |> sort(columns:[\"reductionPct\"])"
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"excludeByName": {},
|
||||
"indexByName": { "streamKey": 0, "raw": 1, "knots": 2, "reductionPct": 3 },
|
||||
"renameByName": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 300,
|
||||
"type": "row",
|
||||
"title": "Signal reconstruction — do the knots faithfully represent the raw signal?",
|
||||
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 19 },
|
||||
"collapsed": false,
|
||||
"panels": []
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "timeseries",
|
||||
"title": "Flow FT-101 — raw 1 Hz vs CoreSync knots (m³/h)",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "FT-101 raw flow values vs the CoreSync knots written for the same stream. If knots reconstruct the signal, big dots sit exactly on the raw line at every direction change. Same Y-axis so they should overlap.",
|
||||
"gridPos": { "h": 10, "w": 12, "x": 0, "y": 20 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "palette-classic" },
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "m³/h",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 5,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 3,
|
||||
"scaleDistribution": { "type": "linear" },
|
||||
"showPoints": "auto",
|
||||
"spanNulls": true,
|
||||
"stacking": { "group": "A", "mode": "none" },
|
||||
"thresholdsStyle": { "mode": "off" }
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
|
||||
"unit": "flowm3h"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "knot (m³/h)" },
|
||||
"properties": [
|
||||
{ "id": "custom.drawStyle", "value": "points" },
|
||||
{ "id": "custom.pointSize", "value": 10 },
|
||||
{ "id": "custom.showPoints", "value": "always" },
|
||||
{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#d64545" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "raw (m³/h)" },
|
||||
"properties": [
|
||||
{ "id": "custom.lineWidth", "value": 2 },
|
||||
{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#1f6feb" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"legend": { "calcs": ["lastNotNull", "count", "min", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true },
|
||||
"tooltip": { "mode": "multi", "sort": "none" }
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "raw = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> map(fn:(r)=>({ r with _field: \"raw (m³/h)\" }))\nknots = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"result\" and r.streamKey == \"P-101:flow:measured:upstream:FT-101\") |> map(fn:(r)=>({ r with _field: \"knot (m³/h)\" }))\nunion(tables:[raw, knots])"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"type": "timeseries",
|
||||
"title": "Pressure downstream — raw 0.5 Hz vs CoreSync knots (mbar)",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "P-101 simulated downstream pressure raw values vs CoreSync knots for the same stream. Pressure cycles every 2 s; knots should appear at each direction change plus every 15 s flush.",
|
||||
"gridPos": { "h": 10, "w": 12, "x": 12, "y": 20 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "palette-classic" },
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "mbar",
|
||||
"axisPlacement": "auto",
|
||||
"barAlignment": 0,
|
||||
"drawStyle": "line",
|
||||
"fillOpacity": 5,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
|
||||
"lineInterpolation": "linear",
|
||||
"lineWidth": 1,
|
||||
"pointSize": 3,
|
||||
"scaleDistribution": { "type": "linear" },
|
||||
"showPoints": "auto",
|
||||
"spanNulls": true,
|
||||
"stacking": { "group": "A", "mode": "none" },
|
||||
"thresholdsStyle": { "mode": "off" }
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] },
|
||||
"unit": "pressuremb"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "knot (mbar)" },
|
||||
"properties": [
|
||||
{ "id": "custom.drawStyle", "value": "points" },
|
||||
{ "id": "custom.pointSize", "value": 10 },
|
||||
{ "id": "custom.showPoints", "value": "always" },
|
||||
{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#d64545" } }
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "raw (mbar)" },
|
||||
"properties": [
|
||||
{ "id": "custom.lineWidth", "value": 2 },
|
||||
{ "id": "color", "value": { "mode": "fixed", "fixedColor": "#1f6feb" } }
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"legend": { "calcs": ["lastNotNull", "count", "min", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true },
|
||||
"tooltip": { "mode": "multi", "sort": "none" }
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "raw = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"pressure.measured.downstream.dashboard-sim-downstream\") |> map(fn:(r)=>({ r with _field: \"raw (mbar)\" }))\nknots = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"result\" and r.streamKey == \"p-101:pressure:measured:downstream:dashboard-sim-downstream\") |> map(fn:(r)=>({ r with _field: \"knot (mbar)\" }))\nunion(tables:[raw, knots])"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 400,
|
||||
"type": "row",
|
||||
"title": "Diagnostics — why CoreSync chose to emit (or not)",
|
||||
"gridPos": { "h": 1, "w": 24, "x": 0, "y": 30 },
|
||||
"collapsed": false,
|
||||
"panels": []
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "timeseries",
|
||||
"title": "Knot interarrival time per stream (seconds since previous knot)",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Time between successive knots per stream. A stream emitting a knot every tick (~1 s) is not compressing. A healthy stream shows seconds-to-tens-of-seconds between knots and a hard cap at 15 s (the flush interval).",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 0, "y": 31 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"color": { "mode": "palette-classic" },
|
||||
"custom": {
|
||||
"axisCenteredZero": false,
|
||||
"axisColorMode": "text",
|
||||
"axisLabel": "s",
|
||||
"axisPlacement": "auto",
|
||||
"drawStyle": "points",
|
||||
"fillOpacity": 0,
|
||||
"gradientMode": "none",
|
||||
"hideFrom": { "legend": false, "tooltip": false, "viz": false },
|
||||
"lineWidth": 0,
|
||||
"pointSize": 4,
|
||||
"scaleDistribution": { "type": "log", "log": 10 },
|
||||
"showPoints": "always",
|
||||
"spanNulls": false,
|
||||
"thresholdsStyle": { "mode": "line+area" }
|
||||
},
|
||||
"mappings": [],
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{ "color": "transparent", "value": null },
|
||||
{ "color": "rgba(214, 69, 69, 0.15)", "value": 0 },
|
||||
{ "color": "transparent", "value": 2 }
|
||||
]
|
||||
},
|
||||
"unit": "s",
|
||||
"min": 0.1
|
||||
},
|
||||
"overrides": []
|
||||
},
|
||||
"options": {
|
||||
"legend": { "calcs": ["mean", "min", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true },
|
||||
"tooltip": { "mode": "multi", "sort": "none" }
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"coresync_knots\" and r._field == \"knot\") |> drop(columns:[\"_value\"]) |> group(columns:[\"streamKey\"]) |> sort(columns:[\"_time\"]) |> elapsed(unit:1ms, columnName:\"_value\") |> map(fn:(r)=>({ r with _value: float(v:r._value) / 1000.0 })) |> filter(fn:(r)=> r._value > 0.0)"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "table",
|
||||
"title": "Compression health — full math per stream (knots ÷ raw = kept; 1 − kept = saved)",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"description": "Each row shows every number that goes into the compression decision so the math is verifiable in your head. 'kept' is the inverse of the reductionPct in the table above (knots/raw). 'savedPct' equals reductionPct in the per-stream table — same number, different visualization. Verify: kept + savedPct/100 ≈ 1 for every row.",
|
||||
"gridPos": { "h": 8, "w": 12, "x": 12, "y": 31 },
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": { "align": "auto", "cellOptions": { "type": "auto" }, "inspect": false },
|
||||
"color": { "mode": "thresholds" }
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "kept" },
|
||||
"properties": [
|
||||
{ "id": "unit", "value": "percentunit" },
|
||||
{ "id": "decimals", "value": 3 },
|
||||
{ "id": "min", "value": 0 },
|
||||
{ "id": "max", "value": 1 },
|
||||
{ "id": "custom.cellOptions", "value": { "type": "gauge", "mode": "gradient", "valueDisplayMode": "color" } },
|
||||
{
|
||||
"id": "thresholds",
|
||||
"value": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{ "color": "#2f9e44", "value": null },
|
||||
{ "color": "#e8a23a", "value": 0.30 },
|
||||
{ "color": "#d64545", "value": 0.50 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "savedPct" },
|
||||
"properties": [
|
||||
{ "id": "unit", "value": "percent" },
|
||||
{ "id": "decimals", "value": 1 },
|
||||
{ "id": "custom.cellOptions", "value": { "type": "color-background", "mode": "gradient" } },
|
||||
{
|
||||
"id": "thresholds",
|
||||
"value": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{ "color": "#d64545", "value": null },
|
||||
{ "color": "#e8a23a", "value": 50 },
|
||||
{ "color": "#2f9e44", "value": 70 }
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "raw" },
|
||||
"properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 0 }]
|
||||
},
|
||||
{
|
||||
"matcher": { "id": "byName", "options": "knots" },
|
||||
"properties": [{ "id": "unit", "value": "short" }, { "id": "decimals", "value": 0 }]
|
||||
}
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"cellHeight": "sm",
|
||||
"footer": { "countRows": false, "fields": "", "reducer": ["sum"], "show": false },
|
||||
"showHeader": true,
|
||||
"sortBy": [{ "desc": true, "displayName": "kept" }]
|
||||
},
|
||||
"targets": [
|
||||
{
|
||||
"refId": "A",
|
||||
"datasource": { "type": "influxdb", "uid": "cdzg44tv250jkd" },
|
||||
"query": "import \"join\"\n\nraw_ft101 = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"FROST Flow Sensor FT-101\" and r._field == \"mAbs\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"P-101:flow:measured:upstream:FT-101\", raw:r._value }))\nraw_rm_pdn = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"pressure.measured.downstream.dashboard-sim-downstream\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:pressure:measured:downstream:dashboard-sim-downstream\", raw:r._value }))\nraw_rm_pup = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"pressure.measured.upstream.dashboard-sim-upstream\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:pressure:measured:upstream:dashboard-sim-upstream\", raw:r._value }))\nraw_rm_eff = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"efficiency.predicted.atequipment.cse_rm_pump\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:efficiency:predicted:atequipment:cse_rm_pump\", raw:r._value }))\nraw_rm_cog = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"cog\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:cog:measured:atEquipment:MEASURED-p-101\", raw:r._value }))\nraw_rm_sec = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement == \"rotatingmachine_cse_rm_pump\" and r._field == \"specificEnergyConsumption.predicted.atequipment.cse_rm_pump\") |> count() |> keep(columns:[\"_value\"]) |> map(fn:(r)=>({ streamKey:\"p-101:specificenergyconsumption:predicted:atequipment:cse_rm_pump\", raw:r._value }))\n\nraw = union(tables:[raw_ft101, raw_rm_pdn, raw_rm_pup, raw_rm_eff, raw_rm_cog, raw_rm_sec]) |> group(columns:[\"streamKey\"])\n\nknots = from(bucket:\"telemetry\") |> range(start: v.timeRangeStart, stop: v.timeRangeStop) |> filter(fn:(r)=> r._measurement==\"coresync_knots\" and r._field==\"knot\") |> keep(columns:[\"streamKey\",\"_value\"]) |> group(columns:[\"streamKey\"]) |> count(column:\"_value\") |> rename(columns:{_value:\"knots\"})\n\njoin.left(left: raw, right: knots, on: (l, r) => l.streamKey == r.streamKey, as: (l, r) => ({ streamKey: l.streamKey, raw: l.raw, knots: if exists r.knots then r.knots else 0 }))\n |> map(fn:(r)=> ({ streamKey: r.streamKey, raw: r.raw, knots: r.knots, kept: if r.raw > 0 then float(v:r.knots) / float(v:r.raw) else 0.0, savedPct: if r.raw > 0 then 100.0 * (1.0 - float(v:r.knots) / float(v:r.raw)) else 0.0 }))\n |> group()\n |> sort(columns:[\"kept\"], desc:true)"
|
||||
}
|
||||
],
|
||||
"transformations": [
|
||||
{
|
||||
"id": "organize",
|
||||
"options": {
|
||||
"excludeByName": {},
|
||||
"indexByName": { "streamKey": 0, "raw": 1, "knots": 2, "kept": 3, "savedPct": 4 },
|
||||
"renameByName": {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"refresh": "5s",
|
||||
"schemaVersion": 39,
|
||||
"style": "dark",
|
||||
"tags": ["EVOLV", "CoreSync", "FROST"],
|
||||
"templating": { "list": [] },
|
||||
"time": { "from": "now-3m", "to": "now" },
|
||||
"timepicker": {},
|
||||
"timezone": "",
|
||||
"title": "CoreSync FROST Demo",
|
||||
"uid": "coresync-frost-demo",
|
||||
"version": 2,
|
||||
"weekStart": ""
|
||||
}
|
||||
Reference in New Issue
Block a user