@mytec: iter5 ready for test
This commit is contained in:
@@ -42,6 +42,13 @@ self.onmessage = function (e) {
|
||||
|
||||
/**
|
||||
* Calculate RSRP at a specific point (universal formula)
|
||||
*
|
||||
* RSRP = P_tx + G_tx - FSPL - PatternLoss
|
||||
*
|
||||
* Includes:
|
||||
* - Antenna gain (site.gain)
|
||||
* - 3GPP sector pattern with back lobe (no hard cutoff)
|
||||
* - Radio horizon limit based on antenna height
|
||||
*/
|
||||
function calculatePointRSRP(site, point) {
|
||||
var distance = haversineDistance(site.lat, site.lon, point.lat, point.lon);
|
||||
@@ -49,6 +56,14 @@ function calculatePointRSRP(site, point) {
|
||||
// Minimum distance to prevent -Infinity
|
||||
if (distance < 0.01) distance = 0.01;
|
||||
|
||||
// Radio horizon check: d_horizon = 3.57 * sqrt(h_meters)
|
||||
// Uses 4/3 Earth radius for standard atmospheric refraction
|
||||
var siteHeight = site.height || 10; // default 10m if missing
|
||||
var horizon = calculateRadioHorizon(siteHeight);
|
||||
if (distance > horizon) {
|
||||
return -Infinity;
|
||||
}
|
||||
|
||||
// Free space path loss (universal)
|
||||
var fspl =
|
||||
20 * Math.log10(distance) + 20 * Math.log10(site.frequency) + 32.45;
|
||||
@@ -56,31 +71,63 @@ function calculatePointRSRP(site, point) {
|
||||
// Link budget: RSRP = P_tx + G_tx - FSPL
|
||||
var rsrp = site.power + site.gain - fspl;
|
||||
|
||||
// Apply sector antenna directivity: hard cutoff + gradual pattern loss
|
||||
// Apply 3GPP sector antenna pattern (main lobe + side lobes + back lobe)
|
||||
// No hard cutoff — back lobe is attenuated by front-to-back ratio (~25 dB)
|
||||
if (site.antennaType === 'sector' && site.azimuth !== undefined) {
|
||||
var bearing = calculateBearing(site.lat, site.lon, point.lat, point.lon);
|
||||
var relativeAngle = Math.abs(bearing - site.azimuth);
|
||||
var normalizedAngle =
|
||||
relativeAngle > 180 ? 360 - relativeAngle : relativeAngle;
|
||||
|
||||
var beamwidth = site.beamwidth || 65;
|
||||
var frontBackRatio = 25; // dB, typical for sector panel antennas
|
||||
|
||||
// Hard cutoff: no signal outside beamwidth
|
||||
if (normalizedAngle > beamwidth / 2) {
|
||||
return -Infinity;
|
||||
}
|
||||
|
||||
// Gradual 3GPP pattern loss within beamwidth
|
||||
var patternLoss = calculateSectorPatternLoss(
|
||||
normalizedAngle,
|
||||
beamwidth
|
||||
var patternLoss = calculate3GPPPattern(
|
||||
site.azimuth,
|
||||
bearing,
|
||||
beamwidth,
|
||||
frontBackRatio
|
||||
);
|
||||
rsrp -= patternLoss;
|
||||
rsrp -= patternLoss; // patternLoss is positive dB
|
||||
}
|
||||
|
||||
return rsrp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Radio horizon distance in km.
|
||||
* d = 3.57 * sqrt(h) where h is antenna height in meters.
|
||||
* Accounts for 4/3 Earth radius (standard atmosphere refraction).
|
||||
*/
|
||||
function calculateRadioHorizon(heightMeters) {
|
||||
return 3.57 * Math.sqrt(heightMeters);
|
||||
}
|
||||
|
||||
/**
|
||||
* 3GPP TR 36.814 Horizontal Antenna Pattern.
|
||||
*
|
||||
* A(θ) = min[ 12 * (θ / θ_3dB)², A_m ]
|
||||
*
|
||||
* Returns POSITIVE dB loss value (to be subtracted from RSRP).
|
||||
*
|
||||
* - θ = angular offset from boresight (0-180°)
|
||||
* - θ_3dB = half-power beamwidth / 2
|
||||
* - A_m = maximum attenuation = front-to-back ratio
|
||||
*
|
||||
* At 0° → 0 dB loss (boresight)
|
||||
* At ±θ_3dB → 3 dB loss (half-power points)
|
||||
* At ±90° → capped at A_m (~25 dB)
|
||||
* At 180° → capped at A_m (~25 dB, back lobe)
|
||||
*/
|
||||
function calculate3GPPPattern(azimuth, bearing, beamwidth, frontBackRatio) {
|
||||
// Normalize angle difference to -180…+180
|
||||
var angleDiff = bearing - azimuth;
|
||||
while (angleDiff > 180) angleDiff -= 360;
|
||||
while (angleDiff < -180) angleDiff += 360;
|
||||
|
||||
var theta = Math.abs(angleDiff);
|
||||
var theta3dB = beamwidth / 2;
|
||||
var Am = frontBackRatio;
|
||||
|
||||
return Math.min(12 * Math.pow(theta / theta3dB, 2), Am);
|
||||
}
|
||||
|
||||
/**
|
||||
* Haversine distance in km
|
||||
*/
|
||||
@@ -116,16 +163,3 @@ function calculateBearing(lat1, lon1, lat2, lon2) {
|
||||
var bearing = (Math.atan2(y, x) * 180) / Math.PI;
|
||||
return (bearing + 360) % 360;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sector antenna pattern loss (3GPP model)
|
||||
*/
|
||||
function calculateSectorPatternLoss(angleOffBoresight, beamwidth) {
|
||||
var theta3dB = beamwidth / 2;
|
||||
var sideLobeLevel = 20;
|
||||
|
||||
return Math.min(
|
||||
12 * Math.pow(angleOffBoresight / theta3dB, 2),
|
||||
sideLobeLevel
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user