From baa8221b605ea88c9f379b2270bd4954c0387676 Mon Sep 17 00:00:00 2001 From: Beth Probert Date: Thu, 9 Apr 2026 16:04:49 +0100 Subject: [PATCH 1/3] Create system interaction diagram --- GEMINI.md | 54 ++++++++++++++++++++++++++++++++++ design/system_interactions.txt | 40 +++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 GEMINI.md create mode 100644 design/system_interactions.txt diff --git a/GEMINI.md b/GEMINI.md new file mode 100644 index 0000000..91a5829 --- /dev/null +++ b/GEMINI.md @@ -0,0 +1,54 @@ +# ACCORD Project Context + +Autonomous Cooperative Consensus Orbit Determination (ACCORD) is a decentralized framework for satellite operations in Low Earth Orbit (LEO). It uses a Directed Acyclic Graph (DAG)-based Distributed Ledger Technology (DLT) and a reputation-based Byzantine Fault Tolerant (BFT) consensus mechanism called Proof of Inter-Satellite Evaluation (PoISE). + +## Project Overview + +- **Core Technology:** Python 3.13 +- **Main Components:** + - `src/consensus_mech.py`: Implementation of the PoISE consensus mechanism. + - `src/dag.py`: Distributed ledger structure using a DAG. + - `src/filter.py`: Orbit determination logic (Extended Kalman Filter). + - `src/reputation.py`: Satellite reputation management. + - `src/satellite_node.py`: Satellite network node representation. + - `src/simulation.py`: Orbital dynamics and simulation helpers. +- **Demos:** + - `accord_demo.py`: Main demonstration of the framework. + - `mc_demo.py`: Monte Carlo simulation for performance evaluation. + - `streamlit_app.py`: Web-based visualization of results. + +## Building and Running + +### Environment Setup + +1. Create a virtual environment: + ```powershell + python -m venv venv + venv\Scripts\activate + ``` +2. Install dependencies: + - Windows: `pip install -r requirements_windows.txt` + - Linux/macOS: `pip install -r requirements.txt` + +### Running Demos + +- **Standard Demo:** `python accord_demo.py` +- **Monte Carlo Simulation:** `python mc_demo.py --num-runs 10` +- **Streamlit App:** `streamlit run streamlit_app.py` +- **Orbit Visualization:** `python src/visualise_orbits.py` + +### Testing and Quality + +- **Run Tests:** `pytest tests/` +- **Coverage:** `pytest --cov=src tests/` +- **Linting:** `pylint src/ tests/ accord_demo.py mc_demo.py streamlit_app.py` +- **Type Checking:** `mypy .` + +## Development Conventions + +- **Coding Style:** Adheres to PEP 8 (enforced via Pylint). Configuration is in `.pylintrc`. +- **Type Safety:** Uses static typing (checked via Mypy). Configuration is in `mypy.ini`. +- **Testing:** Uses `pytest` for unit testing. Configuration is in `.coveragerc`. +- **Documentation:** README.md provides a high-level overview and installation guide. +- **CI/CD:** GitHub Actions (`.github/workflows/main.yml`) runs Pylint, Mypy, and Pytest on every push. +- **Data Management:** Large simulation data is stored in `sim_data/` as `.npz` files. Git LFS is recommended if tracking these files. diff --git a/design/system_interactions.txt b/design/system_interactions.txt new file mode 100644 index 0000000..fcfa92e --- /dev/null +++ b/design/system_interactions.txt @@ -0,0 +1,40 @@ +@startuml + +participant "Simulation" as sim +participant "Filter" as filter +participant "Satellite" as sat +participant "Consensus (PoISE)" as poise +participant "Ledger (DAG)" as dag + +== Initialisation & Truth Generation == +sim -> sim: simulate_truth_and_meas(N, steps, dt) +note right + Generates truth_hist (ground truth orbits) + and z_hist (noisy ISL measurements) +end note + +sim -> filter: Create EKF instances (initialised with truth[0]) +sim -> sat: Create Satellite nodes +sim -> dag: Initialise DAG with PoISE + +== Simulation Loop == +loop for each timestep k + sim -> filter: predict() & update(z_hist[k]) + note right: Filter estimates state based on noisy measurements + filter -->> sim: ObservationRecords (with NIS) + + sim -> sat: update_position(truth_hist[k]) + + group In-Range Observation + sim -> sat: load_sensor_data(ObservationRecord) + sat -> dag: submit_transaction(queue) + end +end + +== Consensus (Async) == +dag -> dag: listen() to queue +dag -> poise: validate(transaction, reputation) +poise -->> dag: validation_result +dag -> sat: update_reputation() + +@enduml From 8f92a385d612c22ed5452634c72aab5d6ac457aa Mon Sep 17 00:00:00 2001 From: Beth Probert Date: Fri, 10 Apr 2026 13:56:48 +0100 Subject: [PATCH 2/3] Update filter simulation to only generate observation records when satellites are within 5000km of each other. This prevents physically impossible records beign generated which is not computationally efficient. --- design/system_interactions.txt | 12 ++++++++++++ images/system_interactions.png | Bin 0 -> 69809 bytes src/filter.py | 10 ++++++++++ tests/test_filter_ekf.py | 4 ++-- 4 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 images/system_interactions.png diff --git a/design/system_interactions.txt b/design/system_interactions.txt index fcfa92e..b3b478c 100644 --- a/design/system_interactions.txt +++ b/design/system_interactions.txt @@ -18,15 +18,27 @@ sim -> sat: Create Satellite nodes sim -> dag: Initialise DAG with PoISE == Simulation Loop == +/' +The simulation generates all possible observation records for a +maximum possible ISL range set at 5000km. This way, the ISL range +I want to test PoISE against can be set dynamically (up to the +5000km maximum), but also physically impossible observations +(such as 2 satellites at opposite sides of the earth seeing each +other) are not created as this wastes computational effort. +This is sufficient and efficient for research and testing. +'/ + loop for each timestep k sim -> filter: predict() & update(z_hist[k]) note right: Filter estimates state based on noisy measurements filter -->> sim: ObservationRecords (with NIS) + note right: Observation records generated for Max ISL for 5000km sim -> sat: update_position(truth_hist[k]) group In-Range Observation sim -> sat: load_sensor_data(ObservationRecord) + note right: Only loads observations within specified ISL range sat -> dag: submit_transaction(queue) end end diff --git a/images/system_interactions.png b/images/system_interactions.png new file mode 100644 index 0000000000000000000000000000000000000000..24e90553db8ffa0927224d86310e28c441884618 GIT binary patch literal 69809 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 gee3^8cFk>U?)$p|b>fwir|>5h<~C-}&RmNA4 MAX_ISL_RANGE: + # Advance index by 2 as every pair is range and range rate + idx += 2 + continue + yij = y[idx:idx+2] # Recalculate Ht and Ho for the current pair, this is necessary. @@ -507,6 +516,7 @@ def _log_nis(y: np.ndarray, ekf: ExtendedKalmanFilter, N: int, k: int, step=k, observer=i, target=j, nis=nis, dof=yij.shape[0], time = k*dt ) ) + # Advance index by 2 as every pair is range and range rate idx += 2 return obs_records diff --git a/tests/test_filter_ekf.py b/tests/test_filter_ekf.py index 2e4fd2f..ef3c91b 100644 --- a/tests/test_filter_ekf.py +++ b/tests/test_filter_ekf.py @@ -85,8 +85,8 @@ def test_joint_ekf_update(ekf, filter_config): assert not np.allclose(x_prior, x_posterior) # Check the observation records - expected_records = filter_config.N * (filter_config.N - 1) - assert len(obs_records) == expected_records + # Not all records are created due to the 5000km distance check + assert 0 < len(obs_records) <= filter_config.N * (filter_config.N - 1) for record in obs_records: assert record.step == 1 assert record.nis >= 0 From 8ee5baa909e14c03a14d6f5b42f74ba98651505e Mon Sep 17 00:00:00 2001 From: Beth Probert Date: Fri, 10 Apr 2026 16:37:26 +0100 Subject: [PATCH 3/3] Update file --- GEMINI.md | 54 ------------------------------------------------------ 1 file changed, 54 deletions(-) delete mode 100644 GEMINI.md diff --git a/GEMINI.md b/GEMINI.md deleted file mode 100644 index 91a5829..0000000 --- a/GEMINI.md +++ /dev/null @@ -1,54 +0,0 @@ -# ACCORD Project Context - -Autonomous Cooperative Consensus Orbit Determination (ACCORD) is a decentralized framework for satellite operations in Low Earth Orbit (LEO). It uses a Directed Acyclic Graph (DAG)-based Distributed Ledger Technology (DLT) and a reputation-based Byzantine Fault Tolerant (BFT) consensus mechanism called Proof of Inter-Satellite Evaluation (PoISE). - -## Project Overview - -- **Core Technology:** Python 3.13 -- **Main Components:** - - `src/consensus_mech.py`: Implementation of the PoISE consensus mechanism. - - `src/dag.py`: Distributed ledger structure using a DAG. - - `src/filter.py`: Orbit determination logic (Extended Kalman Filter). - - `src/reputation.py`: Satellite reputation management. - - `src/satellite_node.py`: Satellite network node representation. - - `src/simulation.py`: Orbital dynamics and simulation helpers. -- **Demos:** - - `accord_demo.py`: Main demonstration of the framework. - - `mc_demo.py`: Monte Carlo simulation for performance evaluation. - - `streamlit_app.py`: Web-based visualization of results. - -## Building and Running - -### Environment Setup - -1. Create a virtual environment: - ```powershell - python -m venv venv - venv\Scripts\activate - ``` -2. Install dependencies: - - Windows: `pip install -r requirements_windows.txt` - - Linux/macOS: `pip install -r requirements.txt` - -### Running Demos - -- **Standard Demo:** `python accord_demo.py` -- **Monte Carlo Simulation:** `python mc_demo.py --num-runs 10` -- **Streamlit App:** `streamlit run streamlit_app.py` -- **Orbit Visualization:** `python src/visualise_orbits.py` - -### Testing and Quality - -- **Run Tests:** `pytest tests/` -- **Coverage:** `pytest --cov=src tests/` -- **Linting:** `pylint src/ tests/ accord_demo.py mc_demo.py streamlit_app.py` -- **Type Checking:** `mypy .` - -## Development Conventions - -- **Coding Style:** Adheres to PEP 8 (enforced via Pylint). Configuration is in `.pylintrc`. -- **Type Safety:** Uses static typing (checked via Mypy). Configuration is in `mypy.ini`. -- **Testing:** Uses `pytest` for unit testing. Configuration is in `.coveragerc`. -- **Documentation:** README.md provides a high-level overview and installation guide. -- **CI/CD:** GitHub Actions (`.github/workflows/main.yml`) runs Pylint, Mypy, and Pytest on every push. -- **Data Management:** Large simulation data is stored in `sim_data/` as `.npz` files. Git LFS is recommended if tracking these files.