These are the formulas I use to convert the UDP values to a human understandable value.
Many of these came from WeatherFlow.
//Weather Formulas
//Copyright © 2018 Gary W Funk
const myfile = {"alias": "WeatherFormulas", "version": "1.6.12.005", "addtopm2": "no"};
if (typeof require != 'undefined') {
const util = require('./util');
util.writeVersion(myfile.alias, myfile.version, myfile.addtopm2);
}
(function () { 'use strict';
// Vapor Pressure //
function _calcVaporPressure(T) {
// (tmep in C)
T = parseFloat(T);
var a = (7.5 * T) / (237.3 + T);
var Es = 6.1078 * Math.pow(10, a);
return Es;
}
function _convertCToF(T) {
T = parseFloat(T);
var r = 1.8 * T + 32;
return Math.round(100 * r) / 100;
};
// e.DistanceValue.prototype._convertTo
function _convertDistance(D, U) {
// (distance, unit)
D = parseFloat(D);
if (U == 'mi') {
D = D * .621371;
}
return D.toFixed(2);
};
// e.TemperatureValue.convertFToC
function _convertFToC(T) {
T = parseFloat(T);
var r = (T - 32) / 1.8;
return Math.round(100 * r) / 100;
};
var WeatherCalc = {};
// Air Density //
WeatherCalc.calcAirDensity = function(T, P, Dp) {
// (air temp in C, sea level pressure, dew point)
// var d = (P * 100) / (287.05 * (T + 273.15));
T = parseFloat(T);
P = parseFloat(P);
Dp = parseFloat(Dp)
var Es = _calcVaporPressure(Dp),
Rv = 461.4964,
Rd = 287.0531,
tk = T + 273.15,
pv = Es * 100,
pd = (P - Es) * 100,
d = (pv / (Rv * tk) ) + (pd / (Rd * tk) );
return d.toFixed(5);
},
// Delta T //
WeatherCalc.calcDeltaT = function(T, WB) {
// (air temp in C, web bulb in C)
T = parseFloat(T);
WB = parseFloat(WB);
return d = (T - WB).toFixed(2);
},
// Dew Point Temperature //
// e.Observations.prototype._getDewPoint
WeatherCalc.calcDewPoint = function(T, RH) {
//(air temp in C, humidity)
T = parseFloat(T);
RH = parseFloat(RH);
var DP = 243.04 * (Math.log(RH / 100) + 17.625 * T / (243.04 + T)) / (17.625 - Math.log(RH / 100) - 17.625 * T / (243.04 + T));
return DP.toFixed(2);
},
// Feels Like Temperature //
// If temperature >= 80°F = Heat Index.
// If temperature < 50°F = Wind Chill.
// this formula is not complete
// e.DerivedValues.feelsLike
WeatherCalc.calcFeelsLike = function(T, RH) {
// (air temp in C, humidity)
var F = _convertCToF(T);
RH = parseInt(RH, 10);
if (RH < 40 || F < 80) return T;
var r = 61 + 1.2 * (F - 68) + .094 * RH,
s = .5 * (F + r),
n = 0;
if (s > 79) {
if (n = 2.04901523 * F - 42.379 + 10.14333127 * RH - .22475541 * F * RH - 6.83783 * Math.pow(10, -3) * Math.pow(F, 2) - 5.481717 * Math.pow(10, -2) * Math.pow(RH, 2) + 1.22874 * Math.pow(10, -3) * Math.pow(F, 2) * RH + 8.5282 * Math.pow(10, -4) * F * Math.pow(RH, 2) - 1.99 * Math.pow(10, -6) * Math.pow(F, 2) * Math.pow(i, 2), RH <= 13 && F >= 80 && F < 112) {
var o = (13 - i) / 4,
l = Math.sqrt((17 - Math.abs(F - 95)) / 17);
n -= o * l;
} else if (RH > 85 && F >= 80 && F <= 87) {
var c = (RH - 85) / 10,
u = (87 - F) / 5;
n += c * u;
}
} else n = s;
var FL = _convertFToC(n);
return FL;
},
// Heat Index Temperature //
// e.Observations.prototype._getHeatIndex
WeatherCalc.calcHeatIndex = function(T, RH) {
// (air temp in C, humidity)
var F = _convertCToF(T);
RH = parseInt(RH, 10);
if (RH < 40 || F < 80) return T;
var r = 61 + 1.2 * (F - 68) + .094 * RH,
s = .5 * (F + r),
n = 0;
if (s > 79) {
if (n = 2.04901523 * F - 42.379 + 10.14333127 * RH - .22475541 * F * RH - 6.83783 * Math.pow(10, -3) * Math.pow(F, 2) - 5.481717 * Math.pow(10, -2) * Math.pow(RH, 2) + 1.22874 * Math.pow(10, -3) * Math.pow(F, 2) * RH + 8.5282 * Math.pow(10, -4) * F * Math.pow(RH, 2) - 1.99 * Math.pow(10, -6) * Math.pow(F, 2) * Math.pow(i, 2), RH <= 13 && F >= 80 && F < 112) {
var o = (13 - i) / 4,
l = Math.sqrt((17 - Math.abs(F - 95)) / 17);
n -= o * l;
} else if (RH > 85 && F >= 80 && F <= 87) {
var c = (RH - 85) / 10,
u = (87 - F) / 5;
n += c * u;
}
} else n = s;
return _convertFToC(n);
},
// Pressure Trend //
WeatherCalc.calcPressureTrend = function(sn, Z) {
var l,
r,
s,
x,
time,
diff,
old = [],
trend;
l = UDPPres[sn].S.length;
// System.LogHigh('Pressure');
// find the 180th newest record
if (l < 181) {
r = 0;
s = '*';
} else {
r = l - 181;
s = '';
}
time = (Z[0] - UDPPres[sn].S[r][0]);
old = UDPPres[sn].S[r];
diff = (Z[1] - old[1]);
if (r == 0) {
x = (10800 / time);
diff = (diff == 0) ? 0: (diff * x);
}
a = Math.abs(diff);
trend = (diff >= 1) ? 'Rising' : (diff <= -1) ? 'Falling' : 'Steady';
if (a > 2) {
trend = 'Rapid ' + trend;
}
trend += s;
//System.LogHigh('PressureTrend');
//System.LogHigh('l = ' + l);
//System.LogHigh('r = ' + r);
//System.LogHigh('AR = ' + Z[0]);
//System.LogHigh('UDP = ' + UDPPres[sn].S[r][0]);
//System.LogHigh('diff = ' + Z[1] + ' - ' + old[1] + ' = ' + diff.toFixed(2));
//System.LogHigh('time = ' + time);
//System.LogHigh('x = ' + x);
//System.LogHigh('trend = ' + trend);
return {
trend: trend,
value: diff
};
},
// Temperature Trend //
WeatherCalc.calcTemperatureTrend = function(sn, Z) {
var l,
r,
s,
x,
time,
diff,
old = [],
trend,
value;
l = UDPTemp[sn].S.length;
// System.LogHigh('Temp');
// find the 60th newest record
if (l < 61) {
r = 0;
s = '*';
} else {
r = l - 61;
s = '';
}
time = (Z[0] - UDPTemp[sn].S[r][0]);
old = UDPTemp[sn].S[r];
diff = (Z[2] - old[1]);
if (r == 0) {
x = (3600 / time);
diff = (diff == 0) ? 0: (diff * x);
}
a = Math.abs(diff);
trend = (diff >=5) ? 'Rising' : (diff <= -5) ? 'Falling' : 'Steady';
if (a > 10) {
trend = 'Rapid ' + trend;
}
trend += s;
//System.LogHigh('TempTrend');
//System.LogHigh('l = ' + l);
//System.LogHigh('r = ' + r);
//System.LogHigh('AR = ' + Z[0]);
//System.LogHigh('UDP = ' + UDPTemp[sn].S[r][0]);
//System.LogHigh('diff = ' + Z[2] + ' - ' + old[2] + ' = ' + diff.toFixed(2));
//System.LogHigh('time = ' + time);
//System.LogHigh('x = ' + x);
//System.LogHigh('value = ' + value);
//System.LogHigh('trend = ' + trend);
return {
trend: trend,
value: diff
};
},
// Sea Level Pressure //
// e.PressureValue.prototype._convertToSeaLevel
WeatherCalc.calcSeaLevel = function(A, P) {
// (altitude in meters, local pressure in mb)
A = parseFloat(A);
P = parseFloat(P);
var
a = 9.80665,
i = 287.05,
r = .0065,
s = 1013.25,
n = 288.15,
l = a / (i * r),
c = i * r / a,
u = Math.pow(1 + Math.pow(s / P, c) * (r * A / n), l),
d = (P * u);
return d.toFixed(1);
},
// Wet Bulb Temperatre //
// wetbulb = calcwetbulb(Edifference,Twguess,Ctemp,MBpressure,E2,previoussign,incr);
// from http://www.weather.gov/epz/wxcalc_rh
WeatherCalc.calcWetBulb = function(T, RH, P) {
// (temp in C, humidity, station pressure)
T = parseFloat(T);
RH = parseFloat(RH);
P = parseFloat(P);
var Edifference = 1,
Twguess = 0,
previoussign = 1,
incr = 10,
Es = 6.112 * Math.exp(17.67 * T / (T + 243.5)),
E2 = Es * (RH / 100);
outerloop:
while (Math.abs(Edifference) > 0.005) {
Ewguess = 6.112 * Math.exp((17.67 * Twguess) / (Twguess + 243.5));
Eguess = Ewguess - P * (T - Twguess) * 0.00066 * (1 + (0.00115 * Twguess));
Edifference = E2 - Eguess;
if (Edifference == 0) {
break outerloop;
} else {
if (Edifference < 0) {
cursign = -1;
if (cursign != previoussign) {
previoussign = cursign;
incr = incr / 10;
} else {
incr = incr;
}
} else {
cursign = 1;
if (cursign != previoussign) {
previoussign = cursign;
incr = incr / 10;
} else {
incr = incr;
}
}
}
Twguess = Twguess + incr * previoussign;
}
return Twguess.toFixed(2);
},
// Wind and Direction //
WeatherCalc.calcWind = function(d) {
var i,
EW_Vector = 0,
NS_Vector = 0,
gust = 0,
lull = 999,
s = 0;
for (i = 0; i < d.length; i++) {
s += d[i][1];
EW_Vector += Math.sin(0.01745329252 * d[i][2]) * d[i][1];
NS_Vector += Math.cos(0.01745329252 * d[i][2]) * d[i][1];
if (d[i][1] > gust) gust = d[i][1];
if (d[i][1] < lull) lull = d[i][1];
}
var speed = s / d.length;
var EW_Average = (EW_Vector / d.length) * -1;
var NS_Average = (NS_Vector / d.length) * -1;
var dir = (Math.atan2(EW_Average, NS_Average) / 0.01745329252);
var direction = Math.round( dir > 180 ? dir -= 180 : dir += 180 );
return {
date: d[0][0],
direction: direction.toString(),
speed: speed,
lull: lull,
gust: gust
};
},
// Wind Chill Temperature //
// e.Observations.prototype._getWindChill
WeatherCalc.calcWindChill = function(T, W) {
// (air temp, wind speed)
//Debug('temp = ' + T);
//Debug('wind = ' + W);
var F = _convertCToF(T);
var V = WeatherCalc.convertWindSpeed(W, 'mph');
if (V < 5 || F > 50) return parseFloat(T);
var WC = 35.74 + (0.6215 * F) - ( 35.75 * Math.pow(V, .16) ) + ( 0.4275 * F * Math.pow(V, .16) );
return _convertFToC(WC);
},
// Convert Functions //
// e.SWUser.prototype.userAirDensityDisplay
WeatherCalc.convertAirDensity = function(T, U) {
// (air temp, unit)
T = parseFloat(T);
if (U == 'imperial') {
var i = .062428 * T;
return i.toFixed(5);
}
return T;
},
// e.SWUser.prototype.userDeltaTDisplay
WeatherCalc.convertDeltaT = function(T, U) {
// (temp in C, unit)
T = parseFloat(T);
if (U == 'f') {
T = Math.abs(1.8 * T);
}
return T.toFixed(1);
},
// https://stackoverflow.com/questions/37893131/how-to-convert-lat-long-from-decimal-degrees-to-dms-format
WeatherCalc.convertLatLongDecimalToDMS = function(coordinate) {
var dms = {};
var absolute = Math.abs(coordinate);
var degrees = Math.floor(absolute);
var minutesNotTruncated = (absolute - degrees) * 60;
var minutes = Math.floor(minutesNotTruncated);
var seconds = Math.floor((minutesNotTruncated - minutes) * 60);
var hundreths = parseInt((seconds / 60) * 100);
dms['coordinate'] = coordinate;
dms['degrees'] = degrees;
dms['minutes'] = minutes;
dms['seconds'] = seconds;
dms['hundreths'] = hundreths;
return dms;
},
// e.LightningDistanceValue.prototype._convertToText
WeatherCalc.convertLightningDistance = function(D, U) {
// (distance)
D = parseFloat(D);
if (D == 0 || isNaN(D)) return '---';
if (U = 'mi') {
D = _convertDistance(D, U);
}
D = parseInt(D);
/*
return null != this.value && (
this.value > 34 ? (t.graphMin = 20, t.graphMax = 25, t.value = Math.round(new e.DistanceValue(35, this.units).displayValue()), t.symbol = ">") :
this.value > 20 ? (t.graphMin = 15, t.graphMax = 20, t.value = Math.round(new e.DistanceValue(35, this.units).displayValue()), t.symbol = "≤") :
this.value > 10 ? (t.graphMin = 10, t.graphMax = 15, t.value = Math.round(new e.DistanceValue(20, this.units).displayValue()), t.symbol = "≤") :
this.value > 5 ? (t.graphMin = 5, t.graphMax = 10, t.value = Math.round(new e.DistanceValue(10, this.units).displayValue()), t.symbol = "≤") :
(t.graphMin = 0, t.graphMax = 5, t.value = Math.round(new e.DistanceValue(5, this.units).displayValue()), t.symbol = "≤")), t
if (D > 34) {
i = 35.0;
} else if (D > 29) {
i = 29.9;
} else if (D > 24) {
i = 24.9;
} else if (D > 19) {
i = 19.9;
} else if (D > 14) {
i = 14.9;
} else if (D > 9) {
i = 9.1;
} else {
i = 4.9;
}
*/
return D;
},
// e.DistanceValue.prototype._convertTo
WeatherCalc.convertMeasure = function(D, U) {
// (distance, unit)
D = parseFloat(D);
if (U == 'ft') {
D = D * 3.28084;
}
return D.toFixed(2);
},
WeatherCalc.convertMoonPhase8 = function(D) {
D = D * 1000;
var e = Math.floor((D / 125));
return (e % 8);
},
WeatherCalc.convertMoonPhase16 = function(D) {
D = D * 1000;
var e = Math.floor((D / 62.5));
return (e % 16);
},
// e.PrecipValue.prototype._convertTo
WeatherCalc.convertPrecip = function(T, U) {
// (precip, unit)
var t = parseFloat(T);
var i = t;
switch (U) {
case 'in':
i = .0393701 * t;
return parseFloat(i.toFixed(3));
break;
case 'cm':
i = .1 * t;
return parseFloat(i.toFixed(1));
break;
default:
return i;
break;
}
},
// e.PrecipValue.prototype._convertTo
WeatherCalc.convertPrecipRate = function(T, I, U) {
// (precip, unit)
t = parseFloat(T);
var i = t;
switch (U) {
case 'in':
i = .0393701 * t;
return (i * (60 / I)).toFixed(3);
break;
case 'cm':
i = .1 * t;
return i.toFixed(1);
break;
default:
return i;
break;
}
},
WeatherCalc.convertPrecipType = function(T) {
// (precip, unit)
var i;
switch (T) {
case 0:
i = 'None';
break;
case 1:
i = 'Rain';
break;
case 2:
i = 'Hail';
break;
default:
i = '---';
}
return i;
},
// e.PressureValue.prototype._convert
WeatherCalc.convertPressure = function(P, U) {
// (pressure, unit)
if (null == P) return null;
P = parseFloat(P);
if (U == 'inhg') {
return (.0295301 * P).toFixed(3);
} else {
return P.toFixed(1);
}
},
// e.TemperatureValue.prototype.convertTo
WeatherCalc.convertTemp = function(T, U) {
// (air temp, unit)
T = parseFloat(T);
if (U == 'f') {
T =_convertCToF(T);
}
return parseFloat(T.toFixed(1));
},
WeatherCalc.convertUcaseFirst = function(s) {
// (string)
s = s.charAt(0).toUpperCase() + s.slice(1);;
return s;
},
WeatherCalc.convertUptime = function(Time) {
var day,
hour,
minute,
second,
temp,
time = parseInt(Time, 10);
// Debug('time = ' + time);
temp = time / 86400;
day = parseInt(temp, 10);
// Debug('Day = ' + day);
time = time - (86400 * day);
temp = time / 3600;
hour = parseInt(temp, 10);
time = time - (3600 * hour);
temp = time / 60;
minute = parseInt(temp, 10);
time = time - (60 * minute);
temp = time;
second = parseInt(temp, 10);
temp = '';
if (day > 0) {
temp = day.toString()
temp += 'd ';
}
temp += hour.toString() + 'h ' + minute.toString() + 'm ' + second.toString() + 's';
return temp;
},
WeatherCalc.convertWindDirection16 = function(D) {
var e = Math.floor((D / 22.5) + 0.5);
return (e % 16);
},
WeatherCalc.convertWindDirection32 = function(D) {
var e = Math.floor((D / 11.25) + 0.25);
return (e % 32);
},
// e.WindSpeedValue.prototype._convertTo
WeatherCalc.convertWindSpeed = function(t, u) {
//(speed, unit)
this.value = t;
var i = this.value;
switch (u) {
case 'mph':
i = 2.2369362920544 * this.value;
break;
case 'kph':
i = 3.6 * this.value;
break;
case 'kts':
i = 1.9438 * this.value;
break;
case 'bft':
i = this.value < .3 ? 0 : this.value < 1.6 ? 1 : this.value < 3.5 ? 2 : this.value < 5.5 ? 3 : this.value < 8 ? 4 : this.value < 10.8 ? 5 : this.value < 13.9 ? 6 : this.value < 17.2 ? 7 : this.value < 20.8 ? 8 : this.value < 24.5 ? 9 : this.value < 28.5 ? 10 : this.value < 32.7 ? 11 : this.value >= 32.7 ? 12 : 0;
break;
case 'lfm':
i = 2.2369362920544 * this.value * 88;
}
return parseFloat(i).toFixed(1);
},
WeatherCalc.formatLightningDistance = function(D, U) {
D = parseFloat(D);
if (D == 0) return '---';
var d = Math.ceil(D),
i = '> ';
if (d > D) {
i = '< ';
}
if (U = 'mi') {
D = _convertDistance(D);
}
return (i + d + ' ' + U)
},
// Compass //
WeatherCalc.ToCompass16 = function(num) {
var arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"];
return arr[num];
},
WeatherCalc.ToCompass32 = function(num) {
var arr = ["N", "NbE", "NNE", "NEbN", "NE", "NEbE", "ENE", "EbN", "E", "EbS", "ESE", "SEbE", "SE", "SEbS", "SSE", "SbE", "S", "SbW", "SSW", "SWbS", "SW", "SWbW", "WSW", "WbS", "W", "WbN", "WNW", "NWbW", "NW", "NWbN", "NNW", "NbW"];
return arr[num];
},
WeatherCalc.ToMoonPhase8 = function(num) {
var arr = ["New Moon", "Waxing Crescent", "First Quarter", "Waxing Gibbous", "Full Moon", "Waning Gibbous", "Last Quarter", "Waning Crescent"];
return arr[num];
},
WeatherCalc.ToMoonPhase16 = function(num) {
var arr = ["New Moon", "New Moon >> Waxing Crescent", "Waxing Crescent", "Waxing Crescent >> First Quarter", "First Quarter", "First Quarter >> Waxing Gibbous", "Waxing Gibbous", "Waxing Gibbous >> Full Moon", "Full Moon", "Full Moon >> Waning Gibbous", "Waning Gibbous", "Waning Gibbous >> Last Quarter", "Last Quarter", "Last Quarter >> Waning Crescent", "Waning Crescent", "Waning Crescent >> New Moon"];
return arr[num];
},
WeatherCalc.GetCompass16 = function(deg) {
var num = WeatherCalc.convertWindDirection16(deg);
return WeatherCalc.ToCompass16(num);
};
/*
function _formatAirDensity(P, U) {
//(Pressure, Unit)
if (U == 'imperial') {
U = 'lbs/ft3';
} else {
U = 'kg/m3';
}
return (P + ' ' + U);
}
function _formatDistance(D, U) {
//(Distance, Unit)
if (U == 'mi') {
U = 'miles';
} else {
U = 'kilometers';
}
return (D + ' ' + U);
}
function _formatLightningDistance(D, U) {
D = parseFloat(D);
if (D == 0) return '---';
var d = Math.ceil(D),
i = '> ';
if (d > D) {
i = '< ';
}
if (U = 'mi') {
D = _convertDistance(D);
}
return (i + d + ' ' + U)
}
function _formatMeasure(D, U) {
//(Distance, Unit)
if (U == 'imperial') {
U = 'feet';
} else {
U = 'meters';
}
return (D + ' ' + U);
}
function _formatPressure(P, U) {
//(pressure, unit)
if (U == 'inhg') {
U = 'inHg';
} else {
U = 'millibars'
}
return (P + ' ' + U)
}
function _formatTemp(T, U) {
//(temp, unit)
return T + String.fromCharCode(0x00b0) + ' ' + U.toUpperCase();
}
*/
// export as Node module / AMD module / browser variable
if (typeof exports === 'object' && typeof module !== 'undefined') module.exports = WeatherCalc;
else if (typeof define === 'function' && define.amd) define(WeatherCalc);
else window.WeatherCalc = WeatherCalc;
}());