Air Density, Vapor Pressure and I'm Confused


Haha! Obsession of EU citizen for MKSA :wink:


I thought EU used hPa.


You’re right… In general case. Mine is :wink:


Yes, for weather. But for psychrometry…


This is why weather drives people crazy. LOL


Gary - is it possible your input data is incorrect ?

P = 823.4;   # mbar ?
T = 14.1;    # air temp degC
Dp = 5.5;    # dewpoint degC
H = 56;      # pct relative humidity

H = ( Dp / T ) * 100.0 according to the link that the WF page points to, so using the temperatures above H should be 39 in your input data.

Incidentally, your code translates really trivially to python, FWIW. Cool.


I understand what you state but I used the actual values reported by the WeatherFlow application.

Currently they are:

P = 821.7;
T = 15.9;
Dp = 5.5;
H = 50;



Thank you for your formulas and explanations. You have helped me better understand how this is calculated. This isn’t something I wanted to understand, but it doesn’t hurt. :slight_smile:


You’re welcome @GaryFunk :blush:
And if that can reassure you, I also took a long time to understand psychrometry :wink:


I like that your formula incorporates over water AND over ice. I am going to modify the WeatherFlow formula to return for ice.



So I am slowly figuring what is going on here.

First, the vapor pressure is being calculated as Saturated Vapor Pressure in millibars based on the Dew Point temperature.

Then that result is being passed to the Air Density formula.

This is what I ended up with.

The good news is my values agree darn close to professional and government stations around the area. Yea ME!

