使用自定义函数隐藏复杂性:计算热指数
作者:David G. Simmons / 用例, 开发者, 产品
2019 年 8 月 23 日
导航至
您是否曾经观看当地天气预报——或天气频道——听到他们宣布温度,然后是“热指数”?或者外面感觉有多热?至少在美国,尤其是在南方,它是夏季每次天气预报的一部分。但是您有没有想过他们实际上是如何计算热指数的?由于我收集温度和湿度数据,有一天我决定去弄清楚。毕竟,这真的有多难呢?提示:永远不要问自己这个问题!
热指数计算
当我开始寻找我确信可以将温度和湿度读数转换为热指数 (HI) 的简单计算方法时,我后悔走上了这条路。我很容易找到一个页面,美国国家海洋和大气管理局 (NOAA) 在该页面上列出了公式。它被称为 Rothfusz 回归方程,它看起来像这样
HI = -42.379 + 2.04901523T + 10.14333127RH - .22475541TRH - .00683783TT - .05481717RHRH + .00122874TTRH + .00085282TRHRH - .00000199TTRHRH
其中 T 是温度,RH 是相对湿度。简单,对吧?没那么快!事实证明,这个(简单)方程有很多注意事项。例如,如果相对湿度低于 13% 且温度在 80ºF 到 112ºF 之间,则必须通过从中减去以下调整来调整热指数
调整 = [(13-RH)/4]*SQRT{[17-ABS(T-95.)]/17}
好的,没问题。但是等等,还有更多!如果相对湿度高于 85%,并且温度在 80ºF 到 112ºF 之间,那么您需要添加以下调整
调整 = [(RH-85)/10] * [(87-T)/5]
太棒了!我们终于到了……等等,我们还没到。如果热指数低于 80ºF,那么您不需要使用该计算来确定热指数。您可以使用更简单的 Steadman 方程
HI = 0.5 * {T + 61.0 + [(T-68.0)1.2] + (RH0.094)}
因此,首先您使用那个“简单”的方程计算热指数——并且,根据 NOAA 的说法,您将该值与温度读数平均。如果该值低于 80ºF,您就得到了答案。如果不是,您需要继续进行 Rothfusz 回归并添加(或减去)任何必要的调整(如果需要)。
看到了吗?真的很简单。
在 Flux 中实现
这里涉及到一些复杂的 Flux。您看,我的温度和湿度读数在不同的测量中,所以首先是构建表并连接它们的任务(感谢 Flux 中跨测量数学的美妙之处!)。
humidity = from(bucket: "telegraf")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r._measurement == "environment" and (r._field == "humidity"))
|> aggregateWindow(every: 30s, fn: mean)
|> fill(column: "_value", usePrevious: true)
|> keep(columns: ["_value", "_time"])
temperature = from(bucket: "telegraf")
|> range(start: v.timeRangeStart)
|> filter(fn: (r) => r._measurement == "temperature" and (r._field == "temp_f"))
|> aggregateWindow(every: 30s, fn: mean)
|> fill(column: "_value", usePrevious: true)
|> keep(columns: ["_value", "_time"])
|> yield(name: "Temperature")
这给了我 2 个值表。(旁注:我生成 Temperature 表,以便我的图表将在同一图表上显示温度和热指数。)
接下来,我连接 2 个表
first_join = join(tables: {temperature: temperature, humidity: humidity}, on: ["_time"])
|>map(fn: (r) => ({temperature: r._value_temperature, humidity:r._value_humidity, _time: r._time}))
|> keep(columns: ["_time", "humidity", "temperature"])
所以现在我有一个单表,按时间对齐,其中包含 temperature
和 humidity
列。剩下的就是进行计算
|> map(fn: (r) => ({t: r.temperature, h: r.humidity}))
|> map(fn: (r) => ({
r with heatIndex:
if ((0.5 * (r.t + 61.0 + ((r.t-68.0)*1.2) + (r.h*0.094)))/2.0) < 80.0 then (0.5 * (r.t + 61.0 + ((r.t - 68.0)*1.2) + (r.h*0.094)))
else if ( r.h < 13.0 and r.t > 80.0) then ((-42.379 + 2.04901523*r.t + 10.14333127*r.h - .22475541*r.t*r.h - .00683783*r.t*r.h - .05481717*r.t*r.h + .00122874*r.t*r.t*r.h + .00085282*r.t*r.h*r.h - .00000199*r.t*r.t*r.h*r.h - (((13.0-r.h)/4.0)*math.sqrt(x: ((17.0-math.abs(x: (r.t-95.0))/17.0))))))
else if r.h > 85.0 and r.t >= 80.0 and r.t <= 87.0 then ((-42.379 + 2.04901523*r.t + 10.14333127*r.h - .22475541*r.t*r.h - .00683783*r.t*r.h - .05481717*r.t*r.h + .00122874*r.t*r.t*r.h + .00085282*r.t*r.h*r.h - .00000199*r.t*r.t*r.h*r.h) + (( r.h-85.0 )/10.0) *((87.0-r.t)/5.0))
else (-42.379 + 2.04901523*r.t + 10.14333127*r.h - .22475541*r.t*r.h - .00683783*r.t*r.h - .05481717*r.t*r.h + .00122874*r.t*r.t*r.h + .00085282*r.t*r.h*r.h - .00000199*r.t*r.t*r.h*r.h)
})
)
|> map(fn: (r) => ({_value: r.heatIndex, _time: r._time}))
|> yield(name: "HeatIndex")
我告诉过您 Flux 很复杂!
但在最后,您可以得到一个图表,该图表在同一个表格单元格中显示实际温度和计算出的热指数
下一步
由于这涉及大量复杂的 Flux。下一步是将所有这些都拉入 Flux 函数中,以便您可以简单地在带有 temperature
和 humidity
列的表上调用 |> HeatIndex()
,并返回正确的表,其中所有热指数都为您计算好了。所以我正在将 HeatIndex()
函数添加到 Flux 中,这样您在计算热指数时就可以拥有漂亮的 Flux。
我计划在这个未来的软件包中添加理想气体定律(一个简单的)和风寒计算(另一个丑陋的!),以及从 ºF 到 ºC 的转换器,所以如果您对您将用于环境计算的其他内容有任何想法,请联系我并告诉我!