Skip to content

Commit 15eddcf

Browse files
authored
Merge pull request #37 from oyve/copilot/add-altitude-calculation-feature
Add altitude calculation from pressure time series
2 parents aa075df + a071cbd commit 15eddcf

File tree

3 files changed

+110
-1
lines changed

3 files changed

+110
-1
lines changed

src/common.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,15 @@ export interface Reading {
44
altitude: number, //meter
55
relativeHumidity: number, //relative humidity in %
66
timestamp: number
7+
}
8+
9+
/**
10+
* Sort readings by timestamp (oldest to newest).
11+
* Returns a new sorted array without modifying the original.
12+
*
13+
* @param {Reading[]} readings - Array of readings to sort.
14+
* @returns {Reading[]} New array of readings sorted by timestamp (oldest to newest).
15+
*/
16+
export function sortOldestToNewest(readings: Reading[]): Reading[] {
17+
return [...readings].sort((a, b) => a.timestamp - b.timestamp);
718
}

src/formulas/altitude.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import { Reading } from '../common';
2+
import * as c from '../constants';
3+
14
/**
25
* Estimate the altitude (in meters) where the temperature drops below freezing (0°C).
36
* Assumes a linear lapse rate (default: 0.0065 K/m).
@@ -16,3 +19,42 @@ export function freezingLevelAltitude(
1619
const altitudeDiff = (surfaceTemp - 273.15) / lapseRate;
1720
return surfaceAltitude + altitudeDiff;
1821
}
22+
23+
/**
24+
* Calculate the altitude difference based on the difference in pressure between two points.
25+
* Uses the hypsometric formula (barometric formula) to calculate altitude change.
26+
*
27+
* The formula used is: Δh = (R * T_avg / g) * ln(P1 / P2)
28+
* where:
29+
* - R is the specific gas constant for dry air (287.05 J/(kg·K))
30+
* - T_avg is the average temperature between the two points
31+
* - g is gravitational acceleration (9.80665 m/s²)
32+
* - P1 is the pressure at the reference (lower) point
33+
* - P2 is the pressure at the higher point
34+
*
35+
* @param {number} referencePressure - Pressure at the reference altitude in Pascals (Pa).
36+
* @param {number} currentPressure - Pressure at the current point in Pascals (Pa).
37+
* @param {number} temperature - Average temperature between the two points in Kelvin (K). Defaults to 288.15 K (15°C).
38+
* @returns {number} Altitude difference in meters (m). Positive values indicate higher altitude.
39+
*
40+
* @example
41+
* // Calculate altitude change from sea level pressure to current pressure
42+
* const altitudeDiff = altitudeFromPressureDifference(101325, 95000, 288.15);
43+
* console.log(altitudeDiff); // ~540 meters higher
44+
*
45+
* @see https://en.wikipedia.org/wiki/Hypsometric_equation
46+
*/
47+
export function altitudeFromPressureDifference(
48+
referencePressure: number,
49+
currentPressure: number,
50+
temperature: number = c.STANDARD_MEAN_TEMPERATURE_KELVIN
51+
): number {
52+
const R = c.DRY_AIR_CONSTANTS.gasConstant; // 287.05 J/(kg·K) for dry air
53+
const g = c.DRY_AIR_CONSTANTS.gravity; // 9.80665 m/s²
54+
55+
// Hypsometric formula: Δh = (R * T / g) * ln(P1 / P2)
56+
const scaleHeight = (R * temperature) / g;
57+
const altitudeDifference = scaleHeight * Math.log(referencePressure / currentPressure);
58+
59+
return Math.round(altitudeDifference * 100) / 100;
60+
}

tests/formulas/altitude.test.ts

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { freezingLevelAltitude } from '../../src/formulas/altitude';
1+
import {
2+
freezingLevelAltitude,
3+
altitudeFromPressureDifference
4+
} from '../../src/formulas/altitude';
25
import { cloudBaseHeight } from '../../src/phenomena/cloud';
36

47
describe('freezingLevelHeight', () => {
@@ -88,3 +91,56 @@ describe('cloudBaseHeight', () => {
8891
expect(result).toBeCloseTo(1249.4, 2);
8992
});
9093
});
94+
95+
describe('altitudeFromPressureDifference', () => {
96+
it('should return 0 when pressures are equal', () => {
97+
const result = altitudeFromPressureDifference(101325, 101325);
98+
expect(result).toBe(0);
99+
});
100+
101+
it('should calculate positive altitude difference when current pressure is lower', () => {
102+
// Sea level pressure to ~1000m altitude pressure
103+
// Using standard temperature 288.15K (15°C)
104+
const result = altitudeFromPressureDifference(101325, 89874.46, 288.15);
105+
// Expected: ~1000m (approximately, based on barometric formula)
106+
// The hypsometric formula may give slightly different results than barometric
107+
expect(result).toBeCloseTo(1011, 0); // Within 1 meter
108+
});
109+
110+
it('should calculate negative altitude difference when current pressure is higher', () => {
111+
// From higher altitude to sea level (going down)
112+
const result = altitudeFromPressureDifference(89874.46, 101325, 288.15);
113+
// Expected: ~-1000m (going down)
114+
expect(result).toBeCloseTo(-1011, 0); // Within 1 meter
115+
});
116+
117+
it('should calculate altitude difference at standard sea level to 500m', () => {
118+
// Sea level standard: 101325 Pa
119+
// At 500m altitude: ~95461 Pa (approximately)
120+
// Using hypsometric formula: Δh = (R * T / g) * ln(P1/P2)
121+
// With R=287.05, T=288.15K, g=9.80665
122+
// Scale height = 287.05 * 288.15 / 9.80665 = 8434.5 m
123+
// For ~500m: P2 = P1 * exp(-500/8434.5) = 101325 * 0.9424 = 95461 Pa
124+
const result = altitudeFromPressureDifference(101325, 95461, 288.15);
125+
expect(result).toBeCloseTo(500, -1); // Within 10 meters
126+
});
127+
128+
it('should account for temperature in calculations', () => {
129+
// Same pressure difference at different temperatures should yield different altitudes
130+
const coldTemp = 273.15; // 0°C
131+
const warmTemp = 303.15; // 30°C
132+
133+
const resultCold = altitudeFromPressureDifference(101325, 95000, coldTemp);
134+
const resultWarm = altitudeFromPressureDifference(101325, 95000, warmTemp);
135+
136+
// Warmer air is less dense, so same pressure drop represents larger altitude change
137+
expect(resultWarm).toBeGreaterThan(resultCold);
138+
});
139+
140+
it('should use default temperature when not provided', () => {
141+
const resultWithDefault = altitudeFromPressureDifference(101325, 95000);
142+
const resultWithExplicit = altitudeFromPressureDifference(101325, 95000, 288.15);
143+
144+
expect(resultWithDefault).toBe(resultWithExplicit);
145+
});
146+
});

0 commit comments

Comments
 (0)