function _calcVaporPressure(T) {
	// (temp in C)
	let Eso = 6.1078;
	let C0 = 0.99999683;
	let C1 = -0.90826951E-02;
	let C2 = 0.78736169E-04;
	let C3 = -0.61117958E-06;
	let C4 = 0.43884187E-08;
	let C5 = -0.29883885E-10;
	let C6 = 0.21874425E-12;
	let C7 = -0.17892321E-14;
	let C8 = 0.11112018E-16;
	let C9 = -0.30994571E-19;
	let Pol = C0 + T * (C1 + T * (C2 + T * (C3 + T * (C4 + T * (C5 + T * (C6 + T * (C7 + T * (C8+ T * (C9)))))))));
	let Es = Eso * Math.pow(Pol, -8);
	return (Es);

WeatherCalc.calcAirDensity = function(T, P, Dp, H) {
	// (station pressure in mb, vapor pressure in mb, temp in C) return air density in kg/m3
	T = parseFloat(T);
	P = parseFloat(P);
	Dp = parseFloat(Dp)
	let Es = _calcVaporPressure(Dp),
		Rv = 461.4964,
		Rd = 287.0531,
		Tk = T + 273.15,
		Pv = Es * 100,
		Pd = (P - Es) * 100;
	let d = (Pv / (Rv * Tk)) + (Pd / (Rd * Tk));
	let D = parseFloat(d.toFixed(5));

I will be updating and expanding the formulas I posted later this week.

I want to thank @dsj, @pierre, @peter and the WeatherFlow staff for the valuable help.


Good to hear you’ve managed to make progress with this! So is there still an issue with the WeatherFlow derived air density? As you mentioned above, it looks like their calculation of vapour pressures are a bit wide of the mark…


Hello @GaryFunk, I will try to add fuel to your fire :wink:

There are to notions of vapor pressures.

I will try to explain the difference, but excuse me in advance, I don’t know if my English skills will allow me to express all the nuances.

Partial pressure (of water) - or Partial Vapor Pressure - is the pressure exerced by the water (in gazeous phase) in a mix of other gazes. It represents the portion of the total pressure (as expressed in Dalton’s law). The mix between water in different phases are mainly “directed” by relative humidity, so relative humidity takes part in its computation.

Saturation pressure (of water) - or Vapor Pressure at Saturation - is the pressure exerced by the water (in gazeous phase) in the same mix of other gazes but when you can not “add” more vapor without condensation effect (hence its name). So with a relative humidity at 100%. It is a sort of theoretical computation (you know, with “perfect” conditions).

A (good) approximation for partial pressure is Pp = H * Ps
(where Pp is partial pressure, H the relative humidity and Ps the saturation pressure)

In psychrometry, Pp is a terminal computation, it represents the true situation of a mix of gazes. Ps is an intermediate computation which is useful to other computation…like air density!

If I use the following function:

 * Computes the saturation vapor pressure.
 * @param float $t Temperature in celcius.
 * @return float The computed saturation vapor pressure (in Pascal).
 * @since 3.3.0
protected function compute_saturation_vapor_pressure($t) {
    if ($t < 0) {
        $result = pow(10, 2.7877 + ((9.756 * $t) / (272.7 + $t)));
    else {
        $result = pow(10, 2.7877 + ((7.625 * $t) / (241.6 + $t)));
    return round($result);

I obtain the following “table of calibration”:

40°C => 7427Pa
30°C => 4265Pa
20°C => 2348Pa
15°C => 1712Pa
10°C => 1232Pa
00°C => 613Pa

which is (at a precision of more than 99.3%) what you have in the table extracted from the document you cited. Note these numbers are in line with what gives the vapor pressure calculator of NOAA

At this precision I consider it sufficient to calculate air density at “normal temperatures”… :slight_smile:

You can now complete your computation with the following functions:

 * Computes the vapor pressure.
 * @param float $t Temperature in celcius.
 * @param float $h Humidity in percent.
 * @return float The computed partial vapor pressure (in Pascal).
 * @since 3.3.0
protected function compute_partial_vapor_pressure($t, $h) {
    $p = $this->compute_saturation_vapor_pressure($t);
    return round($h * $p / 100, 0);
 * Computes the air density.
 * @param float $t Temperature in celcius.
 * @param float $p Pressure in pascal.
 * @param float $h Humidity in percent.
 * @return float The computed air density (in kg/m^3).
 * @since 3.3.0
protected function compute_air_density($t, $p, $h) {
    if ($p == 0) {
        return 0;
    $Ps = $this->compute_saturation_vapor_pressure($t) / $p;
    $Rh = 287.06 / (1 - (($h / 100 ) * $Ps * (1 - (287.06 / 461))));
    return round($p / ($Rh * ($t+273.15)), 5);

I don’t know if it helps, but I hope so :blush:


And finally, to answer the following question:

I think the answer is “no”. What is computed by WF seems to me particularly suitable for common uses of air density…


This brings up another question. Why are vapor pressure and air density calculated on the server when every other calculation is done on the client?


This, is a good question. :grin:


@GaryFunk - I got lost in the long thread below this one, but did you guys ever reach resolution on this ?

I found (this link) which has far too much detail even for my too-many-years-ago Chemical Engineering degree brain, but it sure looks like WF is:

  • using equation (3) so a simple Ideal Gas Law calculation
  • and feeding it observed temperature and observed station pressure

Just to test that, I ran my data here from this morning using a quick python routine:

T    = 11.0    # degC observed
Psta = 1004.7  # mb observed

air density ideal-gas-law (T,Psta)  = 1.23177444759
air density WF app reported         = 1.233174

Using your values from your original post in this thread:

T    = 11.4   # degC observed
Psta = 828.8  # mb observed

air density ideal-gas-law (T,Psta) = 1.01346622743
WF reported density from your post = 1.01344

That sure looks like two matches to me…

Python code that should be obvious is:

# ref: (equation 3)
import math
def vpFromIdealGasLaw(t,p):
    T  = float(t) + 273.15    # convert degC => degK
    P = 100 * float(p)       # convert mb   => Pascals
    N  = 287.05               # specific gas constant for dry air J/(kg*degK)
    return P/(N * T)

print "air_density ideal gas law (11.4,828.8)=", vpFromIdealGasLaw(11.4,827.8)


The end result is the air density reported by WeatherFlow is darn close. It’s the vapor pressure that is off by 50%.

So, that means the vapor pressure formula used by WeatherFlow cannot be used by any other formula that requires an accurate value. It also means the the air density formula used by WeatherFlow has to compensate for a vapor pressure value that is half of what it actually is.

I am convinced that there is an issue on the WeatherFlow end and I am open to being corrected by WeatherFlow as I am not an expert and not an authority on vapor pressure or air density. However, I know math and I can clearly see the difference in the values.

All this being said, I have decided on the formulas to use and if asked why my values are different than WeatherFlow, I will simply respond with by demonstrating the formulas I use. It’s not an issue that matters to most but I want to provide the value from UDP data and that requires that vapor pressure and air density (along with density altitude) be calculated from the available UDP data. My goal as always been to match the WeatherFlow data within +/- 0.0001 of value.

Numbers, and how your present them, do matter. Close only counts in horse shoes, hand grenades and atomic bombs.


Not seeing it. Off from ‘what’ ?

VP_weatherflow = (H / 100) * 6.112 * math.exp((17.67 * T) / (243.5 + T))

# but the calculation the WF page links to is different
VP_weather_gov = 6.11 * math.pow(10, ((7.5 * T) / (237.3 + T)));

# using dewpoint of 10.4 degC the two are 0.2% different
VP_weatherflow = 12.5932992479 mb = 12.6164817301 mb

These match the calculations on:

(assuming Pa = mb * 100)

Guess I’m lost where the 50% off is coming from, unless I’m lost in a maze of twisty little metric-vs-imperial unit conversions. I see the two formulas getting the same answer and matching 4 different online references (plus/minus a fraction of a percent)


Read message 31 here: Air Density, Vapor Pressure and I'm Confused