Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
67ac410
feat: minimum elevation for service grid point to satellite link
artistrea Nov 4, 2025
34f455d
fix(topology): imt mss dc topology could create num_stations = 0 fixed
artistrea Nov 5, 2025
9cd3acd
update(parameters): Added z and Lf as parameters for ITU-R S.1528 Rec…
brunohcfaria Nov 10, 2025
9443133
Merge branch 'development' into feat/minimum_elev_service_grid
brunohcfaria Nov 11, 2025
741f854
fix(propagation): Fixed the season parameter check in Atmosfere P.835 to
brunohcfaria Dec 2, 2025
595bddf
fix(simulation): Fixed simulator log facility setup
brunohcfaria Dec 4, 2025
70ef161
Merge remote-tracking branch 'origin/development' into feat/minimum_e…
brunohcfaria Dec 15, 2025
4cea239
Adding a modification that uses 1528 antenna + elevation angle
brunohcfaria Dec 17, 2025
a0f0b61
Prevented multiple antenna instances to be created for Satellite Beam…
brunohcfaria Dec 19, 2025
425d52a
update(antenna): Adding DC-MSS System4 antenna based on
brunohcfaria Dec 22, 2025
89def37
fix(topology): Fixed beam ground elevation shape.
brunohcfaria Jan 21, 2026
6faf697
update(topology): Power backoff zone implementation.
brunohcfaria Dec 22, 2025
075cbbd
update: where power control zone validation happens
artistrea Dec 22, 2025
f906bf9
fix: Fixing power control zone tests and lint errors.
brunohcfaria Jan 21, 2026
011b73d
fix(station_factory): Fixed missing geometry initialization in
brunohcfaria Jan 21, 2026
7742e11
refactor(simulation): Changed how system's power density is set in th…
brunohcfaria Jan 22, 2026
76b71a3
feat(simulation): Implementation of power backoff for DC-MSS as
brunohcfaria Jan 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions sharc/antenna/antenna_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ def create_antenna(
azimuth,
elevation
)
case "Antenna System 4":
# Handled in station_factory.py since it requires two antennas
raise NotImplementedError(
"Antenna System 4 requires two antenna instances and "
"should be created in station_factory.py"
)
case _:
raise ValueError(
f"Antenna factory does not support pattern {
Expand Down
41 changes: 25 additions & 16 deletions sharc/antenna/antenna_s1528.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,12 +175,18 @@ def __init__(self, param: ParametersAntennaS1528):
# the system design
self.l_s = param.antenna_l_s

# far-out side-lobe level [dBi]
if param.far_out_side_lobe is None:
self.l_f = 0
else:
self.l_f = param.far_out_side_lobe

# for elliptical antennas, this is the ratio major axis/minor axis
# we assume circular antennas, so z = 1
self.z = 1

# far-out side-lobe level [dBi]
self.l_f = 0
if param.major_minor_axis_ratio is None:
self.z = 1
else:
self.z = param.major_minor_axis_ratio

# back-lobe level
self.l_b = np.maximum(
Expand All @@ -190,19 +196,22 @@ def __init__(self, param: ParametersAntennaS1528):
# one-half the 3 dB beamwidth in the plane of interest
self.psi_b = param.antenna_3_dB_bw / 2

if self.l_s == -15:
self.a = 2.58 * math.sqrt(1 - 1.4 * math.log10(self.z))
elif self.l_s == -20:
self.a = 2.58 * math.sqrt(1 - 1.0 * math.log10(self.z))
elif self.l_s == -25:
self.a = 2.58 * math.sqrt(1 - 0.6 * math.log10(self.z))
elif self.l_s == -30:
self.a = 2.58 * math.sqrt(1 - 0.4 * math.log10(self.z))
if math.isclose(self.z, 1.0):
self.a = 2.58
else:
sys.stderr.write(
"ERROR\nInvalid AntennaS1528 L_s parameter: " + str(self.l_s),
)
sys.exit(1)
if self.l_s == -15:
self.a = 2.58 * math.sqrt(1 - 1.4 * math.log10(self.z))
elif self.l_s == -20:
self.a = 2.58 * math.sqrt(1 - 1.0 * math.log10(self.z))
elif self.l_s == -25:
self.a = 2.58 * math.sqrt(1 - 0.6 * math.log10(self.z))
elif self.l_s == -30:
self.a = 2.58 * math.sqrt(1 - 0.4 * math.log10(self.z))
else:
sys.stderr.write(
f"ERROR\nInvalid AntennaS1528 L_s parameter {self.l_s} for z={self.z}"
)
sys.exit(1)

self.b = 6.32
self.alpha = 1.5
Expand Down
8 changes: 8 additions & 0 deletions sharc/parameters/antenna/parameters_antenna_s1528.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ class ParametersAntennaS1528(ParametersBase):
l_r: float = None
l_t: float = None

# Recommends 1.2 only
# For elliptical antennas, this is the ratio major axis/minor axis
# we assume circular antennas, so z = 1
major_minor_axis_ratio: float = None

# Far-out side-lobe level
far_out_side_lobe: float = None

def load_parameters_from_file(self, config_file: str):
"""Load the parameters from file an run a sanity check.

Expand Down
48 changes: 48 additions & 0 deletions sharc/parameters/antenna/parameters_antenna_system4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# Implementation of ParametersAntennaSystem4 class
# The System 4 antenna was defined in WP4C Working Document 4C/356 from October 2025
# The antenna is based on S.1528 recommends 1.2
# It defines two sets of parameters for high elevation and low elevation beams
from dataclasses import dataclass, field

from sharc.parameters.parameters_base import ParametersBase
from sharc.parameters.antenna.parameters_antenna_s1528 import ParametersAntennaS1528


@dataclass
class ParametersAntennaSystem4(ParametersBase):
"""Dataclass containing the Antenna System 4 parameters for the simulator.
"""
section_name: str = "Antenna System 4"

# Parameters for high elevation beams
antenna_parameters_high: ParametersAntennaS1528 = field(
# we don't care about frequency and bandwidth here. Just to make validation work.
default_factory=lambda: ParametersAntennaS1528(
frequency=-1,
bandwidth=-1
)
)

# Parameters for low elevation beams
antenna_parameters_low: ParametersAntennaS1528 = field(
# we don't care about frequency and bandwidth here. Just to make validation work.
default_factory=lambda: ParametersAntennaS1528(
frequency=-1,
bandwidth=-1
)
)

def load_parameters_from_file(self, config_file: str):
"""Load the parameters from file an run a sanity check.

Parameters
----------
file_name : str
the path to the configuration file

Raises
------
ValueError
if a parameter is not valid
"""
super().load_parameters_from_file(config_file)
6 changes: 6 additions & 0 deletions sharc/parameters/imt/parameters_grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,9 @@ class ParametersSatelliteWithServiceGrid(ParametersTerrestrialGrid):

beam_radius: float = None

# [deg]
minimum_service_angle: float = 5.0

def validate(self, ctx):
"""Validates instance parameters.
Parameters
Expand All @@ -353,6 +356,9 @@ def validate(self, ctx):
)
self.cell_radius = self.beam_radius

if self.minimum_service_angle < 0. or self.minimum_service_angle > 90:
raise ValueError(f"{ctx}.minimum_service_angle should be in [0, 90]")

if not isinstance(
self.eligible_sats_margin_from_border,
float) and not isinstance(
Expand Down
33 changes: 32 additions & 1 deletion sharc/parameters/imt/parameters_imt_mss_dc.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@

from sharc.parameters.parameters_base import ParametersBase
from sharc.parameters.parameters_orbit import ParametersOrbit
from sharc.parameters.imt.parameters_grid import ParametersSatelliteWithServiceGrid, ParametersSelectActiveSatellite
from sharc.parameters.imt.parameters_grid import (
ParametersSatelliteWithServiceGrid,
ParametersSelectActiveSatellite,
ParametersZone,
)

SHARC_ROOT_DIR = (Path(__file__) / ".." / ".." / ".." / "..").resolve()

Expand Down Expand Up @@ -189,6 +193,30 @@ def validate(self, ctx):
)


@dataclass
class ParametersPowerControlZone(ParametersBase):
"""Dataclass for a power control zone in the IMT MSS-DC topology."""
geometry: ParametersZone = field(default_factory=ParametersZone)
power_backoff_db: float = None


@dataclass
class ParametersPowerControl(ParametersBase):
"""Dataclass for power control parameters in the IMT MSS-DC topology."""
zones: list[ParametersPowerControlZone] = field(
default_factory=lambda: [ParametersPowerControlZone()])

def validate(self, ctx):
"""
Validate the power control parameters.
"""
super().validate(ctx)
for i in range(len(self.zones)):
self.zones[i].geometry.validate(ctx + f"zones.{i}.geometry")
if not isinstance(self.zones[i].power_backoff_db, float):
raise ValueError("power_backoff_db is not properly defined.")


@dataclass
class ParametersImtMssDc(ParametersBase):
"""Dataclass for the IMT MSS-DC topology parameters."""
Expand All @@ -211,6 +239,9 @@ class ParametersImtMssDc(ParametersBase):
# for IMT Space Stations
beam_radius: float = 36516.0

power_control_zones: ParametersPowerControl = field(
default_factory=ParametersPowerControl)

sat_is_active_if: ParametersSelectActiveSatellite = field(
default_factory=ParametersSelectActiveSatellite)

Expand Down
13 changes: 11 additions & 2 deletions sharc/parameters/parameters_antenna.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from sharc.parameters.antenna.parameters_antenna_s672 import ParametersAntennaS672
from sharc.parameters.antenna.parameters_antenna_with_freq import ParametersAntennaWithFreq
from sharc.parameters.imt.parameters_antenna_imt import ParametersAntennaImt
from sharc.parameters.antenna.parameters_antenna_system4 import ParametersAntennaSystem4

from dataclasses import dataclass, field
import typing
Expand All @@ -29,7 +30,8 @@ class ParametersAntenna(ParametersBase):
"ITU-R-S.1528-Taylor",
"ITU-R-S.1528-Section1.2",
"ITU-R-S.1528-LEO",
"MSS Adjacent"]
"MSS Adjacent",
"Antenna System 4"]

