rf: derive the rain height from P.839 in the path method
This commit is contained in:
parent
84d1c744f1
commit
1ff6c261f1
|
|
@ -65,7 +65,7 @@ pub use geometry::{air_mass, elevation_from_zenith, zenith_to_elevation};
|
||||||
pub use p839::{RAIN_HEIGHT_OFFSET_KM, grid_step_degrees, rain_height, zero_isotherm_height};
|
pub use p839::{RAIN_HEIGHT_OFFSET_KM, grid_step_degrees, rain_height, zero_isotherm_height};
|
||||||
pub use rain::{
|
pub use rain::{
|
||||||
DEFAULT_RAIN_HEIGHT_KM, RainAttenuation, polarisation_tilt, rain_attenuation,
|
DEFAULT_RAIN_HEIGHT_KM, RainAttenuation, polarisation_tilt, rain_attenuation,
|
||||||
rain_coefficients, specific_rain_attenuation,
|
rain_attenuation_at, rain_coefficients, specific_rain_attenuation,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use apsis_rf::Decibel;
|
pub use apsis_rf::Decibel;
|
||||||
|
|
|
||||||
|
|
@ -31,12 +31,12 @@ use apsis_rf::Decibel;
|
||||||
/// which makes the Earth appear larger than it is.
|
/// which makes the Earth appear larger than it is.
|
||||||
const EFFECTIVE_EARTH_RADIUS_KM: f64 = 8_500.0;
|
const EFFECTIVE_EARTH_RADIUS_KM: f64 = 8_500.0;
|
||||||
|
|
||||||
/// The default height of the rain layer above sea level, in kilometers.
|
/// A mid latitude rain height, in kilometers above sea level.
|
||||||
///
|
///
|
||||||
/// Recommendation P.618 takes this from the zero degree isotherm height,
|
/// Recommendation P.618 takes the rain height from the zero degree isotherm
|
||||||
/// which depends on latitude and season and is tabulated separately. This
|
/// height of Recommendation P.839, which is tabulated as a function of
|
||||||
/// value is representative of mid latitudes; a caller working in the tropics
|
/// latitude and longitude. Prefer [`rain_attenuation_at`], which looks the
|
||||||
/// should raise it and one in polar regions should lower it.
|
/// value up, over [`rain_attenuation`] with this constant.
|
||||||
pub const DEFAULT_RAIN_HEIGHT_KM: f64 = 3.0;
|
pub const DEFAULT_RAIN_HEIGHT_KM: f64 = 3.0;
|
||||||
|
|
||||||
/// One term of a P.838-3 curve fit.
|
/// One term of a P.838-3 curve fit.
|
||||||
|
|
@ -435,3 +435,39 @@ pub fn rain_attenuation(
|
||||||
pub const fn polarisation_tilt(degrees_from_horizontal: f64) -> f64 {
|
pub const fn polarisation_tilt(degrees_from_horizontal: f64) -> f64 {
|
||||||
degrees_from_horizontal * core::f64::consts::PI / 180.0
|
degrees_from_horizontal * core::f64::consts::PI / 180.0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the total rain attenuation along a slant path, taking the rain
|
||||||
|
/// height from the Recommendation P.839 model.
|
||||||
|
///
|
||||||
|
/// This is the same calculation as [`rain_attenuation`], with the rain layer
|
||||||
|
/// height looked up from the tabulated zero degree isotherm height at the
|
||||||
|
/// given latitude and longitude rather than supplied by the caller. It is
|
||||||
|
/// the form to use unless a locally measured isotherm height is available.
|
||||||
|
///
|
||||||
|
/// The station height must be given; pass zero for a station at sea level.
|
||||||
|
///
|
||||||
|
/// Returns `None` when the coordinates are not usable, or when any of the
|
||||||
|
/// other arguments is rejected by [`rain_attenuation`].
|
||||||
|
///
|
||||||
|
/// Source: the rain height is from ITU-R Recommendation P.839-4 and the path
|
||||||
|
/// method from ITU-R Recommendation P.618-13.
|
||||||
|
pub fn rain_attenuation_at(
|
||||||
|
rain_rate: f64,
|
||||||
|
frequency: f64,
|
||||||
|
polarisation: f64,
|
||||||
|
elevation: f64,
|
||||||
|
station_height_km: f64,
|
||||||
|
latitude: f64,
|
||||||
|
longitude: f64,
|
||||||
|
) -> Option<RainAttenuation> {
|
||||||
|
let rain_height_km = crate::p839::rain_height(latitude, longitude)?;
|
||||||
|
rain_attenuation(
|
||||||
|
rain_rate,
|
||||||
|
frequency,
|
||||||
|
polarisation,
|
||||||
|
elevation,
|
||||||
|
station_height_km,
|
||||||
|
rain_height_km,
|
||||||
|
latitude,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -393,3 +393,44 @@ fn polarisation_tilt_converts_degrees() {
|
||||||
"forty five degrees",
|
"forty five degrees",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_integrated_path_uses_the_p839_rain_height() {
|
||||||
|
use apsis_atmosphere::{rain_attenuation_at, rain_height};
|
||||||
|
let latitude = 45.0;
|
||||||
|
let longitude = 0.0;
|
||||||
|
let integrated = rain_attenuation_at(
|
||||||
|
20.0,
|
||||||
|
12.0e9,
|
||||||
|
HORIZONTAL,
|
||||||
|
THIRTY_DEGREES,
|
||||||
|
0.0,
|
||||||
|
latitude,
|
||||||
|
longitude,
|
||||||
|
)
|
||||||
|
.expect("valid");
|
||||||
|
let explicit = rain_attenuation(
|
||||||
|
20.0,
|
||||||
|
12.0e9,
|
||||||
|
HORIZONTAL,
|
||||||
|
THIRTY_DEGREES,
|
||||||
|
0.0,
|
||||||
|
rain_height(latitude, longitude).expect("valid coordinates"),
|
||||||
|
latitude,
|
||||||
|
)
|
||||||
|
.expect("valid");
|
||||||
|
assert!((integrated.attenuation_db - explicit.attenuation_db).abs() < 1e-12);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn the_integrated_path_rejects_unusable_coordinates() {
|
||||||
|
use apsis_atmosphere::rain_attenuation_at;
|
||||||
|
assert_eq!(
|
||||||
|
rain_attenuation_at(20.0, 12.0e9, HORIZONTAL, THIRTY_DEGREES, 0.0, 91.0, 0.0),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
rain_attenuation_at(20.0, 12.0e9, HORIZONTAL, THIRTY_DEGREES, 0.0, 0.0, f64::NAN),
|
||||||
|
None
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue