物联网传感器常见问题
以下场景展示了用于提取IoT传感器数据的信息的常见查询:
以下所有场景使用 machineProduction 示例数据集,该数据集由 InfluxDB sample 包 提供。有关更多信息,请参见 示例数据。
计算状态中的时间
在这种情况下,我们查看生产线是否顺利运行 (state=OK),以及生产线顺利运行或不顺利运行的时间百分比 (state=NOK)。如果在该时间段内没有记录任何数据 (state=NaN),您可以选择检索该时间段之前的最后状态。
要可视化状态时间,请参见 Mosaic visualization。
计算机器在每个状态下花费的时间百分比
- 导入
contrib/tomhollingworth/events包。 - 查询
state字段。 - 使用
events.duration()返回每个数据点之间的时间量(以指定单位),并将间隔存储在duration列中。 - 按状态值列分组(在这种情况下是
_value)、_start、_stop和其他相关维度。 - 对
duration列求和以计算在每个状态下花费的总时间。 - 将汇总的持续时间转换为
_value列。 - 使用
map()来计算在每个状态下花费的时间百分比。
import "contrib/tomhollingworth/events"
from(bucket: "machine")
|> range(start: 2021-08-01T00:00:00Z, stop: 2021-08-02T00:30:00Z)
|> filter(fn: (r) => r["_measurement"] == "machinery")
|> filter(fn: (r) => r["_field"] == "state")
|> events.duration(unit: 1h, columnName: "duration")
|> group(columns: ["_value", "_start", "_stop", "station_id"])
|> sum(column: "duration")
|> pivot(rowKey: ["_stop"], columnKey: ["_value"], valueColumn: "duration")
|> map(
fn: (r) => {
totalTime = float(v: r.NOK + r.OK)
return {r with NOK: float(v: r.NOK) / totalTime * 100.0, OK: float(v: r.OK) / totalTime * 100.0}
},
)
上述查询关注于生产线中报告的特定时间范围的状态变化。
range()定义了要查询的时间范围。filter()定义了要过滤的字段 (state) 和测量 (machinery)。events.duration()计算两个点之间的时间。group()按字段值重新分组数据,因此具有OK和NOK字段值的点被分组到不同的表中。sum()返回每个状态花费的持续时间的总和。
此时查询的输出为:
| _值 | 持续时间 |
|---|---|
| 不良 | 22 |
| _值 | 持续时间 |
|---|---|
| 好的 | 172 |
pivot() 为 _value 列中的每个唯一值创建列,然后将相关的持续时间分配为列值。
透视操作的输出是:
| 不合格 | 合格 |
|---|---|
| 22 | 172 |
根据上面的输出, map() 执行以下操作:
- 添加
NOK和OK值以计算totalTime。 - 将
NOK除以totalTime,然后将商乘以 100。 - 将
OK除以totalTime,然后将商乘以 100。
这将返回:
| 不合格 | 合格 |
|---|---|
| 11.34020618556701 | 88.65979381443299 |
结果显示,生产在OK状态下的时间占88.66%,而在NOK状态下的时间占11.34%。
马赛克可视化
马赛克可视化展示了随时间变化的状态。 在这个例子中,马赛克可视化根据state字段显示了不同颜色的瓷砖。
from(bucket: "machine")
|> range(start: 2021-08-01T00:00:00Z, stop: 2021-08-02T00:30:00Z)
|> filter(fn: (r) => r._measurement == "machinery")
|> filter(fn: (r) => r._field == "state")
|> aggregateWindow(every: v.windowPeriod, fn: last, createEmpty: false)
在可视化数据时,数据点的数量可能超过可用像素的数量。要将数据划分为覆盖单个像素的时间窗口,使用 aggregateWindow,并将 every 参数设置为 v.windowPeriod。 使用 last 作为聚合 fn 以返回每个时间窗口中的最后一个值。 将 createEmpty 设置为 false,以便结果不会包括空的时间窗口。
计算时间加权平均
要计算数据点的时间加权平均,使用 timeWeightedAvg() 函数。
下面的示例查询了machinery测量中的oil_temp字段。timeWeightedAvg()函数返回基于5秒间隔的油温的时间加权平均值。
from(bucket: "machine")
|> range(start: 2021-08-01T00:00:00Z, stop: 2021-08-01T00:00:30Z)
|> filter(fn: (r) => r._measurement == "machinery" and r._field == "oil_temp")
|> timeWeightedAvg(unit: 5s)
输出数据
| 站点编号 | 开始时间 | 结束时间 | 数值 |
|---|---|---|---|
| g1 | 2021-08-01T01:00:00.000Z | 2021-08-01T00:00:30.000Z | 40.25396118491921 |
| g2 | 2021-08-01T01:00:00.000Z | 2021-08-01T00:00:30.000Z | 40.6 |
| g3 | 2021-08-01T01:00:00.000Z | 2021-08-01T00:00:30.000Z | 41.384505595567866 |
| g4 | 2021-08-01T01:00:00.000Z | 2021-08-01T00:00:30.000Z | 41.26735518634935 |
计算事件之间的值
通过获取特定时间范围内的平均值来计算事件之间的值。
以下场景查询从四条生产线开始和结束时的数据。 以下查询计算该期间每个磨削站的平均油温。
batchStart = 2021-08-01T00:00:00Z
batchStop = 2021-08-01T00:00:20Z
from(bucket: "machine")
|> range(start: batchStart, stop: batchStop)
|> filter(fn: (r) => r._measurement == "machinery" and r._field == "oil_temp")
|> mean()
输出
| 站点编号 | 开始时间 | 结束时间 | 数值 |
|---|---|---|---|
| g1 | 2021-08-01T01:00:00.000Z | 2021-08-02T00:00:00.000Z | 40 |
| g2 | 2021-08-01T01:00:00.000Z | 2021-08-02T00:00:00.000Z | 40.6 |
| g3 | 2021-08-01T01:00:00.000Z | 2021-08-02T00:00:00.000Z | 41.379999999999995 |
| g4 | 2021-08-01T01:00:00.000Z | 2021-08-02T00:00:00.000Z | 41.2 |
确定一个具有现有值的状态
使用多个现有值来确定状态。
以下示例根据机器生产样本数据中 pressure 和 pressure-target 字段的差异计算状态。
通过比较现有字段来确定状态:
- 查询要比较的字段(在这种情况下,
pressure和pressure_target)。 - (可选) 使用
aggregateWindow()将数据窗口化为基于时间的窗口,并应用聚合函数(如mean())以返回表示更大时间窗口的值。 - 使用
pivot()将字段值转移到列中。 - 使用
map()来比较或操作不同字段列的值。 - 使用
map()来分配状态(在这种情况下,needsMaintenance基于字段列值的关系。
import "math"
from(bucket: "machine")
|> range(start: 2021-08-01T00:00:00Z, stop: 2021-08-02T00:00:00Z)
|> filter(fn: (r) => r["_measurement"] == "machinery")
|> filter(fn: (r) => r["_field"] == "pressure" or r["_field"] == "pressure_target")
|> aggregateWindow(every: 12h, fn: mean)
|> pivot(rowKey:["_time"], columnKey: ["_field"], valueColumn: "_value")
|> map(fn: (r) => ({ r with pressureDiff: r.pressure - r.pressure_target }))
|> map(fn: (r) => ({ r with needsMaintenance: if math.abs(x: r.pressureDiff) >= 15.0 then true else false }))
输出
| 时间 | 需要维护 | 压力 | 目标压力 | 压力差 | 站点ID |
|---|---|---|---|---|---|
| 2021-08-01T12:00:00.000Z | 错误 | 101.83929080014092 | 104.37786394078252 | -2.5385731406416028 | g1 |
| 2021-08-02T00:00:00.000Z | false | 96.04368008245874 | 102.27698650674662 | -6.233306424287889 | g1 |
| 时间 | 需要维护 | 压力 | 目标压力 | 压力差 | 站点ID |
|---|---|---|---|---|---|
| 2021-08-01T12:00:00.000Z | false | 101.62490431541765 | 104.83915260886623 | -3.214248293448577 | g2 |
| 2021-08-02T00:00:00.000Z | false | 94.52039415465273 | 105.90869375273046 | -11.388299598077722 | g2 |
| 时间 | 需要维护 | 压力 | 目标压力 | 压力差 | 站点ID |
|---|---|---|---|---|---|
| 2021-08-01T12:00:00.000Z | 假 | 92.23774168403503 | 104.81867444768653 | -12.580932763651504 | g3 |
| 2021-08-02T00:00:00.000Z | 是 | 89.20867846153847 | 108.2579185520362 | -19.049240090497733 | g3 |
| 时间 | 需要维护 | 压力 | 目标压力 | 压力差 | 站点ID |
|---|---|---|---|---|---|
| 2021-08-01T12:00:00.000Z | false | 94.40834093349847 | 107.6827757125155 | -13.274434779017028 | g4 |
| 2021-08-02T00:00:00.000Z | true | 88.61785638936534 | 108.25471698113208 | -19.636860591766734 | g4 |
表格显示,从站点 g4 的 pressureDiff 值 -19.636860591766734 和从站点 g3 的 -19.049240090497733 均高于 15,因此状态发生了变化,这使得 needMaintenance 值标记为“true”,需要对该站点进行维修,以将该值恢复为 false。