dtmb-sdr 0.2.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.
- dtmb_sdr-0.2.0/.gitignore +28 -0
- dtmb_sdr-0.2.0/.pytest_cache/README.md +8 -0
- dtmb_sdr-0.2.0/LICENSE +21 -0
- dtmb_sdr-0.2.0/Makefile +18 -0
- dtmb_sdr-0.2.0/PKG-INFO +223 -0
- dtmb_sdr-0.2.0/README.md +179 -0
- dtmb_sdr-0.2.0/THIRD_PARTY.md +17 -0
- dtmb_sdr-0.2.0/core/cpp/CMakeLists.txt +95 -0
- dtmb_sdr-0.2.0/core/cpp/include/dtmb/core.hpp +400 -0
- dtmb_sdr-0.2.0/core/cpp/include/dtmb/core_c.h +72 -0
- dtmb_sdr-0.2.0/core/cpp/src/c3780.cpp +601 -0
- dtmb_sdr-0.2.0/core/cpp/src/core.cpp +556 -0
- dtmb_sdr-0.2.0/core/cpp/src/fec.cpp +511 -0
- dtmb_sdr-0.2.0/core/cpp/src/frame_sync.cpp +227 -0
- dtmb_sdr-0.2.0/core/cpp/src/pn_channel.cpp +1499 -0
- dtmb_sdr-0.2.0/core/cpp/src/resampler.cpp +341 -0
- dtmb_sdr-0.2.0/core/cpp/tests/test_ldpc_h_gate.cpp +318 -0
- dtmb_sdr-0.2.0/core/cpp/tools/binary_stdio.hpp +27 -0
- dtmb_sdr-0.2.0/core/cpp/tools/c3780_extract.cpp +4816 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ci8_resample.cpp +262 -0
- dtmb_sdr-0.2.0/core/cpp/tools/deinterleave_qam64.cpp +6859 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_bch_decode.cpp +6052 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_cuda_backend.cpp +23 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_cuda_backend.cu +681 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_cuda_backend.hpp +37 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_h_gate.cpp +609 -0
- dtmb_sdr-0.2.0/core/cpp/tools/ldpc_h_gate.hpp +82 -0
- dtmb_sdr-0.2.0/pyproject.toml +53 -0
- dtmb_sdr-0.2.0/python/dtmb/__init__.py +5 -0
- dtmb_sdr-0.2.0/python/dtmb/__pycache__/__init__.cpython-312.pyc +0 -0
- dtmb_sdr-0.2.0/python/dtmb/__pycache__/decode.cpython-312.pyc +0 -0
- dtmb_sdr-0.2.0/python/dtmb/__pycache__/ts.cpython-312.pyc +0 -0
- dtmb_sdr-0.2.0/python/dtmb/data/dtmb_ldpc_rate1.alist +11942 -0
- dtmb_sdr-0.2.0/python/dtmb/data/dtmb_ldpc_rate2.alist +10418 -0
- dtmb_sdr-0.2.0/python/dtmb/data/dtmb_ldpc_rate3.alist +8894 -0
- dtmb_sdr-0.2.0/python/dtmb/decode.py +205 -0
- dtmb_sdr-0.2.0/python/dtmb/ts.py +713 -0
- dtmb_sdr-0.2.0/requirements.txt +1 -0
- dtmb_sdr-0.2.0/tests/__pycache__/test_decode.cpython-312-pytest-9.0.3.pyc +0 -0
- dtmb_sdr-0.2.0/tests/test_decode.py +65 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.pyd
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.mypy_cache/
|
|
6
|
+
.ruff_cache/
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
.mamba-env/
|
|
10
|
+
.conda-pkgs/
|
|
11
|
+
|
|
12
|
+
build/
|
|
13
|
+
out/
|
|
14
|
+
dist/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
|
|
17
|
+
*.iq
|
|
18
|
+
*.cfile
|
|
19
|
+
*.cf32
|
|
20
|
+
*.ci8
|
|
21
|
+
*.ts
|
|
22
|
+
|
|
23
|
+
captures/*
|
|
24
|
+
!captures/README.md
|
|
25
|
+
test_vectors/*
|
|
26
|
+
!test_vectors/README.md
|
|
27
|
+
scan_results/
|
|
28
|
+
.DS_Store
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# pytest cache directory #
|
|
2
|
+
|
|
3
|
+
This directory contains data from the pytest's cache plugin,
|
|
4
|
+
which provides the `--lf` and `--ff` options, as well as the `cache` fixture.
|
|
5
|
+
|
|
6
|
+
**Do not** commit this to version control.
|
|
7
|
+
|
|
8
|
+
See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information.
|
dtmb_sdr-0.2.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ning
|
|
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.
|
dtmb_sdr-0.2.0/Makefile
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
PYTHON ?= python
|
|
2
|
+
CMAKE ?= cmake
|
|
3
|
+
BUILD_DIR ?= build/core-cpp
|
|
4
|
+
|
|
5
|
+
.PHONY: configure build test install
|
|
6
|
+
|
|
7
|
+
configure:
|
|
8
|
+
$(CMAKE) -S core/cpp -B $(BUILD_DIR) -DDTMB_CORE_BUILD_TESTS=ON
|
|
9
|
+
|
|
10
|
+
build: configure
|
|
11
|
+
$(CMAKE) --build $(BUILD_DIR) --config Release
|
|
12
|
+
|
|
13
|
+
test: build
|
|
14
|
+
ctest --test-dir $(BUILD_DIR) -C Release --output-on-failure
|
|
15
|
+
$(PYTHON) -m pytest tests
|
|
16
|
+
|
|
17
|
+
install:
|
|
18
|
+
$(PYTHON) -m pip install -e .
|
dtmb_sdr-0.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
|
+
Name: dtmb-sdr
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Vendor-neutral CI8 stream to MPEG-TS DTMB receiver
|
|
5
|
+
Author: dtmb-sdr contributors
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Ning
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Classifier: Development Status :: 3 - Alpha
|
|
29
|
+
Classifier: Environment :: Console
|
|
30
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
31
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
32
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
33
|
+
Classifier: Programming Language :: C++
|
|
34
|
+
Classifier: Programming Language :: Python :: 3
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
38
|
+
Classifier: Topic :: Multimedia :: Video
|
|
39
|
+
Requires-Python: >=3.10
|
|
40
|
+
Provides-Extra: dev
|
|
41
|
+
Requires-Dist: build>=1; extra == "dev"
|
|
42
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# dtmb-sdr
|
|
46
|
+
|
|
47
|
+
A minimal, vendor-neutral DTMB receiver. It accepts interleaved signed 8-bit
|
|
48
|
+
complex samples (CI8) from a file or standard input and emits MPEG transport
|
|
49
|
+
stream packets to a file or standard output.
|
|
50
|
+
|
|
51
|
+
```text
|
|
52
|
+
CI8 file/stdin
|
|
53
|
+
-> sample-rate conversion
|
|
54
|
+
-> PN945 synchronization and C=3780 equalization
|
|
55
|
+
-> QAM64 deinterleaving and soft demapping
|
|
56
|
+
-> LDPC, BCH, and descrambling
|
|
57
|
+
-> MPEG-TS file/stdout
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Hardware acquisition is intentionally outside this repository. Any application
|
|
61
|
+
that can produce CI8 bytes at a known sample rate can feed the receiver.
|
|
62
|
+
|
|
63
|
+
## Build
|
|
64
|
+
|
|
65
|
+
Requirements are CMake 3.20+, a C++20 compiler, and Python 3.10+.
|
|
66
|
+
|
|
67
|
+
For a released platform wheel, installation is simply:
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
pip install dtmb-sdr
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
The wheel contains the native receiver executables and required LDPC data; no
|
|
74
|
+
separate source checkout or CMake build is required.
|
|
75
|
+
|
|
76
|
+
To build from a source checkout:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
python -m pip install -e ".[dev]"
|
|
80
|
+
cmake -S core/cpp -B build/core-cpp -DDTMB_CORE_BUILD_TESTS=ON
|
|
81
|
+
cmake --build build/core-cpp --config Release
|
|
82
|
+
ctest --test-dir build/core-cpp -C Release --output-on-failure
|
|
83
|
+
pytest
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Build a distributable wheel with:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
python -m build --wheel
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Standard PyPI wheels use the portable CPU decoder. CUDA is intentionally an
|
|
93
|
+
explicit source-build option because CUDA toolkit and GPU architecture support
|
|
94
|
+
are platform-specific.
|
|
95
|
+
|
|
96
|
+
## Decode a CI8 file
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
dtmb-decode \
|
|
100
|
+
--input capture.ci8 \
|
|
101
|
+
--input-rate 16000000 \
|
|
102
|
+
--output recovered.ts \
|
|
103
|
+
--acceleration cpu \
|
|
104
|
+
--error-policy continue
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The default profile is QAM64, FEC rate 0.6, interleaver mode 2
|
|
108
|
+
(`--system-info-index 22`). Profiles 19 through 24 select the supported QAM64
|
|
109
|
+
FEC/interleaver combinations.
|
|
110
|
+
|
|
111
|
+
Strict mode is the default. `--error-policy continue` omits unclean frames and
|
|
112
|
+
adds MPEG-TS discontinuity indications before later clean output.
|
|
113
|
+
|
|
114
|
+
## Optional CUDA LDPC acceleration
|
|
115
|
+
|
|
116
|
+
CPU decoding is the portable baseline. Build the optional CUDA LDPC backend
|
|
117
|
+
when a supported NVIDIA toolchain is available:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
cmake -S core/cpp -B build/core-cpp-cuda \
|
|
121
|
+
-DDTMB_CORE_ENABLE_CUDA_LDPC=ON \
|
|
122
|
+
-DDTMB_CORE_BUILD_TESTS=ON
|
|
123
|
+
cmake --build build/core-cpp-cuda --config Release
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Then select it explicitly:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
dtmb-decode \
|
|
130
|
+
--bin-dir build/core-cpp-cuda \
|
|
131
|
+
--input capture.ci8 \
|
|
132
|
+
--input-rate 16000000 \
|
|
133
|
+
--output recovered.ts \
|
|
134
|
+
--acceleration cuda
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The CUDA backend batches LDPC codewords and reports host-to-device, kernel,
|
|
138
|
+
device-to-host, and total timing metrics. CPU remains available as the
|
|
139
|
+
correctness and portability reference.
|
|
140
|
+
|
|
141
|
+
### Parallelism and observed acceleration
|
|
142
|
+
|
|
143
|
+
The receiver uses independent concurrency at several stages:
|
|
144
|
+
|
|
145
|
+
- multithreaded rational resampling and PN acquisition;
|
|
146
|
+
- worker-parallel C=3780 frame equalization;
|
|
147
|
+
- chunked QAM64 deinterleaving and soft demapping;
|
|
148
|
+
- batched LDPC decoding on either CPU workers or CUDA kernels.
|
|
149
|
+
|
|
150
|
+
One observed live-pipeline comparison used 12 CPU workers and 256-frame FEC
|
|
151
|
+
batches. The CPU path processed 198,660 codewords in 30.95 seconds of measured
|
|
152
|
+
FEC batch time (about 6,419 codewords/s). The CUDA path processed 267,486
|
|
153
|
+
codewords in 17.22 seconds of measured FEC batch time (about 15,534
|
|
154
|
+
codewords/s), while 10.41 seconds were attributed to CUDA transfer plus kernel
|
|
155
|
+
execution. After normalizing by processed codewords, the observed FEC-stage
|
|
156
|
+
throughput improvement was approximately 2.4x.
|
|
157
|
+
|
|
158
|
+
These runs did not use an identical retained LLR stream, so the figure is an
|
|
159
|
+
operational observation rather than a controlled cross-machine benchmark.
|
|
160
|
+
Performance depends on the proportion of early-rejected codewords, iteration
|
|
161
|
+
count, batch size, CPU, GPU, and memory-transfer overhead. Reproducible release
|
|
162
|
+
claims should use the same retained LLR input and compare byte-identical output.
|
|
163
|
+
|
|
164
|
+
## Decode a pipe
|
|
165
|
+
|
|
166
|
+
Use `-` for stdin or stdout:
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
ci8-producing-command |
|
|
170
|
+
dtmb-decode --input - --input-rate 16000000 --output recovered.ts
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The source command is deliberately unspecified: the receiver depends only on
|
|
174
|
+
the byte-stream contract, not an SDR vendor or device API.
|
|
175
|
+
|
|
176
|
+
## Play while decoding
|
|
177
|
+
|
|
178
|
+
With ffplay:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
ci8-producing-command |
|
|
182
|
+
dtmb-decode --input - --input-rate 16000000 --output - --error-policy continue |
|
|
183
|
+
ffplay -fflags nobuffer -flags low_delay -f mpegts -
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
With VLC:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
ci8-producing-command |
|
|
190
|
+
dtmb-decode --input - --input-rate 16000000 --output - --error-policy continue |
|
|
191
|
+
vlc - --demux=ts
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Playback quality depends on RF quality and FEC cleanliness. A player detecting
|
|
195
|
+
a service is not evidence that the complete stream is error-free.
|
|
196
|
+
|
|
197
|
+
## Inspect MPEG-TS output
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
dtmb-ts-analyze recovered.ts
|
|
201
|
+
ffprobe -v error -show_programs -show_streams recovered.ts
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## Scope
|
|
205
|
+
|
|
206
|
+
Included:
|
|
207
|
+
|
|
208
|
+
- portable C++20 receive stages;
|
|
209
|
+
- CI8 file and stdin integration;
|
|
210
|
+
- MPEG-TS file and stdout output;
|
|
211
|
+
- required LDPC matrices;
|
|
212
|
+
- core and pipeline-construction tests.
|
|
213
|
+
|
|
214
|
+
Not included:
|
|
215
|
+
|
|
216
|
+
- SDR drivers or hardware-control code;
|
|
217
|
+
- capture recipes, device identifiers, frequencies, gains, or locations;
|
|
218
|
+
- signal-generation, scanning, UI, visualization, sweep, or research tooling;
|
|
219
|
+
- real broadcast captures or derived analysis artifacts.
|
|
220
|
+
|
|
221
|
+
## License
|
|
222
|
+
|
|
223
|
+
MIT. See [LICENSE](LICENSE) and [THIRD_PARTY.md](THIRD_PARTY.md).
|
dtmb_sdr-0.2.0/README.md
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
# dtmb-sdr
|
|
2
|
+
|
|
3
|
+
A minimal, vendor-neutral DTMB receiver. It accepts interleaved signed 8-bit
|
|
4
|
+
complex samples (CI8) from a file or standard input and emits MPEG transport
|
|
5
|
+
stream packets to a file or standard output.
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
CI8 file/stdin
|
|
9
|
+
-> sample-rate conversion
|
|
10
|
+
-> PN945 synchronization and C=3780 equalization
|
|
11
|
+
-> QAM64 deinterleaving and soft demapping
|
|
12
|
+
-> LDPC, BCH, and descrambling
|
|
13
|
+
-> MPEG-TS file/stdout
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Hardware acquisition is intentionally outside this repository. Any application
|
|
17
|
+
that can produce CI8 bytes at a known sample rate can feed the receiver.
|
|
18
|
+
|
|
19
|
+
## Build
|
|
20
|
+
|
|
21
|
+
Requirements are CMake 3.20+, a C++20 compiler, and Python 3.10+.
|
|
22
|
+
|
|
23
|
+
For a released platform wheel, installation is simply:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pip install dtmb-sdr
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The wheel contains the native receiver executables and required LDPC data; no
|
|
30
|
+
separate source checkout or CMake build is required.
|
|
31
|
+
|
|
32
|
+
To build from a source checkout:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
python -m pip install -e ".[dev]"
|
|
36
|
+
cmake -S core/cpp -B build/core-cpp -DDTMB_CORE_BUILD_TESTS=ON
|
|
37
|
+
cmake --build build/core-cpp --config Release
|
|
38
|
+
ctest --test-dir build/core-cpp -C Release --output-on-failure
|
|
39
|
+
pytest
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Build a distributable wheel with:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
python -m build --wheel
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Standard PyPI wheels use the portable CPU decoder. CUDA is intentionally an
|
|
49
|
+
explicit source-build option because CUDA toolkit and GPU architecture support
|
|
50
|
+
are platform-specific.
|
|
51
|
+
|
|
52
|
+
## Decode a CI8 file
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
dtmb-decode \
|
|
56
|
+
--input capture.ci8 \
|
|
57
|
+
--input-rate 16000000 \
|
|
58
|
+
--output recovered.ts \
|
|
59
|
+
--acceleration cpu \
|
|
60
|
+
--error-policy continue
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
The default profile is QAM64, FEC rate 0.6, interleaver mode 2
|
|
64
|
+
(`--system-info-index 22`). Profiles 19 through 24 select the supported QAM64
|
|
65
|
+
FEC/interleaver combinations.
|
|
66
|
+
|
|
67
|
+
Strict mode is the default. `--error-policy continue` omits unclean frames and
|
|
68
|
+
adds MPEG-TS discontinuity indications before later clean output.
|
|
69
|
+
|
|
70
|
+
## Optional CUDA LDPC acceleration
|
|
71
|
+
|
|
72
|
+
CPU decoding is the portable baseline. Build the optional CUDA LDPC backend
|
|
73
|
+
when a supported NVIDIA toolchain is available:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
cmake -S core/cpp -B build/core-cpp-cuda \
|
|
77
|
+
-DDTMB_CORE_ENABLE_CUDA_LDPC=ON \
|
|
78
|
+
-DDTMB_CORE_BUILD_TESTS=ON
|
|
79
|
+
cmake --build build/core-cpp-cuda --config Release
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Then select it explicitly:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
dtmb-decode \
|
|
86
|
+
--bin-dir build/core-cpp-cuda \
|
|
87
|
+
--input capture.ci8 \
|
|
88
|
+
--input-rate 16000000 \
|
|
89
|
+
--output recovered.ts \
|
|
90
|
+
--acceleration cuda
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The CUDA backend batches LDPC codewords and reports host-to-device, kernel,
|
|
94
|
+
device-to-host, and total timing metrics. CPU remains available as the
|
|
95
|
+
correctness and portability reference.
|
|
96
|
+
|
|
97
|
+
### Parallelism and observed acceleration
|
|
98
|
+
|
|
99
|
+
The receiver uses independent concurrency at several stages:
|
|
100
|
+
|
|
101
|
+
- multithreaded rational resampling and PN acquisition;
|
|
102
|
+
- worker-parallel C=3780 frame equalization;
|
|
103
|
+
- chunked QAM64 deinterleaving and soft demapping;
|
|
104
|
+
- batched LDPC decoding on either CPU workers or CUDA kernels.
|
|
105
|
+
|
|
106
|
+
One observed live-pipeline comparison used 12 CPU workers and 256-frame FEC
|
|
107
|
+
batches. The CPU path processed 198,660 codewords in 30.95 seconds of measured
|
|
108
|
+
FEC batch time (about 6,419 codewords/s). The CUDA path processed 267,486
|
|
109
|
+
codewords in 17.22 seconds of measured FEC batch time (about 15,534
|
|
110
|
+
codewords/s), while 10.41 seconds were attributed to CUDA transfer plus kernel
|
|
111
|
+
execution. After normalizing by processed codewords, the observed FEC-stage
|
|
112
|
+
throughput improvement was approximately 2.4x.
|
|
113
|
+
|
|
114
|
+
These runs did not use an identical retained LLR stream, so the figure is an
|
|
115
|
+
operational observation rather than a controlled cross-machine benchmark.
|
|
116
|
+
Performance depends on the proportion of early-rejected codewords, iteration
|
|
117
|
+
count, batch size, CPU, GPU, and memory-transfer overhead. Reproducible release
|
|
118
|
+
claims should use the same retained LLR input and compare byte-identical output.
|
|
119
|
+
|
|
120
|
+
## Decode a pipe
|
|
121
|
+
|
|
122
|
+
Use `-` for stdin or stdout:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
ci8-producing-command |
|
|
126
|
+
dtmb-decode --input - --input-rate 16000000 --output recovered.ts
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The source command is deliberately unspecified: the receiver depends only on
|
|
130
|
+
the byte-stream contract, not an SDR vendor or device API.
|
|
131
|
+
|
|
132
|
+
## Play while decoding
|
|
133
|
+
|
|
134
|
+
With ffplay:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
ci8-producing-command |
|
|
138
|
+
dtmb-decode --input - --input-rate 16000000 --output - --error-policy continue |
|
|
139
|
+
ffplay -fflags nobuffer -flags low_delay -f mpegts -
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
With VLC:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
ci8-producing-command |
|
|
146
|
+
dtmb-decode --input - --input-rate 16000000 --output - --error-policy continue |
|
|
147
|
+
vlc - --demux=ts
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Playback quality depends on RF quality and FEC cleanliness. A player detecting
|
|
151
|
+
a service is not evidence that the complete stream is error-free.
|
|
152
|
+
|
|
153
|
+
## Inspect MPEG-TS output
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
dtmb-ts-analyze recovered.ts
|
|
157
|
+
ffprobe -v error -show_programs -show_streams recovered.ts
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Scope
|
|
161
|
+
|
|
162
|
+
Included:
|
|
163
|
+
|
|
164
|
+
- portable C++20 receive stages;
|
|
165
|
+
- CI8 file and stdin integration;
|
|
166
|
+
- MPEG-TS file and stdout output;
|
|
167
|
+
- required LDPC matrices;
|
|
168
|
+
- core and pipeline-construction tests.
|
|
169
|
+
|
|
170
|
+
Not included:
|
|
171
|
+
|
|
172
|
+
- SDR drivers or hardware-control code;
|
|
173
|
+
- capture recipes, device identifiers, frequencies, gains, or locations;
|
|
174
|
+
- signal-generation, scanning, UI, visualization, sweep, or research tooling;
|
|
175
|
+
- real broadcast captures or derived analysis artifacts.
|
|
176
|
+
|
|
177
|
+
## License
|
|
178
|
+
|
|
179
|
+
MIT. See [LICENSE](LICENSE) and [THIRD_PARTY.md](THIRD_PARTY.md).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Third-Party References
|
|
2
|
+
|
|
3
|
+
## Standard
|
|
4
|
+
|
|
5
|
+
| Name | Purpose | Reuse |
|
|
6
|
+
|------|---------|-------|
|
|
7
|
+
| GB 20600-2006 | Normative DTMB standard: PN sequences, constellation mappings, LDPC/BCH parameters, system information tables | Receiver constants and LDPC interoperability matrices |
|
|
8
|
+
|
|
9
|
+
All DTMB-specific algorithms are reimplemented from the standard, not copied from other projects.
|
|
10
|
+
|
|
11
|
+
## Derived Artifacts
|
|
12
|
+
|
|
13
|
+
Files generated from GB 20600-2006 (not third-party code):
|
|
14
|
+
|
|
15
|
+
| Artifact | Format | Purpose |
|
|
16
|
+
|----------|--------|---------|
|
|
17
|
+
| `python/dtmb/data/dtmb_ldpc_rate{1,2,3}.alist` | MacKay .alist | LDPC parity-check matrices for interoperability with external decoders (AFF3CT, Radford Neal's tools, etc.) |
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
cmake_minimum_required(VERSION 3.20)
|
|
2
|
+
|
|
3
|
+
project(dtmb_core VERSION 0.2.0 LANGUAGES C CXX)
|
|
4
|
+
|
|
5
|
+
option(DTMB_CORE_BUILD_TESTS "Build dtmb-core tests" ON)
|
|
6
|
+
option(DTMB_CORE_ENABLE_CUDA_LDPC "Build the optional CUDA LDPC backend" OFF)
|
|
7
|
+
option(DTMB_CORE_ENABLE_FFTW "Use FFTW3f when available" ON)
|
|
8
|
+
|
|
9
|
+
if(DTMB_CORE_ENABLE_CUDA_LDPC)
|
|
10
|
+
enable_language(CUDA)
|
|
11
|
+
find_package(CUDAToolkit REQUIRED)
|
|
12
|
+
set(CMAKE_CUDA_STANDARD 20)
|
|
13
|
+
set(CMAKE_CUDA_STANDARD_REQUIRED ON)
|
|
14
|
+
endif()
|
|
15
|
+
|
|
16
|
+
add_library(dtmb_core
|
|
17
|
+
src/c3780.cpp
|
|
18
|
+
src/core.cpp
|
|
19
|
+
src/fec.cpp
|
|
20
|
+
src/frame_sync.cpp
|
|
21
|
+
src/pn_channel.cpp
|
|
22
|
+
src/resampler.cpp
|
|
23
|
+
)
|
|
24
|
+
add_library(dtmb::core ALIAS dtmb_core)
|
|
25
|
+
target_compile_features(dtmb_core PUBLIC cxx_std_20)
|
|
26
|
+
target_include_directories(dtmb_core PUBLIC
|
|
27
|
+
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
if(DTMB_CORE_ENABLE_FFTW)
|
|
31
|
+
find_path(FFTW3F_INCLUDE_DIR NAMES fftw3.h HINTS ENV CONDA_PREFIX
|
|
32
|
+
PATH_SUFFIXES include Library/include)
|
|
33
|
+
find_library(FFTW3F_LIBRARY NAMES fftw3f libfftw3f-3 HINTS ENV CONDA_PREFIX
|
|
34
|
+
PATH_SUFFIXES lib Library/lib)
|
|
35
|
+
if(FFTW3F_INCLUDE_DIR AND FFTW3F_LIBRARY)
|
|
36
|
+
target_include_directories(dtmb_core PRIVATE "${FFTW3F_INCLUDE_DIR}")
|
|
37
|
+
target_link_libraries(dtmb_core PUBLIC "${FFTW3F_LIBRARY}")
|
|
38
|
+
target_compile_definitions(dtmb_core PRIVATE DTMB_CORE_HAVE_FFTW3F=1)
|
|
39
|
+
endif()
|
|
40
|
+
endif()
|
|
41
|
+
|
|
42
|
+
if(MSVC)
|
|
43
|
+
target_compile_options(dtmb_core PRIVATE /W4 /permissive-)
|
|
44
|
+
else()
|
|
45
|
+
target_compile_options(dtmb_core PRIVATE -Wall -Wextra -Wpedantic)
|
|
46
|
+
endif()
|
|
47
|
+
|
|
48
|
+
add_executable(dtmb_core_ci8_resample tools/ci8_resample.cpp)
|
|
49
|
+
target_link_libraries(dtmb_core_ci8_resample PRIVATE dtmb::core)
|
|
50
|
+
|
|
51
|
+
add_executable(dtmb_core_c3780_extract tools/c3780_extract.cpp)
|
|
52
|
+
target_link_libraries(dtmb_core_c3780_extract PRIVATE dtmb::core)
|
|
53
|
+
|
|
54
|
+
add_executable(dtmb_core_deinterleave_qam64 tools/deinterleave_qam64.cpp)
|
|
55
|
+
target_link_libraries(dtmb_core_deinterleave_qam64 PRIVATE dtmb::core)
|
|
56
|
+
|
|
57
|
+
add_library(dtmb_ldpc_h_gate_support STATIC tools/ldpc_h_gate.cpp)
|
|
58
|
+
target_compile_features(dtmb_ldpc_h_gate_support PUBLIC cxx_std_20)
|
|
59
|
+
target_include_directories(dtmb_ldpc_h_gate_support PUBLIC tools)
|
|
60
|
+
target_link_libraries(dtmb_ldpc_h_gate_support PUBLIC dtmb::core)
|
|
61
|
+
|
|
62
|
+
if(DTMB_CORE_ENABLE_CUDA_LDPC)
|
|
63
|
+
add_library(dtmb_ldpc_cuda_backend STATIC tools/ldpc_cuda_backend.cu)
|
|
64
|
+
target_compile_definitions(dtmb_ldpc_cuda_backend PUBLIC DTMB_CORE_HAVE_CUDA_LDPC=1)
|
|
65
|
+
target_link_libraries(dtmb_ldpc_cuda_backend PUBLIC dtmb::core CUDA::cudart)
|
|
66
|
+
else()
|
|
67
|
+
add_library(dtmb_ldpc_cuda_backend STATIC tools/ldpc_cuda_backend.cpp)
|
|
68
|
+
target_link_libraries(dtmb_ldpc_cuda_backend PUBLIC dtmb::core)
|
|
69
|
+
endif()
|
|
70
|
+
target_compile_features(dtmb_ldpc_cuda_backend PUBLIC cxx_std_20)
|
|
71
|
+
target_include_directories(dtmb_ldpc_cuda_backend PUBLIC tools)
|
|
72
|
+
|
|
73
|
+
add_executable(dtmb_core_ldpc_bch_decode tools/ldpc_bch_decode.cpp)
|
|
74
|
+
target_link_libraries(dtmb_core_ldpc_bch_decode PRIVATE
|
|
75
|
+
dtmb_ldpc_h_gate_support
|
|
76
|
+
dtmb_ldpc_cuda_backend
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
install(TARGETS
|
|
80
|
+
dtmb_core_ci8_resample
|
|
81
|
+
dtmb_core_c3780_extract
|
|
82
|
+
dtmb_core_deinterleave_qam64
|
|
83
|
+
dtmb_core_ldpc_bch_decode
|
|
84
|
+
RUNTIME DESTINATION dtmb/bin
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if(DTMB_CORE_BUILD_TESTS)
|
|
88
|
+
enable_testing()
|
|
89
|
+
add_executable(dtmb_ldpc_h_gate_tests tests/test_ldpc_h_gate.cpp)
|
|
90
|
+
target_link_libraries(dtmb_ldpc_h_gate_tests PRIVATE dtmb_ldpc_h_gate_support)
|
|
91
|
+
target_compile_definitions(dtmb_ldpc_h_gate_tests PRIVATE
|
|
92
|
+
DTMB_LDPC_RATE2_ALIST="${CMAKE_CURRENT_SOURCE_DIR}/../../python/dtmb/data/dtmb_ldpc_rate2.alist"
|
|
93
|
+
)
|
|
94
|
+
add_test(NAME dtmb_ldpc_h_gate_tests COMMAND dtmb_ldpc_h_gate_tests)
|
|
95
|
+
endif()
|