Skip to content

Commit 817895e

Browse files
committed
Issue #0: Optimize communication when all satellites are talking
1 parent 2eed677 commit 817895e

4 files changed

Lines changed: 55 additions & 9 deletions

File tree

‎docs/source/release_notes.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Development Version
2525
type.
2626
* Improve performance of :class:`~bsk_rl.obs.Eclipse` observations by about 95%.
2727
* Logs a warning if the initial battery charge or buffer level is incompatible with its capacity.
28+
* Optimize communication when all satellites are communicating with each other.
2829

2930

3031

‎src/bsk_rl/comm/communication.py‎

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
import logging
44
from abc import ABC, abstractmethod
5+
from copy import copy
56
from itertools import combinations
6-
from typing import TYPE_CHECKING, Optional
7+
from typing import TYPE_CHECKING
78

89
import numpy as np
910
from scipy.sparse.csgraph import connected_components
11+
from scipy.special import comb
1012

1113
from bsk_rl.sim.dyn import LOSCommDynModel
1214
from bsk_rl.utils.functional import Resetable
@@ -60,18 +62,34 @@ def communicate(self) -> None:
6062
return
6163

6264
communication_pairs = self.communication_pairs()
65+
6366
if len(communication_pairs) > 0:
6467
logger.info(
6568
f"Communicating data between {len(communication_pairs)} pairs of satellites"
6669
)
6770

68-
for sat_1, sat_2 in communication_pairs:
69-
sat_1.data_store.stage_communicated_data(sat_2.data_store.data)
70-
sat_2.data_store.stage_communicated_data(sat_1.data_store.data)
71-
for satellite in self.satellites:
72-
satellite.data_store.update_with_communicated_data()
71+
if len(communication_pairs) == comb(len(self.satellites), 2):
72+
self._communicate_all()
73+
else:
74+
for sat_1, sat_2 in communication_pairs:
75+
sat_1.data_store.stage_communicated_data(sat_2.data_store.data)
76+
sat_2.data_store.stage_communicated_data(sat_1.data_store.data)
77+
for satellite in self.satellites:
78+
satellite.data_store.update_with_communicated_data()
79+
7380
self.last_communication_time = self.satellites[0].simulator.sim_time
7481

82+
def _communicate_all(self):
83+
"""Optimized communication between all pairs of satellites."""
84+
logger.info("Optimizing data communication between all pairs of satellites")
85+
86+
data_type = self.satellites[0].data_store.data.__class__
87+
final_data = data_type()
88+
for satellite in self.satellites:
89+
final_data += satellite.data_store.data
90+
for satellite in self.satellites:
91+
satellite.data_store.data = copy(final_data)
92+
7593

7694
class NoCommunication(CommunicationMethod):
7795
"""Implements no communication between satellites."""

‎src/bsk_rl/data/base.py‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ def __add__(self, other: "Data") -> "Data":
2929
"""Define the combination of two units of data."""
3030
pass
3131

32+
def __copy__(self) -> "Data":
33+
"""Create a shallow copy of the data."""
34+
return self.__class__() + self
35+
3236

3337
class DataStore(ABC):
3438
"""Base class for satellite data logging."""

‎tests/unittest/comm/test_communication.py‎

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
@patch.multiple(CommunicationMethod, __abstractmethods__=set())
1616
class TestCommunicationMethod:
1717
def test_communicate(self):
18-
mock_sats = [MagicMock(), MagicMock()]
18+
mock_sats = [MagicMock(), MagicMock(), MagicMock()]
1919
mock_sats[0].simulator.sim_time = 0.0
2020
comms = CommunicationMethod()
2121
comms.last_communication_time = 0.0
@@ -34,7 +34,7 @@ def test_communicate(self):
3434
sat.data_store.update_with_communicated_data.assert_called_once()
3535

3636
def test_min_period_elapsed(self):
37-
mock_sats = [MagicMock(), MagicMock()]
37+
mock_sats = [MagicMock(), MagicMock(), MagicMock()]
3838
comms = CommunicationMethod(min_period=1.0)
3939
comms.link_satellites(mock_sats)
4040
comms.communication_pairs = MagicMock(
@@ -47,7 +47,7 @@ def test_min_period_elapsed(self):
4747
sat.data_store.update_with_communicated_data.assert_called_once()
4848

4949
def test_min_period_not_elapsed(self):
50-
mock_sats = [MagicMock(), MagicMock()]
50+
mock_sats = [MagicMock(), MagicMock(), MagicMock()]
5151
comms = CommunicationMethod(min_period=1.0)
5252
comms.link_satellites(mock_sats)
5353
comms.communication_pairs = MagicMock(
@@ -59,6 +59,29 @@ def test_min_period_not_elapsed(self):
5959
for sat in mock_sats:
6060
sat.data_store.update_with_communicated_data.assert_not_called()
6161

62+
def test_override_communicate_all(self):
63+
mock_sats = [MagicMock() for i in range(3)]
64+
comms = FreeCommunication()
65+
comms.last_communication_time = 0.0
66+
mock_sats[0].simulator.sim_time = 1.0
67+
comms.link_satellites(mock_sats)
68+
comms._communicate_all = MagicMock()
69+
comms.communicate()
70+
comms._communicate_all.assert_called_once()
71+
72+
def test_override_communicate_all_nocall(self):
73+
mock_sats = [MagicMock() for i in range(3)]
74+
comms = CommunicationMethod()
75+
comms.communication_pairs = MagicMock(
76+
return_value=[(mock_sats[1], mock_sats[0])]
77+
)
78+
comms.last_communication_time = 0.0
79+
mock_sats[0].simulator.sim_time = 1.0
80+
comms.link_satellites(mock_sats)
81+
comms._communicate_all = MagicMock()
82+
comms.communicate()
83+
comms._communicate_all.assert_not_called()
84+
6285

6386
class TestNoCommunication:
6487
def test_communicate(self):

0 commit comments

Comments
 (0)