adsb-generator 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Adam Hamri (adamhamri9)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.4
2
+ Name: adsb-generator
3
+ Version: 0.1.0
4
+ Summary: `adsb-generator` produces realistic I/Q (In-phase/Quadrature) samples of clean and impaired ADS-B (Mode S Downlink Format 17) baseband signals, along with the raw 112-bit message and all applied parameters. It implements an infinite iterator that streams reproducible samples with full control over message type distributions, transmission parameters, and channel impairments.
5
+ Author-email: Adam Hamri <adamhamri9@proton.me>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/adamhamri9/adsb-datagen
8
+ Project-URL: Repository, https://github.com/adamhamri9/adsb-datagen
9
+ Project-URL: Issues, https://github.com/adamhamri9/adsb-datagen/issues
10
+ Keywords: adsb,mode-s,aviation,signal-generation,iq-samples,baseband
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering
21
+ Classifier: Topic :: Communications :: Ham Radio
22
+ Requires-Python: <3.14,>=3.10
23
+ Description-Content-Type: text/markdown
24
+ License-File: LICENSE
25
+ Requires-Dist: numpy>=1.26.0
26
+ Provides-Extra: dev
27
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # adsb-generator
31
+
32
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
33
+ [![Python 3.10+](https://img.shields.io/badge/Python-3.10+-3776AB.svg)](https://www.python.org/downloads/)
34
+
35
+ **Synthetic ADS-B data generator.**
36
+
37
+ `adsb-generator` produces realistic I/Q (In-phase/Quadrature) samples of clean and impaired ADS-B (Mode S Downlink Format 17) baseband signals, along with the raw 112-bit message and all applied parameters. It implements an infinite iterator that streams reproducible samples with full control over message type distributions, transmission parameters, and channel impairments.
38
+
39
+ ## Key Features
40
+
41
+ - **End-to-end pipeline**: random message generation, PPM encoding, and RF channel simulation in a single call.
42
+ - **Four ADS-B message types**: identification, surface position, airborne position, and airborne velocity with configurable emission probabilities.
43
+ - **Realistic channel impairments**: Gaussian Noise(both AWGN and Correlated) , frequency & phase offset, IQ imbalance, and DC offset, all sampled from configurable probability distributions.
44
+ - **Reproducibility**: deterministic output via a shared seed across all pipeline stages.
45
+ - **Configurable distributions**: override any transmission or channel parameter distribution to model specific receiver conditions or hardware behavior.
46
+ - **NumPy-native**: all signals are `np.complex64` arrays, ready for direct use with any downstream processing tool.
47
+
48
+ ## Requirements
49
+
50
+ - Python 3.10+
51
+ - NumPy
52
+
53
+ ## Installation
54
+
55
+ ```bash
56
+ pip install adsb-generator
57
+ ```
58
+
59
+ ## Usage
60
+
61
+ ```python
62
+ from adsb_generator import ADSBGenerator
63
+
64
+ # Create a generator with a fixed seed for reproducibility
65
+ gen = ADSBGenerator(seed=42)
66
+
67
+ # Each iteration yields an ADSBSample with the raw message,
68
+ # clean signal, and channel-impaired signal
69
+ for sample in gen:
70
+ print(f"Message type : {sample.message_type.value}")
71
+ print(f"Raw message : {sample.message:#028x}")
72
+ print(f"Clean signal : {sample.clean_signal.shape} complex64 samples")
73
+ print(f"Noisy signal : {sample.channel_signal.shape} complex64 samples")
74
+ print(f"SNR (dB) : {sample.channel_params['snr_db']:.1f}")
75
+ print(f"Amplitude : {sample.tx_params['amplitude']:.3f}")
76
+ break
77
+ ```
78
+
79
+ ### Customizing Distributions
80
+
81
+ ```python
82
+ from adsb_generator import ADSBGenerator, MessageType, ChannelParams
83
+
84
+ # Favor airborne positions, restrict SNR to low-moderate range
85
+ gen = ADSBGenerator(
86
+ message_type_probs={
87
+ MessageType.AIRBORNE_POSITION: 0.60,
88
+ MessageType.AIRBORNE_VELOCITY: 0.20,
89
+ MessageType.IDENTIFICATION: 0.10,
90
+ MessageType.SURFACE_POSITION: 0.10,
91
+ },
92
+ channel_params_distributions={
93
+ ChannelParams.SNR_DB: [
94
+ [3.0, 8.0, 0.70],
95
+ [8.0, 15.0, 0.30],
96
+ ],
97
+ },
98
+ sample_rate=2e6,
99
+ seed=12345,
100
+ )
101
+
102
+ sample = next(gen)
103
+ ```
104
+
105
+ ## API Reference
106
+
107
+ ### `ADSBGenerator`
108
+
109
+ ```python
110
+ ADSBGenerator(
111
+ message_type_probs: dict[MessageType | str, float] | None = None,
112
+ tx_params_distributions: dict[TXParams | str, list[list[float]]] | None = None,
113
+ channel_params_distributions: dict[ChannelParams | str, list[list[float]]] | None = None,
114
+ sample_rate: float = 2e6,
115
+ seed: int | None = None,
116
+ )
117
+ ```
118
+
119
+ | Parameter | Type | Default | Description |
120
+ |---|---|---|---|
121
+ | `message_type_probs` | `dict` or `None` | Equal 25% per type | Mapping of `MessageType` to emission probabilities (must sum to 1.0). |
122
+ | `tx_params_distributions` | `dict` or `None` | Single amplitude band | Mapping of `TXParams` to `[[min, max, weight], ...]` intervals. |
123
+ | `channel_params_distributions` | `dict` or `None` | Typical ADS-B conditions | Mapping of `ChannelParams` to `[[min, max, weight], ...]` intervals. |
124
+ | `sample_rate` | `float` | `2e6` | Sampling rate in samples per second. |
125
+ | `seed` | `int` or `None` | Random | Seed for deterministic output across all pipeline stages. |
126
+
127
+ ---
128
+
129
+ ### `ADSBSample`
130
+
131
+ Dataclass returned by each iteration of `ADSBGenerator`.
132
+
133
+ | Field | Type | Description |
134
+ |---|---|---|
135
+ | `message` | `int` | Complete 112-bit ADS-B message (including 24-bit CRC) as an integer. |
136
+ | `message_type` | `MessageType` | The type of ADS-B message generated. |
137
+ | `clean_signal` | `np.ndarray` | Complex baseband I/Q signal before channel impairments (`complex64`). |
138
+ | `tx_params` | `dict[TXParams, float]` | Transmission parameters applied during encoding. |
139
+ | `channel_signal` | `np.ndarray` | Complex baseband I/Q signal after channel impairments (`complex64`). |
140
+ | `channel_params` | `dict[ChannelParams, float]` | Channel parameters applied to the signal. |
141
+
142
+ ---
143
+
144
+ ### `MessageType`
145
+
146
+ | Value | Description |
147
+ |---|---|
148
+ | `IDENTIFICATION` | Aircraft identification (callsign) messages (TC 1--4). |
149
+ | `SURFACE_POSITION` | Surface position messages (TC 5--8). |
150
+ | `AIRBORNE_POSITION` | Airborne position messages (TC 9--18, 20--22). |
151
+ | `AIRBORNE_VELOCITY` | Airborne velocity messages (TC 19). |
152
+
153
+ ---
154
+
155
+ ### `ADSBEncoder`
156
+
157
+ Encodes 112-bit messages into complex baseband I/Q samples using PPM per the Mode S standard.
158
+
159
+ ```python
160
+ ADSBEncoder(
161
+ sample_rate: float = 2e6,
162
+ tx_params_distributions: dict[TXParams | str, list[list[float]]] | None = None,
163
+ seed: int | None = None,
164
+ )
165
+ ```
166
+
167
+ | Method | Returns | Description |
168
+ |---|---|---|
169
+ | `encode(msg: int)` | `tuple[np.ndarray, dict[TXParams, float]]` | Encodes a 112-bit message into a 120-us baseband I/Q signal. |
170
+
171
+ ---
172
+
173
+ ### `ADSBChannel`
174
+
175
+ Simulates realistic RF channel impairments on baseband I/Q signals.
176
+
177
+ ```python
178
+ ADSBChannel(
179
+ sample_rate: float = 2e6,
180
+ channel_params_distributions: dict[ChannelParams | str, list[list[float]]] | None = None,
181
+ seed: int | None = None,
182
+ )
183
+ ```
184
+
185
+ | Method | Returns | Description |
186
+ |---|---|---|
187
+ | `apply(signal: np.ndarray)` | `tuple[np.ndarray, dict[ChannelParams, float]]` | Applies impairments: IQ imbalance, DC offset, frequency offset, phase offset, AWGN. |
188
+
189
+ ---
190
+
191
+ ### `ChannelParams`
192
+
193
+ | Value | Description |
194
+ |---|---|
195
+ | `SNR_DB` | Signal-to-noise ratio in dB. |
196
+ | `NOISE_CORRELATION` | I/Q noise correlation coefficient (-1.0 to 1.0). |
197
+ | `FREQUENCY_OFFSET` | Carrier frequency offset in Hz. |
198
+ | `PHASE_OFFSET` | Phase offset in radians. |
199
+ | `DC_OFFSET_I` | DC offset on the in-phase component. |
200
+ | `DC_OFFSET_Q` | DC offset on the quadrature component. |
201
+ | `IQ_GAIN_IMBALANCE` | Gain imbalance between I and Q channels. |
202
+ | `IQ_PHASE_IMBALANCE` | Phase imbalance between I and Q channels (degrees). |
203
+
204
+ ---
205
+
206
+ ### `ADSBAlgorithms`
207
+
208
+ Static utility class providing ADS-B encoding algorithms.
209
+
210
+ | Method | Returns | Description |
211
+ |---|---|---|
212
+ | `calculate_crc(data: int)` | `int` | Computes 24-bit CRC parity using polynomial `0xFFF409`. |
213
+ | `encode_cpr(lat, lon, odd)` | `tuple[int, int]` | Encodes lat/lon into CPR 17-bit values. |
214
+ | `encode_altitude(alt: int)` | `int` | Encodes altitude in feet into 12-bit Gillham-coded format. |
215
+ | `encode_ground_track(degrees, valid)` | `tuple[int, int]` | Encodes ground track heading into the 7-bit format. |
216
+
217
+ ## Distribution Format
218
+
219
+ All configurable distributions use the format `[[min_val, max_val, weight], ...]` where weights for a given parameter must sum to `1.0` (+/- 0.01 tolerance). Keys can be enum members or their string values (e.g., `ChannelParams.SNR_DB` or `"snr_db"`).
220
+
221
+ ## License
222
+
223
+ [MIT](LICENSE) - Copyright (c) 2026 Adam Hamri (adamhamri9)
@@ -0,0 +1,194 @@
1
+ # adsb-generator
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
4
+ [![Python 3.10+](https://img.shields.io/badge/Python-3.10+-3776AB.svg)](https://www.python.org/downloads/)
5
+
6
+ **Synthetic ADS-B data generator.**
7
+
8
+ `adsb-generator` produces realistic I/Q (In-phase/Quadrature) samples of clean and impaired ADS-B (Mode S Downlink Format 17) baseband signals, along with the raw 112-bit message and all applied parameters. It implements an infinite iterator that streams reproducible samples with full control over message type distributions, transmission parameters, and channel impairments.
9
+
10
+ ## Key Features
11
+
12
+ - **End-to-end pipeline**: random message generation, PPM encoding, and RF channel simulation in a single call.
13
+ - **Four ADS-B message types**: identification, surface position, airborne position, and airborne velocity with configurable emission probabilities.
14
+ - **Realistic channel impairments**: Gaussian Noise(both AWGN and Correlated) , frequency & phase offset, IQ imbalance, and DC offset, all sampled from configurable probability distributions.
15
+ - **Reproducibility**: deterministic output via a shared seed across all pipeline stages.
16
+ - **Configurable distributions**: override any transmission or channel parameter distribution to model specific receiver conditions or hardware behavior.
17
+ - **NumPy-native**: all signals are `np.complex64` arrays, ready for direct use with any downstream processing tool.
18
+
19
+ ## Requirements
20
+
21
+ - Python 3.10+
22
+ - NumPy
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install adsb-generator
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ ```python
33
+ from adsb_generator import ADSBGenerator
34
+
35
+ # Create a generator with a fixed seed for reproducibility
36
+ gen = ADSBGenerator(seed=42)
37
+
38
+ # Each iteration yields an ADSBSample with the raw message,
39
+ # clean signal, and channel-impaired signal
40
+ for sample in gen:
41
+ print(f"Message type : {sample.message_type.value}")
42
+ print(f"Raw message : {sample.message:#028x}")
43
+ print(f"Clean signal : {sample.clean_signal.shape} complex64 samples")
44
+ print(f"Noisy signal : {sample.channel_signal.shape} complex64 samples")
45
+ print(f"SNR (dB) : {sample.channel_params['snr_db']:.1f}")
46
+ print(f"Amplitude : {sample.tx_params['amplitude']:.3f}")
47
+ break
48
+ ```
49
+
50
+ ### Customizing Distributions
51
+
52
+ ```python
53
+ from adsb_generator import ADSBGenerator, MessageType, ChannelParams
54
+
55
+ # Favor airborne positions, restrict SNR to low-moderate range
56
+ gen = ADSBGenerator(
57
+ message_type_probs={
58
+ MessageType.AIRBORNE_POSITION: 0.60,
59
+ MessageType.AIRBORNE_VELOCITY: 0.20,
60
+ MessageType.IDENTIFICATION: 0.10,
61
+ MessageType.SURFACE_POSITION: 0.10,
62
+ },
63
+ channel_params_distributions={
64
+ ChannelParams.SNR_DB: [
65
+ [3.0, 8.0, 0.70],
66
+ [8.0, 15.0, 0.30],
67
+ ],
68
+ },
69
+ sample_rate=2e6,
70
+ seed=12345,
71
+ )
72
+
73
+ sample = next(gen)
74
+ ```
75
+
76
+ ## API Reference
77
+
78
+ ### `ADSBGenerator`
79
+
80
+ ```python
81
+ ADSBGenerator(
82
+ message_type_probs: dict[MessageType | str, float] | None = None,
83
+ tx_params_distributions: dict[TXParams | str, list[list[float]]] | None = None,
84
+ channel_params_distributions: dict[ChannelParams | str, list[list[float]]] | None = None,
85
+ sample_rate: float = 2e6,
86
+ seed: int | None = None,
87
+ )
88
+ ```
89
+
90
+ | Parameter | Type | Default | Description |
91
+ |---|---|---|---|
92
+ | `message_type_probs` | `dict` or `None` | Equal 25% per type | Mapping of `MessageType` to emission probabilities (must sum to 1.0). |
93
+ | `tx_params_distributions` | `dict` or `None` | Single amplitude band | Mapping of `TXParams` to `[[min, max, weight], ...]` intervals. |
94
+ | `channel_params_distributions` | `dict` or `None` | Typical ADS-B conditions | Mapping of `ChannelParams` to `[[min, max, weight], ...]` intervals. |
95
+ | `sample_rate` | `float` | `2e6` | Sampling rate in samples per second. |
96
+ | `seed` | `int` or `None` | Random | Seed for deterministic output across all pipeline stages. |
97
+
98
+ ---
99
+
100
+ ### `ADSBSample`
101
+
102
+ Dataclass returned by each iteration of `ADSBGenerator`.
103
+
104
+ | Field | Type | Description |
105
+ |---|---|---|
106
+ | `message` | `int` | Complete 112-bit ADS-B message (including 24-bit CRC) as an integer. |
107
+ | `message_type` | `MessageType` | The type of ADS-B message generated. |
108
+ | `clean_signal` | `np.ndarray` | Complex baseband I/Q signal before channel impairments (`complex64`). |
109
+ | `tx_params` | `dict[TXParams, float]` | Transmission parameters applied during encoding. |
110
+ | `channel_signal` | `np.ndarray` | Complex baseband I/Q signal after channel impairments (`complex64`). |
111
+ | `channel_params` | `dict[ChannelParams, float]` | Channel parameters applied to the signal. |
112
+
113
+ ---
114
+
115
+ ### `MessageType`
116
+
117
+ | Value | Description |
118
+ |---|---|
119
+ | `IDENTIFICATION` | Aircraft identification (callsign) messages (TC 1--4). |
120
+ | `SURFACE_POSITION` | Surface position messages (TC 5--8). |
121
+ | `AIRBORNE_POSITION` | Airborne position messages (TC 9--18, 20--22). |
122
+ | `AIRBORNE_VELOCITY` | Airborne velocity messages (TC 19). |
123
+
124
+ ---
125
+
126
+ ### `ADSBEncoder`
127
+
128
+ Encodes 112-bit messages into complex baseband I/Q samples using PPM per the Mode S standard.
129
+
130
+ ```python
131
+ ADSBEncoder(
132
+ sample_rate: float = 2e6,
133
+ tx_params_distributions: dict[TXParams | str, list[list[float]]] | None = None,
134
+ seed: int | None = None,
135
+ )
136
+ ```
137
+
138
+ | Method | Returns | Description |
139
+ |---|---|---|
140
+ | `encode(msg: int)` | `tuple[np.ndarray, dict[TXParams, float]]` | Encodes a 112-bit message into a 120-us baseband I/Q signal. |
141
+
142
+ ---
143
+
144
+ ### `ADSBChannel`
145
+
146
+ Simulates realistic RF channel impairments on baseband I/Q signals.
147
+
148
+ ```python
149
+ ADSBChannel(
150
+ sample_rate: float = 2e6,
151
+ channel_params_distributions: dict[ChannelParams | str, list[list[float]]] | None = None,
152
+ seed: int | None = None,
153
+ )
154
+ ```
155
+
156
+ | Method | Returns | Description |
157
+ |---|---|---|
158
+ | `apply(signal: np.ndarray)` | `tuple[np.ndarray, dict[ChannelParams, float]]` | Applies impairments: IQ imbalance, DC offset, frequency offset, phase offset, AWGN. |
159
+
160
+ ---
161
+
162
+ ### `ChannelParams`
163
+
164
+ | Value | Description |
165
+ |---|---|
166
+ | `SNR_DB` | Signal-to-noise ratio in dB. |
167
+ | `NOISE_CORRELATION` | I/Q noise correlation coefficient (-1.0 to 1.0). |
168
+ | `FREQUENCY_OFFSET` | Carrier frequency offset in Hz. |
169
+ | `PHASE_OFFSET` | Phase offset in radians. |
170
+ | `DC_OFFSET_I` | DC offset on the in-phase component. |
171
+ | `DC_OFFSET_Q` | DC offset on the quadrature component. |
172
+ | `IQ_GAIN_IMBALANCE` | Gain imbalance between I and Q channels. |
173
+ | `IQ_PHASE_IMBALANCE` | Phase imbalance between I and Q channels (degrees). |
174
+
175
+ ---
176
+
177
+ ### `ADSBAlgorithms`
178
+
179
+ Static utility class providing ADS-B encoding algorithms.
180
+
181
+ | Method | Returns | Description |
182
+ |---|---|---|
183
+ | `calculate_crc(data: int)` | `int` | Computes 24-bit CRC parity using polynomial `0xFFF409`. |
184
+ | `encode_cpr(lat, lon, odd)` | `tuple[int, int]` | Encodes lat/lon into CPR 17-bit values. |
185
+ | `encode_altitude(alt: int)` | `int` | Encodes altitude in feet into 12-bit Gillham-coded format. |
186
+ | `encode_ground_track(degrees, valid)` | `tuple[int, int]` | Encodes ground track heading into the 7-bit format. |
187
+
188
+ ## Distribution Format
189
+
190
+ All configurable distributions use the format `[[min_val, max_val, weight], ...]` where weights for a given parameter must sum to `1.0` (+/- 0.01 tolerance). Keys can be enum members or their string values (e.g., `ChannelParams.SNR_DB` or `"snr_db"`).
191
+
192
+ ## License
193
+
194
+ [MIT](LICENSE) - Copyright (c) 2026 Adam Hamri (adamhamri9)
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "adsb-generator"
7
+ version = "0.1.0"
8
+ description = "`adsb-generator` produces realistic I/Q (In-phase/Quadrature) samples of clean and impaired ADS-B (Mode S Downlink Format 17) baseband signals, along with the raw 112-bit message and all applied parameters. It implements an infinite iterator that streams reproducible samples with full control over message type distributions, transmission parameters, and channel impairments."
9
+ readme = { file = "README.md", content-type = "text/markdown" }
10
+ license = "MIT"
11
+ requires-python = ">=3.10,<3.14"
12
+ authors = [
13
+ { name = "Adam Hamri", email = "adamhamri9@proton.me" },
14
+ ]
15
+ keywords = ["adsb", "mode-s", "aviation", "signal-generation", "iq-samples", "baseband"]
16
+ classifiers = [
17
+ "Development Status :: 3 - Alpha",
18
+ "Intended Audience :: Developers",
19
+ "Intended Audience :: Science/Research",
20
+ "Operating System :: OS Independent",
21
+ "Programming Language :: Python :: 3",
22
+ "Programming Language :: Python :: 3.10",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Scientific/Engineering",
27
+ "Topic :: Communications :: Ham Radio",
28
+ ]
29
+ dependencies = [
30
+ "numpy>=1.26.0",
31
+ ]
32
+
33
+ [project.optional-dependencies]
34
+ dev = [
35
+ "pytest>=8.0.0",
36
+ ]
37
+
38
+ [project.urls]
39
+ Homepage = "https://github.com/adamhamri9/adsb-datagen"
40
+ Repository = "https://github.com/adamhamri9/adsb-datagen"
41
+ Issues = "https://github.com/adamhamri9/adsb-datagen/issues"
42
+
43
+ [tool.setuptools.packages.find]
44
+ where = ["src"]
45
+
46
+ [tool.pytest.ini_options]
47
+ testpaths = ["tests"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,9 @@
1
+ __version__ = "0.1.0"
2
+
3
+ from .generator import ADSBSample, ADSBGenerator
4
+ from .channel import ChannelParams, ADSBChannel
5
+ from .encoder import TXParams, ADSBEncoder
6
+ from .message import MessageType, ADSBMessage
7
+
8
+ __all__ = ["ADSBSample", "ADSBGenerator", "ChannelParams", "ADSBChannel",
9
+ "TXParams", "ADSBEncoder", "MessageType", "ADSBMessage"]
@@ -0,0 +1,84 @@
1
+ import math
2
+
3
+ class ADSBAlgorithms():
4
+
5
+ CRC_POLY = 0xFFF409
6
+
7
+ @classmethod
8
+ def calculate_crc(cls, data: int) -> int:
9
+
10
+ packet = data << 24
11
+ remainder = packet
12
+
13
+ for bit in range(111, 23, -1):
14
+ if (remainder >> bit) & 1:
15
+ remainder ^= cls.CRC_POLY << (bit - 24)
16
+
17
+ crc = remainder & 0xFFFFFF
18
+
19
+ return packet | crc
20
+
21
+ _NL_TABLE = [
22
+ (87, 59), (83, 58), (79, 57), (76, 56), (73, 55),
23
+ (70, 54), (66, 53), (63, 52), (60, 51), (57, 50),
24
+ (53, 49), (50, 48), (46, 47), (43, 46), (40, 45),
25
+ (37, 44), (34, 43), (31, 42), (28, 41), (25, 40),
26
+ (22, 39), (19, 38), (16, 37), (13, 36), (9, 35),
27
+ (6, 34), (3, 33), (0, 32),
28
+ ]
29
+
30
+ @classmethod
31
+ def _nl(cls, lat: float) -> int:
32
+ if abs(lat) >= 87:
33
+ return 1
34
+ for lat_min, nl in cls._NL_TABLE:
35
+ if abs(lat) >= lat_min:
36
+ return nl
37
+ return 32
38
+
39
+ @classmethod
40
+ def encode_cpr(cls, lat: float, lon: float, odd: bool) -> tuple[int, int]:
41
+ lat = max(-90.0, min(90.0, lat))
42
+ lon = max(-180.0, min(180.0, lon))
43
+
44
+ NB = 17
45
+ factor = 1 << NB
46
+
47
+ nz_lat = 59 if odd else 60
48
+ dlat = 360.0 / nz_lat
49
+
50
+ zone_lat = math.floor(lat / dlat)
51
+ rem_lat = lat - zone_lat * dlat
52
+ yz = int(round((rem_lat / dlat) * factor)) & (factor - 1)
53
+
54
+ rlat = dlat * (yz / factor + zone_lat)
55
+ rlat = max(-90.0, min(90.0, rlat))
56
+
57
+ nl = cls._nl(rlat)
58
+
59
+ dlon = 360.0 / nl
60
+ zone_lon = math.floor(lon / dlon)
61
+ rem_lon = lon - zone_lon * dlon
62
+ xz = int(round((rem_lon / dlon) * factor)) & (factor - 1)
63
+
64
+ return yz, xz
65
+
66
+ @staticmethod
67
+ def encode_altitude(alt: int) -> int:
68
+ alt_clamped = max(-1000, min(50100, alt))
69
+ n = (alt_clamped + 1000) // 25
70
+
71
+ top_bits = (n >> 4) & 0x7F
72
+ bottom_bits = n & 0x0F
73
+
74
+ return (top_bits << 5) | (1 << 4) | bottom_bits
75
+
76
+ @staticmethod
77
+ def encode_ground_track(degrees: float, valid: bool = True) -> tuple[int, int]:
78
+ if not valid or degrees is None:
79
+ return 0, 0
80
+
81
+ degrees = degrees % 360.0
82
+ trk_code = round(degrees * 128.0 / 360.0)
83
+
84
+ return 1, trk_code