Skip to content

Instantly share code, notes, and snippets.

@arget13
Created February 7, 2025 17:46
Show Gist options
  • Save arget13/9951224a6528ea5f753a8a3c52e1a636 to your computer and use it in GitHub Desktop.
Save arget13/9951224a6528ea5f753a8a3c52e1a636 to your computer and use it in GitHub Desktop.
A quick and lazy implementation of P.676
# Quick implementation of ITU's recommendation P.676 (current v13, 8/2022)
# Please note: I'm not a python programmer (I prefer C/asm), so there probably
# are ways to minimize the loss of precission that I don't know of
import numpy as np
def _gaspl(d, f, T, p, den):
d = d / 1000 # km
f = f / 1e9 # GHz
T = 273.15 + T # K
p = p / 100 # hPa
# Spectrum lines of oxygen
oxy = np.array([
# f_0 a_1 a_2 a_3 a_4 a_5 a_6
[50.474214, 0.975, 9.651, 6.690, 0.0, 2.566, 6.850],
[50.987745, 2.529, 8.653, 7.170, 0.0, 2.246, 6.800],
[51.503360, 6.193, 7.709, 7.640, 0.0, 1.947, 6.729],
[52.021429, 14.320, 6.819, 8.110, 0.0, 1.667, 6.640],
[52.542418, 31.240, 5.983, 8.580, 0.0, 1.388, 6.526],
[53.066934, 64.290, 5.201, 9.060, 0.0, 1.349, 6.206],
[53.595775, 124.600, 4.474, 9.550, 0.0, 2.227, 5.085],
[54.130025, 227.300, 3.800, 9.960, 0.0, 3.170, 3.750],
[54.671180, 389.700, 3.182, 10.370, 0.0, 3.558, 2.654],
[55.221384, 627.100, 2.618, 10.890, 0.0, 2.560, 2.952],
[55.783815, 945.300, 2.109, 11.340, 0.0, -1.172, 6.135],
[56.264774, 543.400, 0.014, 17.030, 0.0, 3.525, -0.978],
[56.363399, 1331.800, 1.654, 11.890, 0.0, -2.378, 6.547],
[56.968211, 1746.600, 1.255, 12.230, 0.0, -3.545, 6.451],
[57.612486, 2120.100, 0.910, 12.620, 0.0, -5.416, 6.056],
[58.323877, 2363.700, 0.621, 12.950, 0.0, -1.932, 0.436],
[58.446588, 1442.100, 0.083, 14.910, 0.0, 6.768, -1.273],
[59.164204, 2379.900, 0.387, 13.530, 0.0, -6.561, 2.309],
[59.590983, 2090.700, 0.207, 14.080, 0.0, 6.957, -0.776],
[60.306056, 2103.400, 0.207, 14.150, 0.0, -6.395, 0.699],
[60.434778, 2438.000, 0.386, 13.390, 0.0, 6.342, -2.825],
[61.150562, 2479.500, 0.621, 12.920, 0.0, 1.014, -0.584],
[61.800158, 2275.900, 0.910, 12.630, 0.0, 5.014, -6.619],
[62.411220, 1915.400, 1.255, 12.170, 0.0, 3.029, -6.759],
[62.486253, 1503.000, 0.083, 15.130, 0.0, -4.499, 0.844],
[62.997984, 1490.200, 1.654, 11.740, 0.0, 1.856, -6.675],
[63.568526, 1078.000, 2.108, 11.340, 0.0, 0.658, -6.139],
[64.127775, 728.700, 2.617, 10.880, 0.0, -3.036, -2.895],
[64.678910, 461.300, 3.181, 10.380, 0.0, -3.968, -2.590],
[65.224078, 274.000, 3.800, 9.960, 0.0, -3.528, -3.680],
[65.764779, 153.000, 4.473, 9.550, 0.0, -2.548, -5.002],
[66.302096, 80.400, 5.200, 9.060, 0.0, -1.660, -6.091],
[66.836834, 39.800, 5.982, 8.580, 0.0, -1.680, -6.393],
[67.369601, 18.560, 6.818, 8.110, 0.0, -1.956, -6.475],
[67.900868, 8.172, 7.708, 7.640, 0.0, -2.216, -6.545],
[68.431006, 3.397, 8.652, 7.170, 0.0, -2.492, -6.600],
[68.960312, 1.334, 9.650, 6.690, 0.0, -2.773, -6.650],
[118.750334, 940.300, 0.010, 16.640, 0.0, -0.439, 0.079],
[368.498246, 67.400, 0.048, 16.400, 0.0, 0.000, 0.000],
[424.763020, 637.700, 0.044, 16.400, 0.0, 0.000, 0.000],
[487.249273, 237.400, 0.049, 16.000, 0.0, 0.000, 0.000],
[715.392902, 98.100, 0.145, 16.000, 0.0, 0.000, 0.000],
[773.839490, 572.300, 0.141, 16.200, 0.0, 0.000, 0.000],
[834.145546, 183.100, 0.145, 14.700, 0.0, 0.000, 0.000]
])
# Spectrum lines of water
wat = np.array([
# f_0 b_1 b_2 b_3 b_4 b_5 b_6
[22.235080, .1079, 2.144, 26.38, .76, 5.087, 1.00],
[67.803960, .0011, 8.732, 28.58, .69, 4.930, .82],
[119.995940, .0007, 8.353, 29.48, .70, 4.780, .79],
[183.310087, 2.273, .668, 29.06, .77, 5.022, .85],
[321.225630, .0470, 6.179, 24.04, .67, 4.398, .54],
[325.152888, 1.514, 1.541, 28.23, .64, 4.893, .74],
[336.227764, .0010, 9.825, 26.93, .69, 4.740, .61],
[380.197353, 11.67, 1.048, 28.11, .54, 5.063, .89],
[390.134508, .0045, 7.347, 21.52, .63, 4.810, .55],
[437.346667, .0632, 5.048, 18.45, .60, 4.230, .48],
[439.150807, .9098, 3.595, 20.07, .63, 4.483, .52],
[443.018343, .1920, 5.048, 15.55, .60, 5.083, .50],
[448.001085, 10.41, 1.405, 25.64, .66, 5.028, .67],
[470.888999, .3254, 3.597, 21.34, .66, 4.506, .65],
[474.689092, 1.260, 2.379, 23.20, .65, 4.804, .64],
[488.490108, .2529, 2.852, 25.86, .69, 5.201, .72],
[503.568532, .0372, 6.731, 16.12, .61, 3.980, .43],
[504.482692, .0124, 6.731, 16.12, .61, 4.010, .45],
[547.676440, .9785, .158, 26.00, .70, 4.500, 1.00],
[552.020960, .1840, .158, 26.00, .70, 4.500, 1.00],
[556.935985, 497.0, .159, 30.86, .69, 4.552, 1.00],
[620.700807, 5.015, 2.391, 24.38, .71, 4.856, .68],
[645.766085, .0067, 8.633, 18.00, .60, 4.000, .50],
[658.005280, .2732, 7.816, 32.10, .69, 4.140, 1.00],
[752.033113, 243.4, .396, 30.86, .68, 4.352, .84],
[841.051732, .0134, 8.177, 15.90, .33, 5.760, .45],
[859.965698, .1325, 8.055, 30.60, .68, 4.090, .84],
[899.303175, .0547, 7.914, 29.85, .68, 4.530, .90],
[902.611085, .0386, 8.429, 28.65, .70, 5.100, .95],
[906.205957, .1836, 5.110, 24.08, .70, 4.700, .53],
[916.171582, 8.400, 1.441, 26.73, .70, 5.150, .78],
[923.112692, .0079, 10.293, 29.00, .70, 5.000, .80],
[970.315022, 9.009, 1.919, 25.50, .64, 4.940, .67],
[987.926764, 134.6, .257, 29.85, .68, 4.550, .90],
[1780.000000, 17506., .952, 196.3, 2.0, 24.15, 5.00]
])
theta = 300 / T
e = den * T / 216.7 # Water vapour pressure
# a(0) and b(0) are the freq itself
a = lambda i: oxy[:,i]
b = lambda i: wat[:,i]
# Strength of each spectrum line
S_oxy = a(1) * 1e-7 * p * theta**3 * np.exp(a(2) * (1 - theta))
S_wat = b(1) * 1e-1 * e * theta**3.5 * np.exp(b(2) * (1 - theta))
# Width of each line [dfo = (delta f)_oxygen]
dfo = a(3) * 1e-4 * (p * theta**(.8 - a(4)) + 1.1 * e * theta)
dfo = np.sqrt(dfo**2 + 2.25e-6)
dfw = b(3) * 1e-4 * (p * theta**b(4) + b(5) * e * theta**b(6))
dfw = .535 * dfw + np.sqrt(.217 * dfw**2 + 2.1316e-12 * b(0)**2 / theta)
# A correction factor for oxygen lines
delta = (a(5) + a(6) * theta) * 1e-4 * (p + e) * theta**.8
# Shape factors
F_oxy = f / a(0)
F_oxy *= (dfo - delta * (a(0) - f)) / ((a(0) - f)**2 + dfo**2) + \
(dfo - delta * (a(0) + f)) / ((a(0) + f)**2 + dfo**2);
F_wat = f / b(0)
F_wat *= dfw / ((b(0) - f)**2 + dfw**2) + dfw / ((b(0) + f)**2 + dfw**2)
# Nitrogen absorption + Debye model
dw = 5.6e-4 * (p + e) * theta**.8
Nd = f * p * theta**2
Nd *= 6.16e-5 / (dw * (1 + (f / dw)**2)) + \
(1.4e-12 * p * theta**1.5) / (1 + 1.9e-5 * f**1.5)
gamma = (np.dot(S_oxy, F_oxy) + Nd + np.dot(S_wat, F_wat)) * .1820 * f
return gamma * d
gaspl = np.vectorize(_gaspl)
# import matplotlib.pyplot as plt
# f = np.linspace(1, 1000, 1000) * 1e9
# L = np.log(gaspl(1000, f, 15, 101325, 7.5))
# plt.plot(f, L)
# L = np.log(gaspl(1000, f, 15, 101325, 0))
# plt.plot(f, L)
# plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment