commkit 3.1.3__tar.gz → 3.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.
Files changed (288) hide show
  1. {commkit-3.1.3 → commkit-3.2.0}/AGENTS.md +3 -1
  2. {commkit-3.1.3 → commkit-3.2.0}/CHANGELOG.md +20 -1
  3. {commkit-3.1.3 → commkit-3.2.0}/PKG-INFO +3 -3
  4. {commkit-3.1.3 → commkit-3.2.0}/README.md +2 -2
  5. {commkit-3.1.3 → commkit-3.2.0}/commkit/__init__.py +1 -1
  6. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/__init__.py +21 -1
  7. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/base.py +23 -1
  8. commkit-3.2.0/commkit/coding/exit.py +946 -0
  9. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/ldpc.py +3 -0
  10. {commkit-3.1.3 → commkit-3.2.0}/commkit/core/frame.py +14 -0
  11. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/frontend.py +8 -2
  12. {commkit-3.1.3 → commkit-3.2.0}/commkit/io.py +3 -0
  13. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/__init__.py +6 -0
  14. commkit-3.2.0/commkit/plotting/coding.py +362 -0
  15. {commkit-3.1.3 → commkit-3.2.0}/examples/00-getting-started.ipynb +18 -4
  16. {commkit-3.1.3 → commkit-3.2.0}/examples/06-awgn-and-performance-metrics.ipynb +43 -28
  17. {commkit-3.1.3 → commkit-3.2.0}/examples/07-channel-coding.ipynb +133 -6
  18. {commkit-3.1.3 → commkit-3.2.0}/examples/README.md +2 -2
  19. {commkit-3.1.3 → commkit-3.2.0}/pyproject.toml +2 -2
  20. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_coding_base.py +27 -0
  21. commkit-3.2.0/tests/coding/test_exit.py +258 -0
  22. commkit-3.2.0/tests/coding/test_ldpc_exit.py +172 -0
  23. commkit-3.2.0/tests/plotting/test_plot_coding.py +182 -0
  24. {commkit-3.1.3 → commkit-3.2.0}/tests/test_api_contracts.py +10 -0
  25. {commkit-3.1.3 → commkit-3.2.0}/uv.lock +1 -1
  26. {commkit-3.1.3 → commkit-3.2.0}/.gitattributes +0 -0
  27. {commkit-3.1.3 → commkit-3.2.0}/.github/workflows/ci.yml +0 -0
  28. {commkit-3.1.3 → commkit-3.2.0}/.github/workflows/publish.yml +0 -0
  29. {commkit-3.1.3 → commkit-3.2.0}/.gitignore +0 -0
  30. {commkit-3.1.3 → commkit-3.2.0}/.python-version +0 -0
  31. {commkit-3.1.3 → commkit-3.2.0}/LICENSE +0 -0
  32. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0002_pre_v2.json +0 -0
  33. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0003_v2_0.json +0 -0
  34. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0004_fiber_dbp.json +0 -0
  35. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0005_gpu_decoder_path.json +0 -0
  36. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0006_perf_cleanup.json +0 -0
  37. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0007_v3_0.json +0 -0
  38. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0008_v3_1.json +0 -0
  39. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_block_blind.py +0 -0
  40. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_block_lms.py +0 -0
  41. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_bps.py +0 -0
  42. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_coding.py +0 -0
  43. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_equalizers.py +0 -0
  44. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_fiber.py +0 -0
  45. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_filters.py +0 -0
  46. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_import.py +0 -0
  47. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_llr.py +0 -0
  48. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_mapping.py +0 -0
  49. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_signal_pipeline.py +0 -0
  50. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/bench_sync_misc.py +0 -0
  51. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/benchutils.py +0 -0
  52. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/conftest.py +0 -0
  53. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/record_baseline.py +0 -0
  54. {commkit-3.1.3 → commkit-3.2.0}/benchmarks/workloads.py +0 -0
  55. {commkit-3.1.3 → commkit-3.2.0}/commkit/_array.py +0 -0
  56. {commkit-3.1.3 → commkit-3.2.0}/commkit/_circular.py +0 -0
  57. {commkit-3.1.3 → commkit-3.2.0}/commkit/_constants.py +0 -0
  58. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/__init__.py +0 -0
  59. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/compiler.py +0 -0
  60. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/graphs.py +0 -0
  61. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/algebraic.cu +0 -0
  62. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/bps_anchor.cu +0 -0
  63. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/bps_min_d2.cu +0 -0
  64. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/cs_block.cu +0 -0
  65. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/iir.cu +0 -0
  66. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/ldpc.cu +0 -0
  67. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/llr.cu +0 -0
  68. {commkit-3.1.3 → commkit-3.2.0}/commkit/_cuda/src/selftest.cu +0 -0
  69. {commkit-3.1.3 → commkit-3.2.0}/commkit/_dispersion.py +0 -0
  70. {commkit-3.1.3 → commkit-3.2.0}/commkit/_fft.py +0 -0
  71. {commkit-3.1.3 → commkit-3.2.0}/commkit/_fiber.py +0 -0
  72. {commkit-3.1.3 → commkit-3.2.0}/commkit/_overlap_save.py +0 -0
  73. {commkit-3.1.3 → commkit-3.2.0}/commkit/_random.py +0 -0
  74. {commkit-3.1.3 → commkit-3.2.0}/commkit/_sequences.py +0 -0
  75. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/__init__.py +0 -0
  76. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/_common.py +0 -0
  77. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/allan.py +0 -0
  78. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/drift.py +0 -0
  79. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/fm_noise.py +0 -0
  80. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/interferometry.py +0 -0
  81. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/linewidth/__init__.py +0 -0
  82. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/linewidth/dsh.py +0 -0
  83. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/linewidth/phase.py +0 -0
  84. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/linewidth/result.py +0 -0
  85. {commkit-3.1.3 → commkit-3.2.0}/commkit/analysis/trajectory.py +0 -0
  86. {commkit-3.1.3 → commkit-3.2.0}/commkit/backend.py +0 -0
  87. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/_galois.py +0 -0
  88. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/_gf2.py +0 -0
  89. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/_ldpc_tables.py +0 -0
  90. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/_numba_loops.py +0 -0
  91. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/algebraic.py +0 -0
  92. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/convolutional.py +0 -0
  93. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/crc.py +0 -0
  94. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/interleaving.py +0 -0
  95. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/linear.py +0 -0
  96. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/polar.py +0 -0
  97. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/product.py +0 -0
  98. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/ratematch.py +0 -0
  99. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/shaping.py +0 -0
  100. {commkit-3.1.3 → commkit-3.2.0}/commkit/coding/turbo.py +0 -0
  101. {commkit-3.1.3 → commkit-3.2.0}/commkit/core/__init__.py +0 -0
  102. {commkit-3.1.3 → commkit-3.2.0}/commkit/core/_signal_adapter.py +0 -0
  103. {commkit-3.1.3 → commkit-3.2.0}/commkit/core/generation.py +0 -0
  104. {commkit-3.1.3 → commkit-3.2.0}/commkit/core/signal.py +0 -0
  105. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/__init__.py +0 -0
  106. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_block/__init__.py +0 -0
  107. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_block/_blind.py +0 -0
  108. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_block/_dd.py +0 -0
  109. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_block/_engine.py +0 -0
  110. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_common.py +0 -0
  111. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_kernels_numba.py +0 -0
  112. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/_numba_loops.py +0 -0
  113. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/blind.py +0 -0
  114. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/linear.py +0 -0
  115. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/pilots.py +0 -0
  116. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/polarization.py +0 -0
  117. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/result.py +0 -0
  118. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/sequential/__init__.py +0 -0
  119. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/sequential/_blind.py +0 -0
  120. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/sequential/_dd.py +0 -0
  121. {commkit-3.1.3 → commkit-3.2.0}/commkit/equalization/sequential/_setup.py +0 -0
  122. {commkit-3.1.3 → commkit-3.2.0}/commkit/filtering/__init__.py +0 -0
  123. {commkit-3.1.3 → commkit-3.2.0}/commkit/filtering/fiber.py +0 -0
  124. {commkit-3.1.3 → commkit-3.2.0}/commkit/filtering/linear.py +0 -0
  125. {commkit-3.1.3 → commkit-3.2.0}/commkit/filtering/pulses.py +0 -0
  126. {commkit-3.1.3 → commkit-3.2.0}/commkit/frequency.py +0 -0
  127. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/__init__.py +0 -0
  128. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/channel/__init__.py +0 -0
  129. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/channel/linear.py +0 -0
  130. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/channel/nonlinear.py +0 -0
  131. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/noise.py +0 -0
  132. {commkit-3.1.3 → commkit-3.2.0}/commkit/impairments/source.py +0 -0
  133. {commkit-3.1.3 → commkit-3.2.0}/commkit/logger.py +0 -0
  134. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/__init__.py +0 -0
  135. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/_numba_llr.py +0 -0
  136. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/bits.py +0 -0
  137. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/constellation.py +0 -0
  138. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/gray.py +0 -0
  139. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/llr.py +0 -0
  140. {commkit-3.1.3 → commkit-3.2.0}/commkit/mapping/shaping.py +0 -0
  141. {commkit-3.1.3 → commkit-3.2.0}/commkit/math.py +0 -0
  142. {commkit-3.1.3 → commkit-3.2.0}/commkit/metrics.py +0 -0
  143. {commkit-3.1.3 → commkit-3.2.0}/commkit/multirate.py +0 -0
  144. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/analysis.py +0 -0
  145. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/constellation.py +0 -0
  146. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/equalizer.py +0 -0
  147. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/eye.py +0 -0
  148. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/filter_response.py +0 -0
  149. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/spectral.py +0 -0
  150. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/sync.py +0 -0
  151. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/theme.py +0 -0
  152. {commkit-3.1.3 → commkit-3.2.0}/commkit/plotting/waveform.py +0 -0
  153. {commkit-3.1.3 → commkit-3.2.0}/commkit/py.typed +0 -0
  154. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/__init__.py +0 -0
  155. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/_common.py +0 -0
  156. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/bps.py +0 -0
  157. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/carrier_phase.py +0 -0
  158. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/corrections.py +0 -0
  159. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/pilots.py +0 -0
  160. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/pll.py +0 -0
  161. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/tikhonov.py +0 -0
  162. {commkit-3.1.3 → commkit-3.2.0}/commkit/recovery/viterbi_viterbi.py +0 -0
  163. {commkit-3.1.3 → commkit-3.2.0}/commkit/smoothing.py +0 -0
  164. {commkit-3.1.3 → commkit-3.2.0}/commkit/spectral.py +0 -0
  165. {commkit-3.1.3 → commkit-3.2.0}/commkit/timing.py +0 -0
  166. {commkit-3.1.3 → commkit-3.2.0}/examples/01-constellations-and-bit-mapping.ipynb +0 -0
  167. {commkit-3.1.3 → commkit-3.2.0}/examples/02-spectral-analysis.ipynb +0 -0
  168. {commkit-3.1.3 → commkit-3.2.0}/examples/03-digital-filters.ipynb +0 -0
  169. {commkit-3.1.3 → commkit-3.2.0}/examples/04-pulse-shaping-and-matched-filtering.ipynb +0 -0
  170. {commkit-3.1.3 → commkit-3.2.0}/examples/05-multirate-and-resampling.ipynb +0 -0
  171. {commkit-3.1.3 → commkit-3.2.0}/examples/08-probabilistic-shaping-and-coded-modulation.ipynb +0 -0
  172. {commkit-3.1.3 → commkit-3.2.0}/examples/09-laser-phase-noise.ipynb +0 -0
  173. {commkit-3.1.3 → commkit-3.2.0}/examples/10-front-end-impairments.ipynb +0 -0
  174. {commkit-3.1.3 → commkit-3.2.0}/examples/11-frame-synchronization-and-timing.ipynb +0 -0
  175. {commkit-3.1.3 → commkit-3.2.0}/examples/12-frequency-offset-estimation.ipynb +0 -0
  176. {commkit-3.1.3 → commkit-3.2.0}/examples/13-blind-carrier-phase-recovery.ipynb +0 -0
  177. {commkit-3.1.3 → commkit-3.2.0}/examples/14-pilot-aided-carrier-recovery.ipynb +0 -0
  178. {commkit-3.1.3 → commkit-3.2.0}/examples/15-linear-channel-equalization.ipynb +0 -0
  179. {commkit-3.1.3 → commkit-3.2.0}/examples/16-adaptive-equalization.ipynb +0 -0
  180. {commkit-3.1.3 → commkit-3.2.0}/examples/17-blind-equalization.ipynb +0 -0
  181. {commkit-3.1.3 → commkit-3.2.0}/examples/18-polarization-multiplexing.ipynb +0 -0
  182. {commkit-3.1.3 → commkit-3.2.0}/examples/19-chromatic-dispersion.ipynb +0 -0
  183. {commkit-3.1.3 → commkit-3.2.0}/examples/20-nonlinear-fiber-and-backpropagation.ipynb +0 -0
  184. {commkit-3.1.3 → commkit-3.2.0}/examples/21-fec-in-optical-standards.ipynb +0 -0
  185. {commkit-3.1.3 → commkit-3.2.0}/examples/22-coherent-transceiver-end-to-end.ipynb +0 -0
  186. {commkit-3.1.3 → commkit-3.2.0}/examples/23-carrier-phase-characterization.ipynb +0 -0
  187. {commkit-3.1.3 → commkit-3.2.0}/examples/24-laser-linewidth-self-heterodyne.ipynb +0 -0
  188. {commkit-3.1.3 → commkit-3.2.0}/examples/25-laser-linewidth-short-delay-and-flicker.ipynb +0 -0
  189. {commkit-3.1.3 → commkit-3.2.0}/examples/26-laser-linewidth-self-homodyne-iq.ipynb +0 -0
  190. {commkit-3.1.3 → commkit-3.2.0}/examples/27-measurement-template-self-heterodyne.ipynb +0 -0
  191. {commkit-3.1.3 → commkit-3.2.0}/examples/28-measurement-template-self-homodyne-iq.ipynb +0 -0
  192. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_allan.py +0 -0
  193. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_drift.py +0 -0
  194. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_fm_noise.py +0 -0
  195. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_interferometry.py +0 -0
  196. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_linewidth.py +0 -0
  197. {commkit-3.1.3 → commkit-3.2.0}/tests/analysis/test_trajectory.py +0 -0
  198. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_algebraic.py +0 -0
  199. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_convolutional.py +0 -0
  200. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_crc.py +0 -0
  201. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_gf2.py +0 -0
  202. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_interleaving.py +0 -0
  203. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_ldpc.py +0 -0
  204. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_ldpc_kernel.py +0 -0
  205. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_ldpc_tables.py +0 -0
  206. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_linear_codes.py +0 -0
  207. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_polar.py +0 -0
  208. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_product.py +0 -0
  209. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_ratematch.py +0 -0
  210. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_shaping.py +0 -0
  211. {commkit-3.1.3 → commkit-3.2.0}/tests/coding/test_turbo.py +0 -0
  212. {commkit-3.1.3 → commkit-3.2.0}/tests/common/__init__.py +0 -0
  213. {commkit-3.1.3 → commkit-3.2.0}/tests/common/coding.py +0 -0
  214. {commkit-3.1.3 → commkit-3.2.0}/tests/common/conversions.py +0 -0
  215. {commkit-3.1.3 → commkit-3.2.0}/tests/common/kernel_utils.py +0 -0
  216. {commkit-3.1.3 → commkit-3.2.0}/tests/common/memory.py +0 -0
  217. {commkit-3.1.3 → commkit-3.2.0}/tests/common/metrics.py +0 -0
  218. {commkit-3.1.3 → commkit-3.2.0}/tests/common/periodic.py +0 -0
  219. {commkit-3.1.3 → commkit-3.2.0}/tests/common/reference_impl.py +0 -0
  220. {commkit-3.1.3 → commkit-3.2.0}/tests/common/signals.py +0 -0
  221. {commkit-3.1.3 → commkit-3.2.0}/tests/conftest.py +0 -0
  222. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_frame.py +0 -0
  223. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_generation.py +0 -0
  224. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_psqam.py +0 -0
  225. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_signal.py +0 -0
  226. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_signal_adapter.py +0 -0
  227. {commkit-3.1.3 → commkit-3.2.0}/tests/core/test_signal_mimo.py +0 -0
  228. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_blind.py +0 -0
  229. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_block.py +0 -0
  230. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_bps_kernel.py +0 -0
  231. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_cpr.py +0 -0
  232. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_cs_kernel.py +0 -0
  233. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_equalizer_oracles.py +0 -0
  234. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_linear.py +0 -0
  235. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_mimo.py +0 -0
  236. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_polarization.py +0 -0
  237. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_sequential.py +0 -0
  238. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_state.py +0 -0
  239. {commkit-3.1.3 → commkit-3.2.0}/tests/equalization/test_winit.py +0 -0
  240. {commkit-3.1.3 → commkit-3.2.0}/tests/impairments/channel/test_channel_linear.py +0 -0
  241. {commkit-3.1.3 → commkit-3.2.0}/tests/impairments/channel/test_channel_nonlinear.py +0 -0
  242. {commkit-3.1.3 → commkit-3.2.0}/tests/impairments/test_frontend.py +0 -0
  243. {commkit-3.1.3 → commkit-3.2.0}/tests/impairments/test_noise.py +0 -0
  244. {commkit-3.1.3 → commkit-3.2.0}/tests/impairments/test_source.py +0 -0
  245. {commkit-3.1.3 → commkit-3.2.0}/tests/mapping/test_bits.py +0 -0
  246. {commkit-3.1.3 → commkit-3.2.0}/tests/mapping/test_constellation.py +0 -0
  247. {commkit-3.1.3 → commkit-3.2.0}/tests/mapping/test_gray.py +0 -0
  248. {commkit-3.1.3 → commkit-3.2.0}/tests/mapping/test_llr.py +0 -0
  249. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_analysis.py +0 -0
  250. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_constellation.py +0 -0
  251. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_equalizer.py +0 -0
  252. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_eye.py +0 -0
  253. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_filter_response.py +0 -0
  254. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_spectral.py +0 -0
  255. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_sync.py +0 -0
  256. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_theme.py +0 -0
  257. {commkit-3.1.3 → commkit-3.2.0}/tests/plotting/test_plot_waveform.py +0 -0
  258. {commkit-3.1.3 → commkit-3.2.0}/tests/plugins/__init__.py +0 -0
  259. {commkit-3.1.3 → commkit-3.2.0}/tests/plugins/precision_trace.py +0 -0
  260. {commkit-3.1.3 → commkit-3.2.0}/tests/plugins/transfer_trace.py +0 -0
  261. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_bps.py +0 -0
  262. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_corrections.py +0 -0
  263. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_joint.py +0 -0
  264. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_pilots.py +0 -0
  265. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_pll.py +0 -0
  266. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_recovery_oracles.py +0 -0
  267. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_tikhonov.py +0 -0
  268. {commkit-3.1.3 → commkit-3.2.0}/tests/recovery/test_viterbi_viterbi.py +0 -0
  269. {commkit-3.1.3 → commkit-3.2.0}/tests/test_array.py +0 -0
  270. {commkit-3.1.3 → commkit-3.2.0}/tests/test_backend.py +0 -0
  271. {commkit-3.1.3 → commkit-3.2.0}/tests/test_cuda_infra.py +0 -0
  272. {commkit-3.1.3 → commkit-3.2.0}/tests/test_dispersion.py +0 -0
  273. {commkit-3.1.3 → commkit-3.2.0}/tests/test_examples.py +0 -0
  274. {commkit-3.1.3 → commkit-3.2.0}/tests/test_fiber.py +0 -0
  275. {commkit-3.1.3 → commkit-3.2.0}/tests/test_filtering.py +0 -0
  276. {commkit-3.1.3 → commkit-3.2.0}/tests/test_frequency.py +0 -0
  277. {commkit-3.1.3 → commkit-3.2.0}/tests/test_import_hygiene.py +0 -0
  278. {commkit-3.1.3 → commkit-3.2.0}/tests/test_io.py +0 -0
  279. {commkit-3.1.3 → commkit-3.2.0}/tests/test_logger.py +0 -0
  280. {commkit-3.1.3 → commkit-3.2.0}/tests/test_math.py +0 -0
  281. {commkit-3.1.3 → commkit-3.2.0}/tests/test_metrics.py +0 -0
  282. {commkit-3.1.3 → commkit-3.2.0}/tests/test_multirate.py +0 -0
  283. {commkit-3.1.3 → commkit-3.2.0}/tests/test_pulse_shaping.py +0 -0
  284. {commkit-3.1.3 → commkit-3.2.0}/tests/test_signal_pipeline.py +0 -0
  285. {commkit-3.1.3 → commkit-3.2.0}/tests/test_smoothing.py +0 -0
  286. {commkit-3.1.3 → commkit-3.2.0}/tests/test_spectral.py +0 -0
  287. {commkit-3.1.3 → commkit-3.2.0}/tests/test_timing.py +0 -0
  288. {commkit-3.1.3 → commkit-3.2.0}/tests/test_working_memory.py +0 -0
@@ -175,7 +175,7 @@ Dependencies point downward only:
175
175
  - Never use a global RNG.
176
176
  - **Types:** a transform is written `def f(samples: S, ...) -> S` with the TypeVar `S` from `core/_signal_adapter.py` (bound to `np.ndarray | Signal`), so a Signal gives a Signal and an array an array. Do not reassign the `samples` parameter; name the unwrapped array `x`.
177
177
  - **Device follows the data.** There are no `backend=` arguments and no global switches. Unsupported array types (JAX, PyTorch) raise `TypeError`.
178
- - Only factories with no input data to follow (`generate`, `generate_phase_noise`, `Preamble`/`SingleCarrierFrame.to_signal`, `load_npz`) take `device: str = "cpu"`, validated with `require_device()`. They draw randomness as the rule above says and do the vectorized work (mapping, shaping) on `device`. The default is never "GPU if available".
178
+ - Only factories with no input data to follow (`generate`, `generate_phase_noise`, `Preamble`/`SingleCarrierFrame.to_signal`, `load_npz`, and the Monte Carlo EXIT curves `decoder_exit_curve` and `demapper_exit_curve`) take `device: str = "cpu"`, validated with `require_device()` (in `coding`, which cannot import `core`, by the same check in `coding.exit`). They draw randomness as the rule above says and do the vectorized work (mapping, shaping) on `device`. The default is never "GPU if available".
179
179
  - **No `debug_plot`.** Numerical code never imports plotting. Plot functions consume results or recompute through public compute functions.
180
180
  - **Design and apply are separate functions**, for example `RRC(...).taps(sps)` and `fir_filter`, or `butterworth_sos` and `iir_filter`.
181
181
 
@@ -227,6 +227,7 @@ Docstrings describe the code as it is; a change in behavior updates them in the
227
227
  - Wrong input raises, with a message naming the argument.
228
228
  - **No fallbacks for a broken environment.** Code never catches a failure of CuPy, a CUDA kernel (compile, load, launch), a CUDA-graph capture or any other dependency in order to run a slower or different implementation; the failure raises to the caller. The kernels and graphs are tested on a GPU before every release (§2), a broken CuPy already fails when data moves to the GPU, and a path kept "just in case" is code that no test or user runs. Dispatch on the *input* is different and allowed: a kernel's documented limits (dtype, number of points, phases or channels) may route to the general implementation where that implementation exists anyway (the CPU's), and the dispatch says so where it happens. A GPU-only path that would serve only inputs beyond a kernel's limit is not written; such input raises (`compute_llr` above 16 bits per symbol).
229
229
  - `logger` is for diagnostics only. Per-channel logging that needs a device-to-host transfer is wrapped in `if logger.isEnabledFor(logging.INFO):`.
230
+ - **Levels:** `DEBUG` traces what a call is about to do (method, parameters, sizes). `INFO` is one summary per public call of what a user would print next: the values a metric or estimator found, the parameters an impairment applied, an equalizer's exit MSE, a decoder's failed checks and iterations, what `generate`, a frame or `io` produced. `WARNING` flags a result that is returned but suspect (no convergence, a fit outside its valid range, a near-zero power, a code with 4-cycles). Value objects and pure helpers (taps, tables, code construction) do not log. `warnings.warn` is used only for `PrecisionWarning`, which callers filter.
230
231
  - The library never configures handlers, Matplotlib or warning filters at import time.
231
232
 
232
233
  ---
@@ -263,6 +264,7 @@ Docstrings describe the code as it is; a change in behavior updates them in the
263
264
  | Binary linear algebra of codes: encoding, syndromes, the correlations of maximum-likelihood decoding, the syndromes of algebraic decoding, Chase's test patterns through a hard decoder | one float32 GEMM per chunk (`coding._gf2.matmul_mod2`: BLAS, cuBLAS), exact below an inner dimension of 2^24, its parity taken in place on the CPU and by one elementwise kernel writing int8 on the GPU; small tables (generators, coset leaders) cached per code object and device (`backend._device_tables`) | follows the input |
264
265
  | Algebraic decoding from the syndromes (BCH, Reed-Solomon): Berlekamp-Massey, a Chien search that stops at the locator's degree, Forney at the roots | CPU: Numba `parallel=True` over codewords. GPU: CUDA kernel (`algebraic_correct`), one thread per codeword, the same steps in integer table arithmetic, so both agree exactly (a CuPy version running Berlekamp-Massey in lockstep over the codewords, about 450 launches per decode, was 12x slower on KP4) | follows the input |
265
266
  | Iterative decoding of many codewords: layered LDPC belief propagation (min-sum, sum-product) | CPU: Numba `parallel=True` over codewords, all layers and iterations inside, without fast-math. GPU: CUDA kernel (`ldpc_layered`), one thread block per codeword, the rows of a layer in parallel, early stop per codeword inside the kernel; the same rows in the same order on both, so min-sum agrees bit for bit (a CuPy version, about 12 launches per layer, was 7-23x slower) | follows the input |
267
+ | Analysis by Monte Carlo (EXIT curves) | the work is the existing compiled decoders and vectorized NumPy/CuPy (the demapper's distance table in chunks, histograms on the device); the closed-form parts (the `J` table, LDPC node curves, the chart's trajectory) are host NumPy on grids of a few thousand points, about 0.1 s. No kernel of its own: a whole curve takes 0.05-0.3 s on the GPU | follows `device` |
266
268
  | Elementwise chains between multi-core FFTs (the fiber solver's Kerr and PMD stages) | NumPy: a Numba `parallel=True` pass there competes with `scipy.fft`'s threads (the solver's Numba passes measured 1.1-1.8x slower end to end, 2^14-2^20); adopt one only on a paired end-to-end A/B | CPU |
267
269
 
268
270
  **Numba kernels live at module level**, in a private module that a getter imports on first use (`equalization/_numba_loops.py`, `coding/_numba_loops.py`, `mapping/_numba_llr.py`), so `import commkit` does not load Numba and the disk cache (`cache=True`) keeps them across processes. A kernel defined inside a function that calls another kernel defined there captures that dispatcher in its closure, which Numba's cache key does not reproduce in a new process: it compiled again in every process (3 s for `compute_llr`, 6 s for polar list decoding). A getter may build a kernel in a closure that captures only constants (`_get_numba_sos`).
@@ -4,6 +4,21 @@ Notable changes to CommKit, newest first. Performance figures are from the refer
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [3.2.0] - 2026-10-30
8
+
9
+ EXIT analysis and coding diagnostics. EXIT charts for any soft-in soft-out component, measured through the existing decoders or the demapper, or in closed form for LDPC codes with their threshold; plots of LLR distributions, parity-check matrices and EXIT charts; and INFO logging in the modules where it was missing. Nothing changes for existing code.
10
+
11
+ ### Added
12
+
13
+ - **EXIT analysis** in `commkit.coding.exit`. `ExitCurve` is the transfer curve of one soft-in soft-out component and `exit_chart(first, second)` the `ExitChart` of two, with the decoding trajectory, whether the tunnel is open and where it closes. Curves come from `decoder_exit_curve` (measured through `decode` for any code whose decoder returns a-posteriori LLRs: LDPC, BCJR, Chase), `demapper_exit_curve` (measured, for iterative demapping on AWGN) and `ldpc_exit_curves` (the variable and check nodes of an LDPC code in closed form), with `ldpc_threshold`, the belief-propagation threshold in the Gaussian approximation (0.498 for the DVB-S2 rate-1/2 short code, the NGMI at which simulated QPSK frames start to decode). Measured curves run on the chosen device; the docstrings list the limitations (Gaussian a-priori LLRs, long interleavers, no curve for decoders without soft output such as turbo and polar, early stopping).
14
+ - **Coding plots**: `plot_llr_distribution(llrs, bits)` draws the LLR densities given the transmitted bit and their consistency, `log p(L | 0) / p(L | 1)` against `L`, which shows LLRs from a wrong `noise_var` or demapper model; `plot_parity_check(code)` draws the nonzero entries and node degrees of a parity-check matrix; `plot_exit_chart(chart)` draws an `ExitChart` and marks where a closed tunnel stalls.
15
+ - INFO logging where it was missing: `decode` reports the blocks whose own check failed and the iterations used, `estimate_iq_imbalance` its estimate, and `SingleCarrierFrame.to_signal`, `save_npz` and `load_npz` what they built, saved or loaded. Notebook 00 shows how to turn it on.
16
+ - Notebook 06 checks LLR consistency; notebook 07 predicts the LDPC threshold with an EXIT chart and charts iterative demapping with Gray and natural labels.
17
+
18
+ ### Development
19
+
20
+ - AGENTS.md states the logging levels: DEBUG for what a call is about to do, INFO for one summary per public call, WARNING for a returned but suspect result; value objects do not log, and `warnings.warn` is kept for `PrecisionWarning`.
21
+
7
22
  ## [3.1.3] - 2026-10-30
8
23
 
9
24
  Additive noise without a scaling knob. `apply_awgn` either measures the signal or takes an absolute noise variance, and the OSNR moves to its own function, `apply_ase`.
@@ -303,7 +318,11 @@ See the [GitHub release](https://github.com/lokgar/commkit/releases/tag/v1.1.0)
303
318
 
304
319
  First release. See the [GitHub release](https://github.com/lokgar/commkit/releases/tag/v1.0.0).
305
320
 
306
- [Unreleased]: https://github.com/lokgar/commkit/compare/v3.1.0...HEAD
321
+ [Unreleased]: https://github.com/lokgar/commkit/compare/v3.2.0...HEAD
322
+ [3.2.0]: https://github.com/lokgar/commkit/compare/v3.1.3...v3.2.0
323
+ [3.1.3]: https://github.com/lokgar/commkit/compare/v3.1.2...v3.1.3
324
+ [3.1.2]: https://github.com/lokgar/commkit/compare/v3.1.1...v3.1.2
325
+ [3.1.1]: https://github.com/lokgar/commkit/compare/v3.1.0...v3.1.1
307
326
  [3.1.0]: https://github.com/lokgar/commkit/compare/v3.0.0...v3.1.0
308
327
  [3.0.0]: https://github.com/lokgar/commkit/compare/v2.3.0...v3.0.0
309
328
  [2.3.0]: https://github.com/lokgar/commkit/compare/v2.2.0...v2.3.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: commkit
3
- Version: 3.1.3
3
+ Version: 3.2.0
4
4
  Summary: A Python library for high-performance digital communications research.
5
5
  Project-URL: Homepage, https://github.com/lokgar/commkit
6
6
  Project-URL: Repository, https://github.com/lokgar/commkit
@@ -129,8 +129,8 @@ CommKit never picks a device for you: data stays where you put it, and each func
129
129
  | [`commkit.math`](https://github.com/lokgar/commkit/blob/main/commkit/math.py) | `rms`, `normalize`, dB conversions. |
130
130
  | [`commkit.smoothing`](https://github.com/lokgar/commkit/blob/main/commkit/smoothing.py) | Display and estimation smoothers (moving average, Savitzky-Golay, 2-D density). Signal-chain filters are in `filtering`. |
131
131
  | [`commkit.io`](https://github.com/lokgar/commkit/blob/main/commkit/io.py) | `save_npz` / `load_npz` for Signals. |
132
- | [`commkit.plotting`](https://github.com/lokgar/commkit/tree/main/commkit/plotting) | Constellations, eye diagrams, spectra, filter responses, equalizer convergence, and synchronization and laser diagnostics that draw the estimates. Imported on first use. |
133
- | [`commkit.coding`](https://github.com/lokgar/commkit/tree/main/commkit/coding) | Channel coding: `encode` / `decode` dispatched on a code object, `LinearBlockCode` (Hamming, extended and shortened), syndrome and maximum-likelihood decoding; `LDPCCode` (DVB-S2, the 802.3ca / 50G-PON code, any parity-check or quasi-cyclic matrix) with layered min-sum and sum-product decoding on the CPU (Numba) and GPU (CUDA); `ReedSolomonCode` (G.709, KR4, KP4, 10G-EPON, XGS-PON) and `BCHCode` with Berlekamp-Massey decoding; Chase-Pyndiah soft decoding; the G.709.2 `StaircaseCode` and `Concatenated` codes (400ZR C-FEC with its exact Hamming(128,119), 802.3dj); `PolarCode` (5G NR information set) with SC and CRC-aided SCL decoding; `ConvolutionalCode` (K = 7, terminated or tail-biting) with Viterbi and BCJR, `TurboCode` (LTE); `CRC` (NR, LTE, Ethernet), `Interleaver`, `Punctured` and `Shortened`; distribution matching (`CCDM`) and probabilistic amplitude shaping (`PAS`). Coded payloads through `generate(..., code=)`. |
132
+ | [`commkit.plotting`](https://github.com/lokgar/commkit/tree/main/commkit/plotting) | Constellations, eye diagrams, spectra, filter responses, equalizer convergence, synchronization and laser diagnostics that draw the estimates, and coding diagnostics: LLR distributions and their consistency, parity-check matrices, EXIT charts. Imported on first use. |
133
+ | [`commkit.coding`](https://github.com/lokgar/commkit/tree/main/commkit/coding) | Channel coding: `encode` / `decode` dispatched on a code object, `LinearBlockCode` (Hamming, extended and shortened), syndrome and maximum-likelihood decoding; `LDPCCode` (DVB-S2, the 802.3ca / 50G-PON code, any parity-check or quasi-cyclic matrix) with layered min-sum and sum-product decoding on the CPU (Numba) and GPU (CUDA); `ReedSolomonCode` (G.709, KR4, KP4, 10G-EPON, XGS-PON) and `BCHCode` with Berlekamp-Massey decoding; Chase-Pyndiah soft decoding; the G.709.2 `StaircaseCode` and `Concatenated` codes (400ZR C-FEC with its exact Hamming(128,119), 802.3dj); `PolarCode` (5G NR information set) with SC and CRC-aided SCL decoding; `ConvolutionalCode` (K = 7, terminated or tail-biting) with Viterbi and BCJR, `TurboCode` (LTE); `CRC` (NR, LTE, Ethernet), `Interleaver`, `Punctured` and `Shortened`; distribution matching (`CCDM`) and probabilistic amplitude shaping (`PAS`); EXIT charts of measured decoder and demapper curves, and of LDPC codes in closed form with their threshold. Coded payloads through `generate(..., code=)`. |
134
134
 
135
135
  Importing `commkit` has no side effects: it configures no logging, Matplotlib or warning filters, and does not touch the GPU.
136
136
 
@@ -93,8 +93,8 @@ CommKit never picks a device for you: data stays where you put it, and each func
93
93
  | [`commkit.math`](https://github.com/lokgar/commkit/blob/main/commkit/math.py) | `rms`, `normalize`, dB conversions. |
94
94
  | [`commkit.smoothing`](https://github.com/lokgar/commkit/blob/main/commkit/smoothing.py) | Display and estimation smoothers (moving average, Savitzky-Golay, 2-D density). Signal-chain filters are in `filtering`. |
95
95
  | [`commkit.io`](https://github.com/lokgar/commkit/blob/main/commkit/io.py) | `save_npz` / `load_npz` for Signals. |
96
- | [`commkit.plotting`](https://github.com/lokgar/commkit/tree/main/commkit/plotting) | Constellations, eye diagrams, spectra, filter responses, equalizer convergence, and synchronization and laser diagnostics that draw the estimates. Imported on first use. |
97
- | [`commkit.coding`](https://github.com/lokgar/commkit/tree/main/commkit/coding) | Channel coding: `encode` / `decode` dispatched on a code object, `LinearBlockCode` (Hamming, extended and shortened), syndrome and maximum-likelihood decoding; `LDPCCode` (DVB-S2, the 802.3ca / 50G-PON code, any parity-check or quasi-cyclic matrix) with layered min-sum and sum-product decoding on the CPU (Numba) and GPU (CUDA); `ReedSolomonCode` (G.709, KR4, KP4, 10G-EPON, XGS-PON) and `BCHCode` with Berlekamp-Massey decoding; Chase-Pyndiah soft decoding; the G.709.2 `StaircaseCode` and `Concatenated` codes (400ZR C-FEC with its exact Hamming(128,119), 802.3dj); `PolarCode` (5G NR information set) with SC and CRC-aided SCL decoding; `ConvolutionalCode` (K = 7, terminated or tail-biting) with Viterbi and BCJR, `TurboCode` (LTE); `CRC` (NR, LTE, Ethernet), `Interleaver`, `Punctured` and `Shortened`; distribution matching (`CCDM`) and probabilistic amplitude shaping (`PAS`). Coded payloads through `generate(..., code=)`. |
96
+ | [`commkit.plotting`](https://github.com/lokgar/commkit/tree/main/commkit/plotting) | Constellations, eye diagrams, spectra, filter responses, equalizer convergence, synchronization and laser diagnostics that draw the estimates, and coding diagnostics: LLR distributions and their consistency, parity-check matrices, EXIT charts. Imported on first use. |
97
+ | [`commkit.coding`](https://github.com/lokgar/commkit/tree/main/commkit/coding) | Channel coding: `encode` / `decode` dispatched on a code object, `LinearBlockCode` (Hamming, extended and shortened), syndrome and maximum-likelihood decoding; `LDPCCode` (DVB-S2, the 802.3ca / 50G-PON code, any parity-check or quasi-cyclic matrix) with layered min-sum and sum-product decoding on the CPU (Numba) and GPU (CUDA); `ReedSolomonCode` (G.709, KR4, KP4, 10G-EPON, XGS-PON) and `BCHCode` with Berlekamp-Massey decoding; Chase-Pyndiah soft decoding; the G.709.2 `StaircaseCode` and `Concatenated` codes (400ZR C-FEC with its exact Hamming(128,119), 802.3dj); `PolarCode` (5G NR information set) with SC and CRC-aided SCL decoding; `ConvolutionalCode` (K = 7, terminated or tail-biting) with Viterbi and BCJR, `TurboCode` (LTE); `CRC` (NR, LTE, Ethernet), `Interleaver`, `Punctured` and `Shortened`; distribution matching (`CCDM`) and probabilistic amplitude shaping (`PAS`); EXIT charts of measured decoder and demapper curves, and of LDPC codes in closed form with their threshold. Coded payloads through `generate(..., code=)`. |
98
98
 
99
99
  Importing `commkit` has no side effects: it configures no logging, Matplotlib or warning filters, and does not touch the GPU.
100
100
 
@@ -31,7 +31,7 @@ Matplotlib, change warning filters, or touch the GPU.
31
31
  import importlib
32
32
  from typing import Any
33
33
 
34
- __version__ = "3.1.3"
34
+ __version__ = "3.2.0"
35
35
 
36
36
  from .backend import PrecisionWarning
37
37
  from .core import (
@@ -23,13 +23,26 @@ Codes: :class:`LinearBlockCode` (Hamming), :class:`LDPCCode` (DVB-S2, PON),
23
23
  :class:`Stages`, :class:`SC`, :class:`SCL`, :class:`Viterbi`, :class:`BCJR`,
24
24
  :class:`TurboIterations`. Bit
25
25
  permutations: :func:`interleave` and :func:`deinterleave` with an
26
- :class:`Interleaver`.
26
+ :class:`Interleaver`. EXIT analysis: :func:`exit_chart` of two
27
+ :class:`ExitCurve` objects, from :func:`decoder_exit_curve` (any soft-output
28
+ decoder), :func:`demapper_exit_curve` (iterative demapping) or
29
+ :func:`ldpc_exit_curves` (LDPC nodes, closed form, with
30
+ :func:`ldpc_threshold`).
27
31
  """
28
32
 
29
33
  from .algebraic import BCHCode, BerlekampMassey, ReedSolomonCode
30
34
  from .base import DecodeResult, decode, encode
31
35
  from .convolutional import BCJR, ConvolutionalCode, Viterbi
32
36
  from .crc import CRC
37
+ from .exit import (
38
+ ExitChart,
39
+ ExitCurve,
40
+ decoder_exit_curve,
41
+ demapper_exit_curve,
42
+ exit_chart,
43
+ ldpc_exit_curves,
44
+ ldpc_threshold,
45
+ )
33
46
  from .interleaving import Interleaver, deinterleave, interleave
34
47
  from .ldpc import LDPCCode, MinSum, SumProduct
35
48
  from .linear import Chase, LinearBlockCode, MaximumLikelihood, Syndrome
@@ -49,6 +62,8 @@ __all__ = [
49
62
  "Concatenated",
50
63
  "ConvolutionalCode",
51
64
  "DecodeResult",
65
+ "ExitChart",
66
+ "ExitCurve",
52
67
  "HardIterations",
53
68
  "Interleaver",
54
69
  "LDPCCode",
@@ -72,5 +87,10 @@ __all__ = [
72
87
  "decode",
73
88
  "deinterleave",
74
89
  "encode",
90
+ "decoder_exit_curve",
91
+ "demapper_exit_curve",
92
+ "exit_chart",
75
93
  "interleave",
94
+ "ldpc_exit_curves",
95
+ "ldpc_threshold",
76
96
  ]
@@ -17,6 +17,7 @@ along the last axis; a block never spans channels.
17
17
  from __future__ import annotations
18
18
 
19
19
  import dataclasses
20
+ import logging
20
21
  from collections.abc import Callable
21
22
  from dataclasses import dataclass
22
23
  from typing import Any, NamedTuple
@@ -24,7 +25,7 @@ from typing import Any, NamedTuple
24
25
  import numpy as np
25
26
 
26
27
  from .._array import as_2d, restore_1d, validate_array, warn_if_double
27
- from ..backend import ArrayType, get_array_module
28
+ from ..backend import ArrayType, get_array_module, to_device
28
29
  from ..logger import logger
29
30
 
30
31
  __all__ = ["DecodeResult", "decode", "encode"]
@@ -272,6 +273,26 @@ def encode(bits: ArrayType, *, code: Any) -> ArrayType:
272
273
  return restore_1d(was_1d, out.reshape(x2.shape[0], num_blocks * code.n))
273
274
 
274
275
 
276
+ def _log_decode(res: _Decoded, code: Any, method: Any) -> None:
277
+ """Log the decoder's own success check and iterations (INFO level)."""
278
+ # Two (R,) transfers, made only when INFO is enabled.
279
+ if not logger.isEnabledFor(logging.INFO) or res.valid.size == 0:
280
+ return
281
+ valid = to_device(res.valid, "cpu")
282
+ iterations = to_device(res.iterations, "cpu")
283
+ failed = int(valid.size - np.count_nonzero(valid))
284
+ most = int(iterations.max())
285
+ used = f", iterations mean {float(iterations.mean()):.1f}, max {most}"
286
+ logger.info(
287
+ "Decoded %d block(s) of %r with %r: %d failed the decoder's check%s.",
288
+ valid.size,
289
+ code,
290
+ method,
291
+ failed,
292
+ used if most > 1 else "",
293
+ )
294
+
295
+
275
296
  def decode(llrs: ArrayType, *, code: Any, method: Any = None) -> DecodeResult:
276
297
  """Decode LLRs (or hard decisions) of a code's transmitted bits.
277
298
 
@@ -325,6 +346,7 @@ def decode(llrs: ArrayType, *, code: Any, method: Any = None) -> DecodeResult:
325
346
  return None
326
347
  return restore_1d(was_1d, a.reshape(x2.shape[0], num_blocks * size))
327
348
 
349
+ _log_decode(res, code, method)
328
350
  return DecodeResult(
329
351
  bits=shaped(res.bits, code.k),
330
352
  llrs=shaped(res.llrs, code.n),