使用自定义函数隐藏复杂性:计算热指数

导航至

您是否曾经观看过当地的天气——或者天气频道——并听到他们宣布温度,然后是“热指数”?或者外面有多热?至少在美国,尤其是在南部,这是夏季每次天气预报的一部分。但您是否曾经想过他们是如何实际计算热指数的?由于我收集温度和湿度数据,我决定有一天去弄清楚它。毕竟,这真的有那么难吗?提示:永远不要问自己这个问题!

热指数的计算

当我开始寻找将温度和湿度读数转换为热指数(HI)的简单计算方法时,我后悔选择了这条道路。我很容易就找到了一个页面,美国国家海洋和大气管理局(NOAA)在上面列出了公式。它被称为Rothfusz回归方程,其形式如下

HI = -42.379 + 2.04901523T + 10.14333127RH - .22475541TRH - .00683783TT - .05481717RHRH + .00122874TTRH + .00085282TRHRH - .00000199TTRHRH

其中,T代表温度,RH代表相对湿度。简单,对吧?但等等,事实并非如此!这个(简单)方程有一些限制。例如,如果相对湿度小于13%,且温度在80ºF和112ºF之间,那么您需要通过减去以下调整来调整热指数

ADJUSTMENT = [(13-RH)/4]*SQRT{[17-ABS(T-95.)]/17}

好吧,好吧。但是等等,还有更多!如果相对湿度高于85%,且温度在80ºF和112ºF之间,那么您需要将以下调整添加到其中

ADJUSTMENT = [(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")

这样我就得到了两个值表格。(备注:我生成温度表格,这样我的图表就可以在同一图表上显示温度和热指数。)

接下来,我连接这两个表格

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"])

现在,我有一个单一的表格,按时间对齐,有temperaturehumidity列。剩下的就是进行计算

|> 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函数,这样您就可以简单地使用|> HeatIndex()在您的表格中调用temperaturehumidity列,并得到一个所有计算热指数都为您计算好的表格。所以我现在正在添加HeatIndex()函数到Flux,这样您在计算热指数时就可以有很好的Flux体验。

我计划将理想气体定律(一个简单的)和风寒效应(另一个复杂的)的计算也加入到这个未来的包中,以及从华氏度到摄氏度的转换器,如果您有任何其他用于环境计算的想法,请联系我并告诉我!