# chosen antenna radiation pattern
pattern: typing.Literal["OMNI",
Expand All @@ -44,7 +46,8 @@ class ParametersAntenna(ParametersBase):
"ITU-R-S.1528-Taylor",
"ITU-R-S.1528-Section1.2",
"ITU-R-S.1528-LEO",
"MSS Adjacent"] = None
"MSS Adjacent",
"Antenna System 4"] = None

# antenna gain [dBi]
gain: float = None
Expand Down Expand Up @@ -94,6 +97,10 @@ class ParametersAntenna(ParametersBase):
default_factory=ParametersAntennaS672,
)

antenna_system_4: ParametersAntennaSystem4 = field(
default_factory=ParametersAntennaSystem4,
)

def set_external_parameters(self, **kwargs):
"""
Set external parameters for all sub-parameters of the antenna.
Expand Down Expand Up @@ -198,6 +205,8 @@ def validate(self, ctx):
self.itu_r_s_672.validate(f"{ctx}.itu_r_s_672")
case "MSS Adjacent":
self.mss_adjacent.validate(f"{ctx}.mss_adjacent")
case "Antenna System 4":
self.antenna_system_4.validate(f"{ctx}.antenna_system_4")
case _:
raise NotImplementedError(
"ParametersAntenna.validate does not implement this antenna validation!", )
9 changes: 8 additions & 1 deletion sharc/parameters/parameters_mss_d2d.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@
from dataclasses import dataclass, field, asdict
from sharc.parameters.parameters_base import ParametersBase
from sharc.parameters.parameters_orbit import ParametersOrbit
from sharc.parameters.imt.parameters_imt_mss_dc import ParametersSelectActiveSatellite, ParametersSectorPositioning
from sharc.parameters.imt.parameters_imt_mss_dc import (
ParametersSelectActiveSatellite,
ParametersSectorPositioning,
ParametersPowerControl
)
from sharc.parameters.parameters_p619 import ParametersP619
from sharc.parameters.parameters_antenna import ParametersAntenna
from sharc.parameters.antenna.parameters_antenna_s1528 import ParametersAntennaS1528
Expand Down Expand Up @@ -40,6 +44,9 @@ class ParametersMssD2d(ParametersBase):
# active
beams_load_factor: float = 1.0

power_control_zones: ParametersPowerControl = field(
default_factory=ParametersPowerControl)

# Central beam positioning
beam_positioning: ParametersSectorPositioning = field(
default_factory=ParametersSectorPositioning)
Expand Down
3 changes: 3 additions & 0 deletions sharc/propagation/atmosphere.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,9 @@ def get_reference_atmosphere_p835(
"""

h_km = altitude / 1000
season = season.lower()
if season not in ['winter', 'summer']:
raise ValueError(f"Invalid season name f{season}.")

if latitude <= 22:
# low latitude
Expand Down
Loading