commkit 3.4.0__tar.gz → 3.6.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.
- commkit-3.6.0/.github/icon.svg +1 -0
- commkit-3.6.0/.github/logo.svg +1 -0
- {commkit-3.4.0 → commkit-3.6.0}/.github/workflows/ci.yml +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/AGENTS.md +24 -65
- {commkit-3.4.0 → commkit-3.6.0}/CHANGELOG.md +69 -1
- {commkit-3.4.0 → commkit-3.6.0}/PKG-INFO +13 -13
- {commkit-3.4.0 → commkit-3.6.0}/README.md +12 -12
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_fiber.py +18 -1
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_signal_pipeline.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/workloads.py +4 -2
- {commkit-3.4.0 → commkit-3.6.0}/commkit/__init__.py +1 -1
- commkit-3.6.0/commkit/_dispersion.py +194 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_fiber.py +8 -9
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_sequences.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/__init__.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/_common.py +0 -115
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/drift.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/fm_noise.py +8 -8
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/interferometry.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/linewidth/__init__.py +7 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/linewidth/dsh.py +23 -20
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/linewidth/phase.py +112 -56
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/linewidth/result.py +32 -28
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/trajectory.py +7 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/__init__.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/exit.py +9 -5
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/performance.py +16 -14
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/product.py +7 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/core/__init__.py +5 -2
- {commkit-3.4.0 → commkit-3.6.0}/commkit/core/frame.py +5 -154
- {commkit-3.4.0 → commkit-3.6.0}/commkit/core/generation.py +2 -2
- commkit-3.6.0/commkit/core/preamble.py +170 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/__init__.py +2 -3
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/_block/__init__.py +7 -4
- commkit-3.4.0/commkit/equalization/blind.py → commkit-3.6.0/commkit/equalization/_block/_blind.py +206 -11
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/_block/_dd.py +13 -1
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/_numba_loops.py +4 -2
- commkit-3.6.0/commkit/equalization/_sequential/__init__.py +21 -0
- {commkit-3.4.0/commkit/equalization/sequential → commkit-3.6.0/commkit/equalization/_sequential}/_blind.py +18 -1
- {commkit-3.4.0/commkit/equalization/sequential → commkit-3.6.0/commkit/equalization/_sequential}/_dd.py +30 -5
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/linear.py +4 -4
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/polarization.py +2 -2
- {commkit-3.4.0 → commkit-3.6.0}/commkit/filtering/__init__.py +21 -3
- commkit-3.6.0/commkit/filtering/fiber.py +1238 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/filtering/response.py +19 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/frequency.py +20 -20
- {commkit-3.4.0 → commkit-3.6.0}/commkit/impairments/__init__.py +2 -2
- commkit-3.4.0/commkit/impairments/channel/linear.py → commkit-3.6.0/commkit/impairments/fiber_channel.py +194 -12
- {commkit-3.4.0 → commkit-3.6.0}/commkit/impairments/noise.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/commkit/metrics/error_rates.py +22 -23
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/__init__.py +12 -8
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/analysis.py +165 -56
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/coding.py +10 -4
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/constellation.py +2 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/filter_response.py +5 -1
- commkit-3.6.0/commkit/plotting/frequency.py +374 -0
- commkit-3.6.0/commkit/plotting/recovery.py +551 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/theme.py +117 -5
- commkit-3.6.0/commkit/plotting/timing.py +129 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/__init__.py +7 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/_common.py +6 -3
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/carrier_phase.py +13 -13
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/corrections.py +11 -11
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/pilots.py +9 -7
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/pll.py +18 -13
- {commkit-3.4.0 → commkit-3.6.0}/commkit/timing.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/examples/07-channel-coding.ipynb +5 -5
- {commkit-3.4.0 → commkit-3.6.0}/examples/08-probabilistic-shaping-and-coded-modulation.ipynb +5 -3
- {commkit-3.4.0 → commkit-3.6.0}/examples/10-front-end-impairments.ipynb +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/examples/12-frequency-offset-estimation.ipynb +6 -6
- {commkit-3.4.0 → commkit-3.6.0}/examples/14-pilot-aided-carrier-recovery.ipynb +16 -12
- {commkit-3.4.0 → commkit-3.6.0}/examples/18-polarization-multiplexing.ipynb +6 -4
- commkit-3.6.0/examples/19-chromatic-dispersion.ipynb +657 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/20-nonlinear-fiber-and-backpropagation.ipynb +23 -19
- {commkit-3.4.0 → commkit-3.6.0}/examples/21-fec-in-optical-standards.ipynb +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/examples/22-coherent-transceiver-end-to-end.ipynb +8 -7
- {commkit-3.4.0 → commkit-3.6.0}/examples/23-carrier-phase-characterization.ipynb +78 -52
- {commkit-3.4.0 → commkit-3.6.0}/examples/24-laser-linewidth-self-heterodyne.ipynb +16 -10
- {commkit-3.4.0 → commkit-3.6.0}/examples/25-laser-linewidth-short-delay-and-flicker.ipynb +28 -16
- {commkit-3.4.0 → commkit-3.6.0}/examples/26-laser-linewidth-self-homodyne-iq.ipynb +27 -22
- {commkit-3.4.0 → commkit-3.6.0}/examples/27-measurement-template-self-heterodyne.ipynb +29 -15
- {commkit-3.4.0 → commkit-3.6.0}/examples/28-measurement-template-self-homodyne-iq.ipynb +37 -19
- {commkit-3.4.0 → commkit-3.6.0}/examples/README.md +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/pyproject.toml +2 -5
- {commkit-3.4.0 → commkit-3.6.0}/scripts/sanitize.sh +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_drift.py +2 -2
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_linewidth.py +87 -50
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_ldpc.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_polar.py +2 -4
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_product.py +12 -5
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_shaping.py +11 -7
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_turbo.py +4 -4
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/coding.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/signals.py +33 -5
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_frame.py +1 -16
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_generation.py +43 -27
- commkit-3.6.0/tests/core/test_preamble.py +26 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_psqam.py +21 -8
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_signal.py +84 -23
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_signal_mimo.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_blind.py +7 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_cpr.py +17 -7
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_cs_kernel.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_equalizer_oracles.py +6 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_sequential.py +13 -6
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_state.py +3 -1
- commkit-3.4.0/tests/impairments/channel/test_channel_linear.py → commkit-3.6.0/tests/impairments/test_fiber_channel_linear.py +4 -4
- {commkit-3.4.0 → commkit-3.6.0}/tests/metrics/test_common.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/tests/metrics/test_error_rates.py +26 -20
- {commkit-3.4.0 → commkit-3.6.0}/tests/metrics/test_information.py +4 -2
- {commkit-3.4.0 → commkit-3.6.0}/tests/metrics/test_quality.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_analysis.py +34 -7
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_coding.py +6 -2
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_constellation.py +9 -7
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_equalizer.py +31 -7
- commkit-3.6.0/tests/plotting/test_plot_frequency.py +120 -0
- commkit-3.6.0/tests/plotting/test_plot_recovery.py +159 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_spectral.py +9 -11
- commkit-3.6.0/tests/plotting/test_plot_theme.py +88 -0
- commkit-3.6.0/tests/plotting/test_plot_timing.py +75 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_waveform.py +6 -11
- {commkit-3.4.0 → commkit-3.6.0}/tests/plugins/precision_trace.py +25 -3
- {commkit-3.4.0 → commkit-3.6.0}/tests/plugins/transfer_trace.py +38 -7
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_corrections.py +43 -19
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_pilots.py +23 -18
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_pll.py +30 -18
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_recovery_oracles.py +3 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_api_contracts.py +51 -30
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_dispersion.py +7 -15
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_fiber.py +1 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_filter_response.py +21 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_filtering.py +500 -19
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_frequency.py +30 -24
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_io.py +15 -8
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_pulse_shaping.py +22 -6
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_receiver_chain.py +3 -3
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_signal_pipeline.py +5 -1
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_timing.py +8 -3
- {commkit-3.4.0 → commkit-3.6.0}/uv.lock +1 -1
- commkit-3.4.0/commkit/_dispersion.py +0 -137
- commkit-3.4.0/commkit/equalization/_block/_blind.py +0 -202
- commkit-3.4.0/commkit/equalization/_kernels_numba.py +0 -48
- commkit-3.4.0/commkit/equalization/sequential/__init__.py +0 -19
- commkit-3.4.0/commkit/filtering/fiber.py +0 -211
- commkit-3.4.0/commkit/impairments/channel/__init__.py +0 -24
- commkit-3.4.0/commkit/impairments/channel/nonlinear.py +0 -182
- commkit-3.4.0/commkit/plotting/sync.py +0 -1120
- commkit-3.4.0/examples/19-chromatic-dispersion.ipynb +0 -304
- commkit-3.4.0/tests/plotting/test_plot_sync.py +0 -341
- commkit-3.4.0/tests/plotting/test_plot_theme.py +0 -28
- {commkit-3.4.0 → commkit-3.6.0}/.gitattributes +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/.github/workflows/publish.yml +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/.gitignore +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/.python-version +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/LICENSE +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0002_pre_v2.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0003_v2_0.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0004_fiber_dbp.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0005_gpu_decoder_path.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0006_perf_cleanup.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0007_v3_0.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/baselines/Linux-CPython-3.14-64bit/0008_v3_1.json +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_block_blind.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_block_lms.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_bps.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_coding.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_equalizers.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_filters.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_import.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_llr.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_mapping.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/bench_sync_misc.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/benchutils.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/conftest.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/benchmarks/record_baseline.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_array.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_circular.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_constants.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/__init__.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/compiler.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/graphs.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/algebraic.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/bps_anchor.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/bps_min_d2.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/cs_block.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/iir.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/ldpc.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/llr.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_cuda/src/selftest.cu +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_fft.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_overlap_save.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/_random.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/analysis/allan.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/backend.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/_galois.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/_gf2.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/_ldpc_tables.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/_numba_loops.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/algebraic.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/base.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/convolutional.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/crc.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/interleaving.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/ldpc.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/linear.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/polar.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/ratematch.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/shaping.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/coding/turbo.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/core/_signal_adapter.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/core/signal.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/_block/_engine.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/_common.py +0 -0
- {commkit-3.4.0/commkit/equalization/sequential → commkit-3.6.0/commkit/equalization/_sequential}/_setup.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/pilots.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/equalization/result.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/filtering/linear.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/filtering/pulses.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/impairments/frontend.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/impairments/source.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/io.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/logger.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/__init__.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/_numba_llr.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/bits.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/constellation.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/gray.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/llr.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/mapping/shaping.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/math.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/metrics/__init__.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/metrics/_common.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/metrics/information.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/metrics/quality.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/multirate.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/equalizer.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/eye.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/spectral.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/plotting/waveform.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/py.typed +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/bps.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/tikhonov.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/recovery/viterbi_viterbi.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/smoothing.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/commkit/spectral.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/00-getting-started.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/01-constellations-and-bit-mapping.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/02-spectral-analysis.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/03-digital-filters.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/04-pulse-shaping-and-matched-filtering.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/05-multirate-and-resampling.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/06-awgn-and-performance-metrics.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/09-laser-phase-noise.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/11-frame-synchronization-and-timing.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/13-blind-carrier-phase-recovery.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/15-linear-channel-equalization.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/16-adaptive-equalization.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/examples/17-blind-equalization.ipynb +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_allan.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_fm_noise.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_interferometry.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/analysis/test_trajectory.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_algebraic.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_coding_base.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_convolutional.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_crc.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_exit.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_gf2.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_interleaving.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_ldpc_exit.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_ldpc_kernel.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_ldpc_tables.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_linear_codes.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_performance.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/coding/test_ratematch.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/__init__.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/conversions.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/kernel_utils.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/memory.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/metrics.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/periodic.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/reference_impl.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/scoring.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/common/theory.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/conftest.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/core/test_signal_adapter.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_block.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_bps_kernel.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_linear.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_mimo.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_polarization.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/equalization/test_winit.py +0 -0
- /commkit-3.4.0/tests/impairments/channel/test_channel_nonlinear.py → /commkit-3.6.0/tests/impairments/test_fiber_channel_nonlinear.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/impairments/test_frontend.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/impairments/test_noise.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/impairments/test_source.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/mapping/test_bits.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/mapping/test_constellation.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/mapping/test_gray.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/mapping/test_llr.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_eye.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/plotting/test_plot_filter_response.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/plugins/__init__.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_bps.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_joint.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_tikhonov.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/recovery/test_viterbi_viterbi.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_array.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_backend.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_cuda_infra.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_examples.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_import_hygiene.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_logger.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_math.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_multirate.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_smoothing.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_spectral.py +0 -0
- {commkit-3.4.0 → commkit-3.6.0}/tests/test_working_memory.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="256" viewBox="17 25 256 256" role="img" aria-labelledby="title desc"><title id="title">CommKit symbol</title><desc id="desc">A hexagon containing equal-width rectangular and sine wave cycles. Transparent vector artwork.</desc><defs><linearGradient id="icon-ink" x1="35" y1="40" x2="250" y2="250" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fca50a" /><stop offset=".5" stop-color="#ed6925" /><stop offset="1" stop-color="#b53657" /></linearGradient><mask id="signal-cutout" maskUnits="userSpaceOnUse" x="20" y="20" width="260" height="260"><rect x="20" y="20" width="260" height="260" fill="white" /><path d="M20 193 H64 V113 H118 V193 H145 C154 193 163 173.944 172 153 C181 132.056 190 113 199 113 C208 113 217 132.056 226 153 C235 173.944 244 193 253 193 H275" fill="none" stroke="black" stroke-width="12" stroke-linejoin="round" stroke-linecap="round" /></mask></defs><g id="CommKit-symbol"><path d="M145 28 L253 90 V216 L145 278 L37 216 V90 Z" fill="url(#icon-ink)" mask="url(#signal-cutout)" /></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="1365" height="306" viewBox="0 0 1365 306" role="img" aria-labelledby="title desc"><title id="title">CommKit — digital to waveform</title><desc id="desc">CommKit signal logo. Exactly half of the hexagon width contains one rectangular pulse cycle; the other half contains one smooth sinusoidal cycle of equal amplitude and width. Plain Roboto Black vector wordmark in Inferno amber-to-purple. Transparent background.</desc><defs><linearGradient id="ink" x1="0" y1="0" x2="1257" y2="0" gradientUnits="userSpaceOnUse"><stop offset="0.000" stop-color="#fb9b06" /><stop offset="0.050" stop-color="#fa9207" /><stop offset="0.100" stop-color="#f8890c" /><stop offset="0.150" stop-color="#f68013" /><stop offset="0.200" stop-color="#f37819" /><stop offset="0.250" stop-color="#f06f20" /><stop offset="0.300" stop-color="#eb6628" /><stop offset="0.350" stop-color="#e75e2e" /><stop offset="0.400" stop-color="#e25734" /><stop offset="0.450" stop-color="#dd513a" /><stop offset="0.500" stop-color="#d74b3f" /><stop offset="0.550" stop-color="#d04545" /><stop offset="0.600" stop-color="#ca404a" /><stop offset="0.650" stop-color="#c33b4f" /><stop offset="0.700" stop-color="#bc3754" /><stop offset="0.750" stop-color="#b3325a" /><stop offset="0.800" stop-color="#ab2f5e" /><stop offset="0.850" stop-color="#a32c61" /><stop offset="0.900" stop-color="#9b2964" /><stop offset="0.950" stop-color="#932667" /><stop offset="1.000" stop-color="#8c2369" /></linearGradient><linearGradient id="icon-ink" x1="35" y1="40" x2="250" y2="250" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#fca50a" /><stop offset=".5" stop-color="#ed6925" /><stop offset="1" stop-color="#b53657" /></linearGradient><mask id="signal-cutout" maskUnits="userSpaceOnUse" x="20" y="20" width="260" height="260"><rect x="20" y="20" width="260" height="260" fill="white" /><path d="M20 193 H64 V113 H118 V193 H145 C154 193 163 173.944 172 153 C181 132.056 190 113 199 113 C208 113 217 132.056 226 153 C235 173.944 244 193 253 193 H275" fill="none" stroke="black" stroke-width="12" stroke-linejoin="round" stroke-linecap="round" /></mask></defs><g id="CommKit-symbol"><path d="M145 28 L253 90 V216 L145 278 L37 216 V90 Z" fill="url(#icon-ink)" mask="url(#signal-cutout)" /></g><g id="CommKit-wordmark" transform="translate(255 18) scale(.88)" fill="url(#ink)"><path d="M 120.79102 36.884766 C 107.14268 36.884766 94.7305 39.308148 83.554688 44.154297 C 72.378875 49.000446 62.81114 55.998142 54.849609 65.146484 C 46.888079 74.294827 40.755319 85.371472 36.453125 98.376953 C 32.150931 111.38243 30 125.99508 30 142.21484 L 30 153.93359 C 30 170.15336 32.051859 184.74123 36.15625 197.69727 C 40.260641 210.6533 46.244792 221.6804 54.107422 230.7793 C 61.970051 239.87819 71.562554 246.85112 82.886719 251.69727 C 94.210883 256.54341 107.09366 258.9668 121.5332 258.9668 C 139.33538 258.9668 154.7882 255.77755 167.89258 249.39844 C 180.99696 243.01932 191.25821 234.09361 198.67578 222.62109 C 206.09336 211.14858 210.14754 197.89623 210.83984 182.86328 L 158.91797 182.86328 C 158.72017 190.97316 157.13695 197.6241 154.16992 202.81641 C 151.20289 208.00871 147.0001 211.86474 141.56055 214.38672 C 136.12099 216.90869 129.44528 218.16992 121.5332 218.16992 C 114.41233 218.16992 108.40341 216.95823 103.50781 214.53516 C 98.612213 212.11208 94.632337 208.33035 91.566406 203.1875 C 88.500475 198.04465 86.275239 191.41848 84.890625 183.30859 C 83.506011 175.19871 82.8125 165.40611 82.8125 153.93359 L 82.8125 141.91797 C 82.8125 130.44545 83.580316 120.63004 85.113281 112.4707 C 86.646247 104.31137 88.995324 97.658477 92.160156 92.515625 C 95.324988 87.372773 99.280096 83.615812 104.02734 81.242188 C 108.77459 78.868563 114.36245 77.681641 120.79102 77.681641 C 129.98881 77.681641 137.35803 79.06671 142.89648 81.835938 C 148.43494 84.605166 152.48912 88.733651 155.06055 94.222656 C 157.63197 99.711662 159.01704 106.51121 159.21484 114.62109 L 211.13672 114.62109 C 209.85101 99.687043 205.64822 86.360394 198.52734 74.640625 C 191.40647 62.920857 181.36814 53.697924 168.41211 46.972656 C 155.45608 40.247388 139.58221 36.884766 120.79102 36.884766 z " /><path d="M 298.42773 92.515625 C 285.86731 92.515625 274.79066 94.569437 265.19727 98.673828 C 255.60387 102.77822 247.54309 108.48992 241.01562 115.80859 C 234.48816 123.12727 229.54427 131.75576 226.18164 141.69531 C 222.81901 151.63486 221.13672 162.48859 221.13672 174.25781 L 221.13672 177.37305 C 221.13672 189.04336 222.81901 199.84951 226.18164 209.78906 C 229.54427 219.72861 234.48816 228.38188 241.01562 235.75 C 247.54309 243.11812 255.65341 248.82982 265.3457 252.88477 C 275.038 256.93971 286.16418 258.9668 298.72461 258.9668 C 311.28504 258.9668 322.36168 256.93971 331.95508 252.88477 C 341.54848 248.82982 349.60925 243.11812 356.13672 235.75 C 362.66418 228.38188 367.61002 219.72861 370.97266 209.78906 C 374.33529 199.84951 376.01562 189.04336 376.01562 177.37305 L 376.01562 174.25781 C 376.01563 162.48859 374.33529 151.63486 370.97266 141.69531 C 367.61002 131.75576 362.66418 123.12727 356.13672 115.80859 C 349.60925 108.48992 341.52566 102.77822 331.88281 98.673828 C 322.23997 94.569437 311.08706 92.515625 298.42773 92.515625 z M 298.42773 131.08789 C 303.76839 131.08789 308.21886 132.22528 311.7793 134.5 C 315.33973 136.77472 318.15941 139.91443 320.23633 143.91992 C 322.31325 147.92541 323.79739 152.52449 324.6875 157.7168 C 325.57761 162.9091 326.02148 168.42265 326.02148 174.25781 L 326.02148 177.37305 C 326.02148 183.40601 325.57761 189.0434 324.6875 194.28516 C 323.79739 199.52691 322.31325 204.10122 320.23633 208.00781 C 318.15941 211.9144 315.3645 214.95699 311.85352 217.13281 C 308.34253 219.30863 303.96636 220.39648 298.72461 220.39648 C 293.38396 220.39648 288.93348 219.30863 285.37305 217.13281 C 281.81261 214.95699 278.99489 211.9144 276.91797 208.00781 C 274.84105 204.10122 273.35691 199.52691 272.4668 194.28516 C 271.57669 189.0434 271.13281 183.40601 271.13281 177.37305 L 271.13281 174.25781 C 271.13281 168.42265 271.57669 162.9091 272.4668 157.7168 C 273.35691 152.52449 274.84105 147.92541 276.91797 143.91992 C 278.99489 139.91443 281.78784 136.77472 285.29883 134.5 C 288.80981 132.22528 293.18598 131.08789 298.42773 131.08789 z " /><path d="M 480.36719 92.515625 C 470.27929 92.515625 461.40311 94.445595 453.73828 98.302734 C 446.18903 102.10171 439.82175 107.44341 434.62305 114.3125 L 432.89648 95.484375 L 386.01562 95.484375 L 386.01562 256 L 436.01172 256 L 436.01172 144.32031 C 436.41891 143.62939 436.82378 142.93778 437.27148 142.28906 C 439.69456 138.77808 442.63807 136.03271 446.09961 134.05469 C 449.56114 132.07667 453.46672 131.08789 457.81836 131.08789 C 461.9722 131.08789 465.48343 131.68038 468.35156 132.86719 C 471.21969 134.054 473.42016 136.37831 474.95312 139.83984 C 476.48609 143.30138 477.25195 148.44536 477.25195 155.26953 L 477.25195 256 L 527.24805 256 L 527.24805 148.89062 C 527.24805 147.33464 527.17118 145.87431 527.11719 144.38672 C 527.51571 143.67165 527.91582 142.95911 528.35938 142.28906 C 530.68355 138.77808 533.57753 136.03271 537.03906 134.05469 C 540.5006 132.07667 544.60431 131.08789 549.35156 131.08789 C 553.3076 131.08789 556.71976 131.70514 559.58789 132.94141 C 562.45602 134.17767 564.65649 136.50198 566.18945 139.91406 C 567.72242 143.32615 568.48828 148.34629 568.48828 154.97266 L 568.48828 256 L 618.63281 256 L 618.63281 154.97266 C 618.63281 143.30234 617.39635 133.48692 614.92383 125.52539 C 612.4513 117.56386 608.98961 111.15865 604.53906 106.3125 C 600.08852 101.46635 594.79592 97.955119 588.66406 95.779297 C 582.5322 93.603475 575.80696 92.515625 568.48828 92.515625 C 558.40038 92.515625 549.54897 94.445595 541.93359 98.302734 C 534.31822 102.15987 527.9645 107.59912 522.87109 114.62109 C 522.37627 115.30328 521.90415 116.00736 521.43359 116.71289 C 519.502 112.42475 517.16107 108.70282 514.33984 105.64648 C 510.186 101.14649 505.24212 97.83145 499.50586 95.705078 C 493.7696 93.578707 487.38916 92.515625 480.36719 92.515625 z " /><path d="M 722.98438 92.515625 C 712.89647 92.515625 704.01834 94.445595 696.35352 98.302734 C 688.80426 102.10171 682.43698 107.44341 677.23828 114.3125 L 675.51172 95.484375 L 628.63281 95.484375 L 628.63281 256 L 678.62695 256 L 678.62695 144.32031 C 679.03414 143.62939 679.43901 142.93778 679.88672 142.28906 C 682.30979 138.77808 685.25331 136.03271 688.71484 134.05469 C 692.17638 132.07667 696.08195 131.08789 700.43359 131.08789 C 704.58744 131.08789 708.09867 131.68038 710.9668 132.86719 C 713.83493 134.054 716.03539 136.37831 717.56836 139.83984 C 719.10132 143.30138 719.86719 148.44536 719.86719 155.26953 L 719.86719 256 L 769.86328 256 L 769.86328 148.89062 C 769.86328 147.33464 769.78642 145.87431 769.73242 144.38672 C 770.13095 143.67165 770.53106 142.95911 770.97461 142.28906 C 773.29878 138.77808 776.19276 136.03271 779.6543 134.05469 C 783.11583 132.07667 787.21955 131.08789 791.9668 131.08789 C 795.92284 131.08789 799.335 131.70514 802.20312 132.94141 C 805.07125 134.17767 807.27172 136.50198 808.80469 139.91406 C 810.33765 143.32615 811.10352 148.34629 811.10352 154.97266 L 811.10352 256 L 861.24805 256 L 861.24805 154.97266 C 861.24805 143.30234 860.01159 133.48692 857.53906 125.52539 C 855.06654 117.56386 851.60484 111.15865 847.1543 106.3125 C 842.70375 101.46635 837.41116 97.955119 831.2793 95.779297 C 825.14743 93.603475 818.42219 92.515625 811.10352 92.515625 C 801.01561 92.515625 792.16421 94.445595 784.54883 98.302734 C 776.93345 102.15987 770.57973 107.59912 765.48633 114.62109 C 764.9915 115.30328 764.51939 116.00736 764.04883 116.71289 C 762.11723 112.42475 759.77631 108.70282 756.95508 105.64648 C 752.80124 101.14649 747.85735 97.83145 742.12109 95.705078 C 736.38484 93.578707 730.00635 92.515625 722.98438 92.515625 z " /><path d="M 871.24805 40 L 871.24805 256 L 923.31836 256 L 923.31836 198.98242 L 944.62891 175.66992 L 990.66992 256 L 1052.2363 256 L 979.33594 135.39062 L 1052.2363 40 L 988 40 L 941.41797 107.79688 L 923.31836 135.24609 L 923.31836 40 L 871.24805 40 z " /><path d="M 1089.9785 29.763672 C 1081.7697 29.763672 1075.094 32.038445 1069.9512 36.587891 C 1064.8083 41.137337 1062.2363 46.972878 1062.2363 54.09375 C 1062.2363 61.214622 1064.8083 67.050163 1069.9512 71.599609 C 1075.094 76.149055 1081.7697 78.423828 1089.9785 78.423828 C 1098.1873 78.423828 1104.863 76.149055 1110.0059 71.599609 C 1115.1487 67.050163 1117.7207 61.214622 1117.7207 54.09375 C 1117.7207 46.972878 1115.1487 41.137337 1110.0059 36.587891 C 1104.863 32.038445 1098.1873 29.763672 1089.9785 29.763672 z M 1065.2031 95.484375 L 1065.2031 256 L 1115.3457 256 L 1115.3457 95.484375 L 1065.2031 95.484375 z " /><path d="M 1148.0449 55.576172 L 1148.0449 95.484375 L 1127.7207 95.484375 L 1127.7207 130.19727 L 1148.0449 130.19727 L 1148.0449 209.86328 C 1148.0449 221.4347 1150.0225 230.82906 1153.9785 238.04883 C 1157.9346 245.2686 1163.6958 250.56119 1171.2617 253.92383 C 1178.8276 257.28646 1187.9515 258.9668 1198.6328 258.9668 C 1203.8746 258.9668 1208.8184 258.59527 1213.4668 257.85352 C 1218.1151 257.11176 1222.5656 256.04868 1226.8184 254.66406 L 1226.8184 218.91211 C 1225.137 219.20881 1223.3576 219.43173 1221.4785 219.58008 C 1219.5994 219.72843 1217.2256 219.80273 1214.3574 219.80273 C 1210.3025 219.80273 1207.0637 219.33214 1204.6406 218.39258 C 1202.2176 217.45302 1200.5105 215.82222 1199.5215 213.49805 C 1198.5325 211.17387 1198.0391 207.88556 1198.0391 203.63281 L 1198.0391 130.19727 L 1224.4453 130.19727 L 1224.4453 95.484375 L 1198.0391 95.484375 L 1198.0391 55.576172 L 1148.0449 55.576172 z " /></g></svg>
|
|
@@ -126,7 +126,7 @@ jobs:
|
|
|
126
126
|
- name: Kernel coverage report
|
|
127
127
|
run: >-
|
|
128
128
|
uv run coverage report --show-missing --fail-under=85
|
|
129
|
-
--include="commkit/equalization/
|
|
129
|
+
--include="commkit/equalization/_numba_loops.py,commkit/equalization/_sequential/*,commkit/frequency.py,commkit/recovery/*,commkit/coding/ldpc.py,commkit/coding/shaping.py,commkit/coding/polar.py,commkit/coding/convolutional.py,commkit/coding/turbo.py"
|
|
130
130
|
|
|
131
131
|
# GPU legs (--device=gpu / --device=all) require CuPy + CUDA and are run
|
|
132
132
|
# manually or on a self-hosted runner; they are intentionally not part of
|
|
@@ -37,10 +37,10 @@ uv run pytest --run-slow # also the long statistical validation
|
|
|
37
37
|
uv run pytest tests/equalization/ -k lms # subset
|
|
38
38
|
uv run pytest --cov=commkit # coverage
|
|
39
39
|
uv run pytest --device=cpu -p tests.plugins.precision_trace \
|
|
40
|
-
--ignore=tests/test_examples.py # precision audit (
|
|
40
|
+
--ignore=tests/test_examples.py # precision audit (see Numerics); the suite passes under it
|
|
41
41
|
uv run pytest --device=gpu -p tests.plugins.transfer_trace \
|
|
42
|
-
--ignore=tests/test_examples.py # transfer audit (
|
|
43
|
-
scripts/sanitize.sh # kernels under compute-sanitizer (
|
|
42
|
+
--ignore=tests/test_examples.py # transfer audit (see Performance); fails on an undocumented transfer
|
|
43
|
+
scripts/sanitize.sh # kernels under compute-sanitizer (see Performance); setup in the script
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Numba kernel coverage runs the kernel tests with `NUMBA_DISABLE_JIT=1` and reports only the kernel modules; the test selection and the `--include` list are in the `kernel-coverage` job of `.github/workflows/ci.yml`.
|
|
@@ -61,7 +61,7 @@ uv run pytest benchmarks/ --benchmark-disable --device=all
|
|
|
61
61
|
uv run pytest benchmarks/bench_bps.py --benchmark-only --device=all # timed
|
|
62
62
|
uv run pytest benchmarks/ --benchmark-only --device=all \
|
|
63
63
|
--benchmark-compare=0008 --benchmark-storage=file://benchmarks/baselines
|
|
64
|
-
uv run python benchmarks/record_baseline.py NAME # record a new baseline (
|
|
64
|
+
uv run python benchmarks/record_baseline.py NAME # record a new baseline (see Benchmarks)
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
---
|
|
@@ -80,6 +80,7 @@ Dependencies point downward only:
|
|
|
80
80
|
| Presentation | `plotting` | everything; **nothing imports plotting** (no `debug_plot`: plot functions consume results or recompute through public functions) |
|
|
81
81
|
|
|
82
82
|
- **Responsibilities:** `filtering` holds signal-chain filters with a real frequency response; `smoothing` display and estimation smoothers only; `analysis` laser and phase characterization; `metrics` is the reporting layer.
|
|
83
|
+
- **Plot axes in SI units** are labelled with the base unit in brackets (`Frequency [Hz]`, `Time [s]`) and get `_set_eng_formatter` (`plotting/theme.py`): at each draw it picks one SI prefix from the visible ticks and writes it into the label's unit (`Frequency [GHz]`), with plain numbers on the ticks. Pass data in SI units and never pre-scale it or prefix the label by hand; log axes keep a prefix per tick, as no single one fits decades.
|
|
83
84
|
- **Codes are storable:** `io` stores a code as its class and constructor fields, so those fields are numbers, strings, tuples, host arrays, constellations or other codes.
|
|
84
85
|
- **Splitting modules:** promote a flat module to a package only when it exceeds about 1000 lines *and* has two or more separable concerns. Never create a `utils/` package or one-function files.
|
|
85
86
|
- **One documented home per public name.** A package `__init__` re-exports its subpackages' public names, and users and documentation import them from the package (`commkit.impairments.Fiber`), not from the subpackage that defines them.
|
|
@@ -150,6 +151,8 @@ Dependencies point downward only:
|
|
|
150
151
|
- A size names its unit: `num_symbols`, `num_blocks` (codewords of a FEC code), `info_bits` (a code's information length where it is a parameter), `blocks_per_frame`, `num_variables`, `num_segments`. In `coding`, `length` and `n` mean the codeword length in bits and `k` the information length, nothing else.
|
|
151
152
|
- A seeded part of a factory takes `<part>_rng` (`payload_rng`), with the semantics of `rng`.
|
|
152
153
|
- `method=` strings name only a numerical flavor of one algorithm (`method="maxlog" | "exact"`); algorithms are objects.
|
|
154
|
+
- Output scaling has three names: `normalize` (bool) measures the power and rescales to the library's convention; `correct_power` (bool) applies the exact, known gain of a rate change without measuring; `<thing>_normalization` (a string) chooses how coefficients are scaled (`taps_normalization="unit_energy" | "unity_gain"`).
|
|
155
|
+
- A search window is `search_range`, a `(start, stop)` pair in the axis's unit, or `search_band`, a half-width in Hz around a nominal frequency.
|
|
153
156
|
- Values are in SI units without a suffix (`linewidth` in Hz, `drift_rate` in rad/s, `taus` in s). A result holding one quantity in two units suffixes the SI one (`lags` in samples, `lag_s`). A conventional non-SI unit goes into the name: `_db`, `_dbm`, `_deg`, `_nm`, `_km`, `_ps_nm_km`. Normalized quantities say so (`normalized_bandwidth`). No second name for one quantity in another unit (no `center_frequency_ghz`); `center_wavelength_nm` is a different, derived quantity.
|
|
154
157
|
|
|
155
158
|
### Docstrings
|
|
@@ -158,6 +161,7 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
158
161
|
|
|
159
162
|
- **Summary line** on the line of the opening quotes, one line, ending with a period. Functions: imperative mood (`Apply ...`), or a noun phrase for a function named after what it returns (`evm`, `welch_psd`). Classes and modules: a noun phrase.
|
|
160
163
|
- **Module docstrings** name what the module holds (`:func:`, `:class:`), then the conventions particular to it (a sign convention, a scaling, a file layout). No marketing adjectives, no history of earlier layouts, no restatement of this file. A private module's summary ends with "(private)" and the body names its users.
|
|
164
|
+
- **Sections by role:** functions and the objects users configure (algorithm objects, codes, pulses, `Constellation`, frames, `Signal`) list their arguments under Parameters. Result classes, the frozen dataclasses a function returns (`*Estimate`, `*Result`, `*Curve`, `FilterResponse`, ...), list their fields under Attributes with the stored types, even when users may build one themselves; the summary then says the constructor takes the same fields.
|
|
161
165
|
- **Types:** inputs are `array_like`, or `array_like or Signal` where Signal-aware; returned arrays and fields are `ndarray` (on the input's device), `ndarray or Signal` for transforms, `numpy.ndarray` where always on the host. Shapes go in the description in double backticks: ``(C, N)``.
|
|
162
166
|
- **Plots** return `(fig, ax) or None`, multi-panel plots `(fig, axes) or None` (`None` with `show=True`).
|
|
163
167
|
- **Defaults:** `name : type, default value`; `name : type, optional` when the default is `None`, with the description saying what `None` does.
|
|
@@ -166,10 +170,10 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
166
170
|
### Errors and logging
|
|
167
171
|
|
|
168
172
|
- Wrong input raises, with a message naming the argument.
|
|
169
|
-
- **No fallbacks for a broken environment.** Code never catches a failure of CuPy, a CUDA kernel (compile, load, launch), a graph capture or another dependency to run a different implementation; the failure raises to the caller. A path kept "just in case" is code no test or user runs. (Dispatch on the *input* is allowed; see
|
|
173
|
+
- **No fallbacks for a broken environment.** Code never catches a failure of CuPy, a CUDA kernel (compile, load, launch), a graph capture or another dependency to run a different implementation; the failure raises to the caller. A path kept "just in case" is code no test or user runs. (Dispatch on the *input* is allowed; see the kernel policy in [Performance](#6-performance).)
|
|
170
174
|
- `logger` is for diagnostics only. Per-channel logging that needs a device-to-host transfer is wrapped in `if logger.isEnabledFor(logging.INFO):`.
|
|
171
175
|
- **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 found, the parameters applied, an equalizer's exit MSE, a decoder's failed checks, what `generate` or `io` produced). `WARNING` flags a returned but suspect result (no convergence, a fit outside its valid range, near-zero power, a code with 4-cycles). Value objects and pure helpers do not log.
|
|
172
|
-
- `warnings.warn` is used only for `PrecisionWarning` (
|
|
176
|
+
- `warnings.warn` is used only for `PrecisionWarning` (see [Numerics](#5-numerics)). The library never configures handlers, Matplotlib or warning filters at import time.
|
|
173
177
|
|
|
174
178
|
---
|
|
175
179
|
|
|
@@ -185,7 +189,7 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
185
189
|
- RLS keeps `P`, the gain `k` and the regressor buffers in complex128 (in single precision `P` loses positive definiteness and the filter diverges);
|
|
186
190
|
- LMS/CMA/RDE accumulate dot products and gradient updates in complex128 around complex64 inputs and weights; the block equalizers stay complex64, as their tap sums run inside the FFTs;
|
|
187
191
|
- sums: metrics compute per element in the input's precision and accumulate in float64.
|
|
188
|
-
- complex128 pays only where single-precision rounding accumulates over many FFT passes, as in the fiber solver
|
|
192
|
+
- complex128 pays only where single-precision rounding accumulates over many FFT passes, as in the fiber solver; there the GPU runs its plain CuPy stages, not the fused complex64 kernels.
|
|
189
193
|
- **The NEP 50 trap:** under NumPy 2 a NumPy scalar is not weak, so `np.float64(a) * x64` (any `np.sqrt`, `np.pi * ...` result, or a float64 array such as `xp.fft.fftfreq`) promotes complex64 to complex128. Combine single-precision data only with Python scalars or arrays cast to its precision. Frequency responses (dispersion, delays, Jones matrices) are computed at float64 phase accuracy and cast to the spectrum's precision before the multiply; rotate with `math._derotate`.
|
|
190
194
|
- **Audit with `tests/plugins/precision_trace.py`** after touching numerics. It lists every float64/complex128 array of sample-rate size that a NumPy path creates from single-precision, integer or bool data or from scratch, with its source line; output dtypes alone hide a compute-in-double-and-cast-back. Every reported site must be one of the deliberate uses above.
|
|
191
195
|
- **Normalization invariant:** at `sps` samples per symbol, `E[|x|²] = 1/sps`; at symbol rate, `E[|x|²] = 1`. Any rate-changing block applies the exact gain correction.
|
|
@@ -201,14 +205,14 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
201
205
|
| Sequential recursions: LMS/RLS/CMA/RDE, PLL, Tikhonov, cycle slips, the Mengali-Morelli bootstrap, per-codeword decoders on trellises and trees (CCDM, polar SC/SCL, Viterbi, BCJR, turbo, recursive systematic encoding) | Numba `@njit(cache=True, fastmath=True, nogil=True)`, independent rows in `prange`. The equalizers' kernel with inline carrier recovery compiles strict (unwrap, running sums) and calls fast-math tap and distance loops as separate functions (an `inline="always"` helper takes its caller's flags) | CPU; GPU input does one round trip |
|
|
202
206
|
| Linear recursions: IIR filtering | CPU: Numba without `fastmath`, so double input matches SciPy bit for bit. GPU: `iir` kernel: each block's state from a zero start in parallel, states carried across blocks in two levels (groups, then across groups), blocks filtered again, in double precision | follows the input |
|
|
203
207
|
| Binary linear algebra of codes: encoding, syndromes, ML-decoding correlations on the GPU, Chase's test patterns | one float32 GEMM per chunk (`coding._gf2.matmul_mod2`), exact below an inner dimension of 2^24, parity in place (CPU) or by one elementwise kernel writing int8 (GPU); small tables cached per code and device (`backend._device_tables`) | follows the input |
|
|
204
|
-
| Algebraic decoding (BCH, Reed-Solomon): Berlekamp-Massey, Chien search to the locator's degree, Forney | CPU: Numba `parallel=True` over codewords. GPU: `algebraic_correct`, one thread per codeword in integer table arithmetic, so both agree exactly
|
|
205
|
-
| Layered LDPC belief propagation (min-sum, sum-product) | CPU: Numba `parallel=True` over codewords, all iterations inside, no fast-math. GPU: `ldpc_layered`, one block per codeword, rows of a layer in parallel, early stop per codeword; same row order, so min-sum agrees bit for bit
|
|
206
|
-
| Maximum-likelihood decoding: the correlation with all `2^k` codewords, the decision and the per-bit maxima of the max-log soft output | CPU: one Numba pass, `parallel=True` over rows, branch-free selects under fast-math without the no-NaN and no-Inf flags (a GEMM then a
|
|
208
|
+
| Algebraic decoding (BCH, Reed-Solomon): Berlekamp-Massey, Chien search to the locator's degree, Forney | CPU: Numba `parallel=True` over codewords. GPU: `algebraic_correct`, one thread per codeword in integer table arithmetic, so both agree exactly | follows the input |
|
|
209
|
+
| Layered LDPC belief propagation (min-sum, sum-product) | CPU: Numba `parallel=True` over codewords, all iterations inside, no fast-math. GPU: `ldpc_layered`, one block per codeword, rows of a layer in parallel, early stop per codeword; same row order, so min-sum agrees bit for bit | follows the input |
|
|
210
|
+
| Maximum-likelihood decoding: the correlation with all `2^k` codewords, the decision and the per-bit maxima of the max-log soft output | CPU: one Numba pass, `parallel=True` over rows, branch-free selects under fast-math without the no-NaN and no-Inf flags (not a GEMM then a pass: its threads compete with BLAS's). GPU: the GEMM per chunk, the per-bit maxima by a CuPy `ReductionKernel` that broadcasts over the codewords instead of building `(rows, codewords, n)`. `soft=False` skips the maxima on both | follows the input |
|
|
207
211
|
| Monte Carlo analysis (EXIT curves, error-rate curves) | the existing encoders, decoders and demapper and vectorized NumPy/CuPy, through the private block functions (no INFO line per batch); closed-form parts are host NumPy on small grids. No kernel of its own | follows `device` |
|
|
208
|
-
| Elementwise chains between multi-core FFTs (fiber solver's Kerr and PMD stages) | NumPy: a Numba `parallel=True` pass competes with `scipy.fft`'s threads
|
|
212
|
+
| Elementwise chains between multi-core FFTs (fiber solver's Kerr and PMD stages) | NumPy: a Numba `parallel=True` pass competes with `scipy.fft`'s threads; adopt one only on a paired end-to-end A/B | CPU |
|
|
209
213
|
| Other hot spots limited by intermediates, launches or round trips | CUDA C++ via CuPy `RawModule` (`commkit/_cuda/src`) | GPU |
|
|
210
214
|
|
|
211
|
-
**Numba kernels live at module level** in a private module
|
|
215
|
+
**Numba kernels live at module level** in a private module (`equalization/_numba_loops.py`, `coding/_numba_loops.py`, `mapping/_numba_llr.py`) that a getter `_get_numba_<name>()`, defined in the module that calls the kernel, imports on first use, so `import commkit` does not load Numba and `cache=True` works across processes. A kernel defined inside a function that calls another kernel defined there recompiles in every process (Numba's cache key misses the captured dispatcher); a getter may build a closure that captures only constants (`_get_numba_sos`).
|
|
212
216
|
|
|
213
217
|
**Host-sync hygiene:**
|
|
214
218
|
|
|
@@ -237,7 +241,7 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
237
241
|
|
|
238
242
|
- **Fixtures:** use `backend_device`, `xp` and `xpt` from `tests/conftest.py`. Assert with `xpt.assert_allclose(...)` (`numpy.testing` raises on CuPy arrays); cast expectations with `xp.asarray` and reductions with `float(...)`.
|
|
239
243
|
- **No configuration skips.** The GPU legs skip only when CuPy is not installed, and fail instead under an explicit `--device=gpu`; a broken CuPy fails under any setting. Tests outside the selected run are deselected at collection (`gpu_only`, `cpu_only`, `slow` without `--run-slow`), so a run with CuPy reports no skips. A new test never calls `pytest.skip` for a configuration.
|
|
240
|
-
- **Layout mirrors the source:** `tests/<subpackage>/test_<module>.py`, `tests/test_<module>.py` for flat modules. Basenames are globally unique (prepend import mode)
|
|
244
|
+
- **Layout mirrors the source:** `tests/<subpackage>/test_<module>.py`, `tests/test_<module>.py` for flat modules. Basenames are globally unique (prepend import mode). Split a large file by concern, each part named after its module (`impairments/test_fiber_channel_linear.py`, `test_fiber_channel_nonlinear.py`). Shared builders live in `tests/common/` and use the public API.
|
|
241
245
|
- **Contract registry** (`tests/test_api_contracts.py`): every public function has a row, checked generically for array and Signal in/out, device preserved, input not mutated, keyword-only parameters, `TypeError` on unsupported arrays, fact conflicts and return rules. Do not repeat these checks per module.
|
|
242
246
|
- **Oracles:** sequential kernels are tested against plain-Python references in `tests/common/reference_impl.py`, CUDA kernels against their CPU reference. Kernel tests skip only on the CPU parametrization (`skip_unless_gpu`), so a kernel that fails to compile fails its tests.
|
|
243
247
|
- **Mathematical meaning:** test documented definitions (a pulse width, a dispersion sign, noise-variance scaling) against independently derived expectations, not only shapes and energies.
|
|
@@ -248,83 +252,38 @@ Docstrings describe the code as it is; a change in behavior updates them in the
|
|
|
248
252
|
- **Tolerances are derived** (AWGN theory, a Cramér–Rao bound, a Wiener or loop-noise prediction, a binomial interval), and the docstring states the derivation and the measured value. `tests/common/theory.py` holds the closed forms, in NumPy and SciPy only.
|
|
249
253
|
- **Real channels**: convergence tests use `make_channel_signal` (RRC pulses, ISI, fractional delay, polarization rotation, DGD, AWGN). The repeat-upsampled builders serve plumbing tests only.
|
|
250
254
|
- **Break the code to check the test**: monkeypatch a plausible wrong result (zeros, a factor of two, the feature off) and confirm the test fails.
|
|
251
|
-
- A strengthened test that exposes a library fault is marked `pytest.mark.xfail(strict=True, reason=...)` with the measured numbers
|
|
255
|
+
- A strengthened test that exposes a library fault is marked `pytest.mark.xfail(strict=True, reason=...)` with the measured numbers; the fix lands in its own commit, which removes the mark.
|
|
252
256
|
- **Monte Carlo tests** state what their sample bounds (0 failures in 12 frames bounds the FER below 0.22 at 95 %) and check the operating point (the pre-FEC BER against theory). The default run uses a smoke size; a `slow` parametrization repeats it with enough trials to mean something.
|
|
253
257
|
- **End-to-end chains** in `tests/test_receiver_chain.py` run several impairments and their receiver, scored against the source bits or AWGN theory, each with one correction left out as a failing baseline.
|
|
254
258
|
- **Warnings are failures**: a WARNING from the `commkit` logger fails the test unless it is marked `allow_warnings` (it provokes a suspect result on purpose) or asserts the log through `caplog`. A WARNING that reports what the caller asked for is a log-level bug, fixed in the library.
|
|
255
259
|
- **API changes never change expected values.** A signature change only changes how tests call the code; numerical changes land in their own commit with independent validation.
|
|
256
|
-
- **Examples** are Jupyter notebooks in `examples/`, committed without outputs (the `nbstripout` filter,
|
|
260
|
+
- **Examples** are Jupyter notebooks in `examples/`, committed without outputs (the `nbstripout` filter, see [Commands](#2-commands)). `tests/test_examples.py` executes each one, so an API change updates the notebooks in the same commit.
|
|
257
261
|
- They form a course: one topic per notebook, `NN-lowercase-words.ipynb`, in teaching order (signals and DSP, channel and metrics, coding, receiver algorithms, fiber systems, characterization). Each opens with what it covers and links the notebooks it builds on, and ends with a link to the next. A new notebook takes its place in the order and updates `examples/README.md` and its neighbors' links.
|
|
258
262
|
- Every claim in the text matches what the cells print: run the notebook and read its numbers before committing. Keep each under about 20 s on the CPU.
|
|
259
263
|
- Plots of hand-computed arrays go through `to_device(x, "cpu")`, so the notebooks run unchanged on the GPU.
|
|
260
|
-
- **Coverage** must not drop below the CI floors: 78 % for the package, 85 % for the Numba kernel modules (the `NUMBA_DISABLE_JIT=1` job,
|
|
264
|
+
- **Coverage** must not drop below the CI floors: 78 % for the package, 85 % for the Numba kernel modules (the `NUMBA_DISABLE_JIT=1` job, see [Commands](#2-commands)).
|
|
261
265
|
|
|
262
266
|
---
|
|
263
267
|
|
|
264
268
|
## 8. Benchmarks
|
|
265
269
|
|
|
266
|
-
`benchmarks/` tracks the GPU-relevant hot paths. Baselines are committed under `benchmarks/baselines/`. The reference is `0008` (`v3_1
|
|
270
|
+
`benchmarks/` tracks the GPU-relevant hot paths. Baselines are committed under `benchmarks/baselines/`. The reference is `0008` (`v3_1`) on the reference machine: RTX 4070 Ti, Ryzen 7 7800X3D, WSL2.
|
|
267
271
|
|
|
268
272
|
- **Workloads must converge**, or the benchmark times a failure mode (slip storms, divergence). Every equalizer benchmark asserts its symbol error rate with `benchutils.assert_converged`.
|
|
269
273
|
- **Workloads** come from `benchmarks/workloads.py` with fixed seeds; never generate data inline.
|
|
270
|
-
- **Baselines** are recorded with `benchmarks/record_baseline.py`: each file in its own process, best of `--passes` (default three; raise it when small benchmarks keep outliers
|
|
274
|
+
- **Baselines** are recorded with `benchmarks/record_baseline.py`: each file in its own process, best of `--passes` (default three; raise it when small benchmarks keep outliers). Never record from a single `pytest benchmarks/` run: small GPU benchmarks run after the large equalizer workloads are slowed by them.
|
|
271
275
|
- **IDs** are `[cpu]` or `[gpu]`, meaning the input device.
|
|
272
276
|
- **Timing:** timed bodies end with the `sync` fixture, or GPU timings measure launches. Each benchmark has one warmup round (compilation, pool growth), and a session fixture warms Numba's thread pool before the first.
|
|
273
277
|
- **Tools:** `benchmarks/benchutils.py` provides `CudaEventTimer` and `nvtx_range` for `nsys`. Logging is set to WARNING in `benchmarks/conftest.py`.
|
|
274
|
-
- **Trust deltas, not single runs.**
|
|
278
|
+
- **Trust deltas, not single runs.** Timings swing widely under load. Re-run a suspected regression in isolation, or do a paired A/B of at least 7 repetitions, alternating old and new. When even unchanged benchmarks move, time the changed part with `CudaEventTimer` and quote it against the step it sits in.
|
|
275
279
|
- A commit touching a hot path quotes its delta against `0008`. Tolerance is 5 % on CPU and 10 % on GPU.
|
|
276
280
|
|
|
277
281
|
---
|
|
278
282
|
|
|
279
283
|
## 9. Release
|
|
280
284
|
|
|
281
|
-
1. On `main`: the CPU and GPU suites pass with no failures or skips, slow validation included (`uv run pytest -rs --run-slow`; strict xfails
|
|
285
|
+
1. On `main`: the CPU and GPU suites pass with no failures or skips, slow validation included (`uv run pytest -rs --run-slow`; the only expected failures are strict xfails whose reason names a known fault); `scripts/sanitize.sh` is clean if a kernel changed; `uv build` succeeds and `uv run --with twine twine check dist/*` passes.
|
|
282
286
|
2. `CHANGELOG.md`: a `## [X.Y.Z] - YYYY-MM-DD` section written for users. Changes that may need code updates come first, with how to migrate, then Added, Performance (measured, as a ratio of new to old time), Fixed and Development. Add its compare link at the bottom and commit.
|
|
283
287
|
3. `uv run bump-my-version bump {patch|minor|major}` commits the new version and tags `vX.Y.Z`.
|
|
284
288
|
4. `git push origin main --tags`. The ruleset on `main` requires pull requests; repository admins bypass it for these two commits.
|
|
285
289
|
5. `gh release create vX.Y.Z --title vX.Y.Z --notes-file notes.md` with the changelog section as notes. Publishing the release runs `.github/workflows/publish.yml`, which uploads to PyPI through Trusted Publishing; a pushed tag alone publishes nothing.
|
|
286
|
-
|
|
287
|
-
---
|
|
288
|
-
|
|
289
|
-
## 10. Roadmap and open items
|
|
290
|
-
|
|
291
|
-
What is not done yet, in suggested order. Unlike the sections above, this is a to-do list: remove an item in the commit that resolves it, and add one when a known gap is left open.
|
|
292
|
-
|
|
293
|
-
### Switch to Python 3.15 (blocked)
|
|
294
|
-
|
|
295
|
-
Goal: require Python 3.15 only, mainly for explicit lazy imports (PEP 810). State checked on 2026-10-23 (uv 0.13.5, CPython 3.15.1):
|
|
296
|
-
|
|
297
|
-
- **Blocker: CuPy has no 3.15 wheels.** `cupy-cuda13x` 14.2.0 ships cp310-cp314 only; support is tracked in cupy/cupy#10259, milestone v14.3.0.
|
|
298
|
-
- **Blocker: `jupyter_client` fails to import on 3.15**: `jsonutil.py` calls `strptime` with a day and no year, which 3.15 rejects (cpython#70647), so `tests/test_examples.py` fails at collection. Wait for a fixed release; do not work around it in commkit.
|
|
299
|
-
- **Ready:** wheels on 3.15 exist for NumPy 2.5.4, SciPy 1.18.1, Numba 0.68.0, Matplotlib 3.11.2, mypy 2.4.0 and the dev tools. The CPU suite has not been run on 3.15.
|
|
300
|
-
|
|
301
|
-
Steps, each its own commit (the version switch first, then each refactor):
|
|
302
|
-
|
|
303
|
-
1. **Validate unchanged code** in a 3.15 venv: full CPU+GPU suite with notebooks (`-rs`), benchmark smoke run, kernel-coverage job, precision audit.
|
|
304
|
-
2. **Switch the floor:** `requires-python = ">=3.15"`, classifiers, ruff `target-version`, dependency minimums to the first 3.15 wheels (`cupy-cuda13x[ctk]>=14.3`, `numba>=0.68`, `numpy>=2.5`, `scipy>=1.18`; recheck each); `ci.yml` matrix and jobs and `publish.yml` on 3.15 (keep `locked` and `lowest-direct`); `uv lock`; README and §2. Record a 3.15 baseline, compare it with `0008` by a paired A/B on unchanged code, and make it the reference.
|
|
305
|
-
3. **Lazy imports.** `lazy` is module-level only (not in functions, classes or `try`, not with `*`); confirm on the interpreter.
|
|
306
|
-
- Move the function-local imports (`import cupy as cp`, `import numba`, `from . import compiler` in `_cuda`, cycle-breaking imports of `Constellation`, `Signal`, `normalize`) to `lazy import` / `lazy from`; find them with `grep -rnE '^\s{4,}(import|from) ' commkit`.
|
|
307
|
-
- CuPy stays optional: every use stays behind `is_cupy_available` / `dispatch`; decide per site whether `backend.py`'s probes stay eager inside `try`.
|
|
308
|
-
- Check that a lazy `numba` does not move the import cost to an odd first call, and turn `TYPE_CHECKING` blocks into `lazy from` where the name is useful at run time.
|
|
309
|
-
- Measure with `benchmarks/bench_import.py`; keep `tests/test_import_hygiene.py` passing and extend it to assert that `import commkit` loads neither CuPy nor Matplotlib, if that becomes true.
|
|
310
|
-
4. **Other cleanups** (verify each against What's New in 3.14 and 3.15): drop `from __future__ import annotations` (PEP 649/749; check nothing reads `__annotations__` as strings); check `open()` without `encoding=` under default UTF-8 mode (PEP 686); grep for `strptime` with a day and no year; try the sampling profiler (PEP 799) on the CPU hot paths and mention it in §8 if useful.
|
|
311
|
-
|
|
312
|
-
### Channel coding
|
|
313
|
-
|
|
314
|
-
1. **oFEC** (OpenROADM, ITU-T G.709.3) is not implemented: its block structure is specified in OpenROADM MSA documents that were not available in a form to implement from. It would build on `BCHCode` (extended BCH(256, 239)), soft-output `Chase` and the staircase decoder's windowed iteration.
|
|
315
|
-
2. **NR rate matching for polar codes** (sub-block interleaving, circular buffer, puncturing and shortening with their frozen-set rules, parity-check bits) and **LTE rate matching for turbo codes** are not included: `PolarCode` and `TurboCode` are the mother codes; `Punctured` and `Shortened` cover generic rate matching.
|
|
316
|
-
|
|
317
|
-
### Test suite
|
|
318
|
-
|
|
319
|
-
- **Standard tables against the standards.** The NR polar reliability sequence (TS 38.212 Table 5.3.1.2-1), the LTE QPP interleaver parameters (TS 36.212 Table 5.1.3-3) and the DVB-S2 and PON parity-check address tables are tested against commkit's own tables. They should be compared in full with fixtures under `tests/data/standards/` transcribed from the specifications, each with a provenance header (document, version, table). ETSI's download pages refuse scripted access; the documents have to be supplied.
|
|
320
|
-
|
|
321
|
-
### Nonlinear fiber channel
|
|
322
|
-
|
|
323
|
-
Each is an addition that leaves the current API unchanged.
|
|
324
|
-
|
|
325
|
-
- **Batched realizations**: a leading axis `(B, 2, N)` (launch-power sweeps, Monte Carlo over seeds) so cuFFT batches them and short records fill the GPU.
|
|
326
|
-
- **Adaptive step rules**: a `step_rule=` object (maximum nonlinear phase per step, local-error method) next to the equal `steps_per_span`, which measured 3x more accurate than logarithmic steps on a 32 GBd, 80 km span.
|
|
327
|
-
- **WDM helpers**: combining frequency-shifted channels into one wideband field and selecting one after propagation; the solver already handles the wide field (with `dispersion_slope_ps_nm2_km` set).
|
|
328
|
-
- **Distributed (Raman) amplification and per-span fiber types** in one call (chaining calls already works: every call speaks launch-relative units).
|
|
329
|
-
- **cuFFT callbacks** fusing the linear stage into the transforms (CuPy's support is experimental and compiles with nvcc at run time).
|
|
330
|
-
- **Self-steepening and Raman scattering** for ultra-wideband fields.
|
|
@@ -4,6 +4,72 @@ Notable changes to CommKit, newest first. Performance figures are from the refer
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [3.6.0] - 2026-11-05
|
|
8
|
+
|
|
9
|
+
Chromatic dispersion for real captures. The compensation takes the link's accumulated dispersion and works as a receiver does, an FIR filter (or overlap-save blocks for backpropagation) in bounded memory, with the exact whole-record path as an option that is valid on captures too; three estimators measure an unknown dispersion, blind or from known symbols. The laser-characterization chain and its notebooks were corrected wherever a plot or a number did not mean what it said, method names that were generic now say what they do, and plot axes carry their SI prefix in the label.
|
|
10
|
+
|
|
11
|
+
### Changes that may need code updates
|
|
12
|
+
|
|
13
|
+
- `correct_chromatic_dispersion` takes the link's accumulated dispersion, `dispersion_ps_nm=` (D·L in ps/nm), instead of `dispersion_ps_nm_km=` and `fiber_length_km=`: a receiver knows the total, and only the product enters the physics. Write `dispersion_ps_nm=17 * 80` for 80 km of standard fiber. `dispersion_compensation_taps` takes the same argument.
|
|
14
|
+
- `correct_chromatic_dispersion(method=)` and `correct_fiber_propagation(method=)` choose between two implementations of the same inverse. The default is the receiver's form, in bounded memory on a record of any length: CD by the FIR of `dispersion_compensation_taps` applied by overlap-save (`bandwidth=` and `num_taps=` choose the filter), DBP in overlapping blocks guarded by the link's dispersion memory, all blocks in one batched pass. `method="whole_record"` is the former path, the exact response over the whole record treated as one period; pass it to reproduce earlier results on simulated records. On a capture both are right except within half the dispersion memory of its ends, which no method can recover; `"whole_record"` is the more precise elsewhere, the default suits streams and studies of the filter.
|
|
15
|
+
- Method objects whose names were generic, or named one thing two ways, say what they do: `recovery.ConstantPhase` replaces `DataAided` (every known-symbol method is data-aided; this one fits one constant phase per channel), `recovery.PilotInterpolation` replaces `PilotAided` and `frequency.PilotSlope` replaces `PilotSymbols` (the same pilots, interpolated as a phase or fitted as a slope), `frequency.SpectralPeak` replaces `BiasTone` (the tone `recovery.PilotTone` names too; its mechanism is the spectral peak, the counterpart of `MthPower`), `analysis.DshFmFit` replaces `DshFmPsd` (one word from the result class `DshFmNoisePsd`), and `coding.StageDecoders` replaces `Stages`. Rename at the call; nothing else changes.
|
|
16
|
+
- `commkit.impairments.channel` is `commkit.impairments.fiber_channel`, leaving room for other channel models. Import from `commkit.impairments` and nothing changes.
|
|
17
|
+
- `filter_response` and `plot_filter_response` evaluate complex coefficients over the whole band `[-fs/2, fs/2)` by default, since their response differs at negative frequencies; real coefficients keep the grid from DC to Nyquist. Pass `frequencies=` for the old grid.
|
|
18
|
+
- `BetaSeparation`'s white-FM floor (`linewidth_floor`) is a Whittle fit of white FM, flicker FM and the detection noise's `f²` tail, the model of `DshFmFit`, instead of the median of an auto-detected plateau, and the estimate now carries `flicker`, `angle_noise_var` and `fm_psd_model`. Without a fence the fit runs from the plateau's lower edge to Nyquist. The default segment is the largest power of two within an eighth of the record (it was capped at 4096 samples), so the β-area can resolve the white-FM crossover; pass `nperseg=` for the old segment.
|
|
19
|
+
- Plot axes in SI units carry one SI prefix in the axis label (`Frequency [GHz]`, `Time [ns]`) with plain numbers on the ticks, chosen anew at every draw, so zooming or new limits rescale both; ticks no longer repeat the prefix (`10 G`). Log axes keep a prefix per tick. Limits stay in SI units (`xlim=(0, 2e9)`).
|
|
20
|
+
- `plot_allan_deviation` draws no `τ^(-1/2)` guide by default (`reference_slopes=False`): anchored at the first point, it was meaningless wherever that point is not white-FM limited.
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- `filtering.dispersion_compensation_taps` designs the FIR filter of `correct_chromatic_dispersion`: the least-squares fit of the inverse fiber response over a band (the signal's occupied bandwidth, or the whole sampled band), exact through Fresnel integrals. Its default length is 1.25 times the group-delay spread over the band, which reaches about -45 dB of residual against the frequency-domain compensation; fitting only the occupied band needs about a third of the taps of a fit over the whole band. Notebook 19 shows the taps, their response and the SNR against the length.
|
|
25
|
+
- `filtering.estimate_chromatic_dispersion` with `ClockToneScan` measures a capture's accumulated dispersion blind, before frequency and carrier recovery: Godard's clock-tone spectral correlation, every candidate scanned by one inverse FFT, the estimate the centroid of the peak (a standard deviation of 5 ps/nm at rolloff 0.1 and 1 ps/nm at 0.35 on 2^17 samples at 15 dB; within 62 ps/nm with 10 ps of DGD and a 1 GHz offset). It returns a `ChromaticDispersionEstimate` with the scan, which `correct_chromatic_dispersion(x, estimate)` takes as its `how` (or `correct_chromatic_dispersion(x, ClockToneScan())` to estimate first), and whose value designs the taps to study with `dispersion_compensation_taps(dispersion_ps_nm=estimate.value, ...)`.
|
|
26
|
+
- `estimate_chromatic_dispersion` has two more methods: `FourthMomentScan`, blind and without an excess band (Nyquist pulses), which scores each candidate compensation by the normalized fourth moment of the field (within 11 ps/nm at rolloff 0 and 0.1; about a second on the CPU, 0.05 s on the GPU), and `QuadraticPhaseFit`, data-aided from the Signal's reference or `symbols=`, which fits the quadratic phase of the channel response measured against the known symbols (within 12 ps/nm to ±34000 ps/nm at 6 dB Es/N0, with phase noise and PMD) and returns the measured group delay. `ClockToneScan` warns when the Signal's pulse has a rolloff below 0.05.
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- `BetaSeparation`'s floor read the foot of the AWGN `f²` tail as plateau: 11 % high on the 32 GBd, 1 MHz, 20 dB trajectory of notebook 23 at the default segment (now 0.999 MHz). When the Welch bins cannot resolve the white-FM crossover with the β-line, a warning says so and names the segment needed; the β-area used to return 0 silently.
|
|
31
|
+
- `DshFmPsd` on a real (single-photodiode) beat reports `fm_psd` and `fm_psd_model` as NaN beyond the beat's support, `min(f_shift, f_s/2 - f_shift)`, where the bins read several times low; `valid` marks it. The fit already excluded them.
|
|
32
|
+
- `plot_frequency_noise_psd` draws the fitted model through the same log-binned reduction as a dense PSD (a fringe-resolving DSH model swung at every notch and was drawn as a filled band), keeps the β-line from setting the vertical range, and no longer breaks log-binned curves at empty low-frequency cells. `plot_dsh_beat_psd` zooms on the line, twice the deep width on each side. `plot_carrier_phase_decomposition` labels the total phase next to the drift.
|
|
33
|
+
- The laser-characterization notebooks (23 to 28) report what their plots show: beat-spectrum limits in Hz (they were MHz on a Hz axis, an empty plot), the β-area resolved and explained as the observed width next to the intrinsic floor, the Allan deviation of the unfiltered frequency with its white-PM, white-FM and wander regions, the flicker corner on segments that resolve it, the record-to-record scatter of `DshIncrement` and of the Lorentzian widths, and verdicts in the measurement templates computed from the numbers instead of printed unconditionally.
|
|
34
|
+
- The fiber channel functions document that they treat their record as one period (circular), which the receiver inverts exactly with `method="whole_record"`.
|
|
35
|
+
|
|
36
|
+
### Development
|
|
37
|
+
|
|
38
|
+
- The precision audit caught the clock-tone scan's frequency-shift phasor built in complex128, which promoted the complex64 scan; it is built in the data's precision.
|
|
39
|
+
- The transfer audit lists the dispersion estimators' host-side fits and the data-aided fit's known symbols; CD compensation and block DBP add no transfers.
|
|
40
|
+
- `AGENTS.md` states the plotting convention for SI units (the base unit in the label, the prefix chosen at draw time) and names the fiber-channel test files.
|
|
41
|
+
|
|
42
|
+
## [3.5.0] - 2026-11-05
|
|
43
|
+
|
|
44
|
+
One name per concept, finished. A review of the API and the module layout renamed the arguments and result fields that broke the library's naming rules, split or merged the modules that broke its size rules, and fixed the two audit tools that could pass without checking anything. Numerical results do not change.
|
|
45
|
+
|
|
46
|
+
### Changes that may need code updates
|
|
47
|
+
|
|
48
|
+
Every rename fails loudly with `TypeError` (or `AttributeError` for a field); none changes a result.
|
|
49
|
+
|
|
50
|
+
- `generate` takes `num_symbols` by keyword only, like every other parameter after the constellation: write `generate(c, num_symbols=N, ...)` instead of `generate(c, N, ...)`.
|
|
51
|
+
- `metrics.fer(info_bits=)` replaces `block_length=`, the code's information length as everywhere else in the coding API.
|
|
52
|
+
- Result fields of the laser analyses have descriptive names:
|
|
53
|
+
- `LinewidthEstimate`: `frequencies`, `fm_psd`, `fm_psd_model`, `increment_var`, `delta_phi_var` and `peak_frequency` replace `f`, `S_f`, `S_f_model`, `var`, `dphi_var` and `f_peak`;
|
|
54
|
+
- `DshFmNoisePsd`: `frequencies` and `fm_psd` replace `f` and `S_f`;
|
|
55
|
+
- `FrequencyDrift`: `peak_to_peak` replaces `pp`.
|
|
56
|
+
- `analysis.carrier_phase_trajectory(symbols, ...)` and `equalization.estimate_transfer_function(samples, ...)` rename their first argument (was `y_eq` and `received`); positional calls are unaffected.
|
|
57
|
+
- `recovery.PLL(proportional_gain=, integral_gain=)` replaces `mu=` and `beta=`, the raw loop gains. `normalized_bandwidth` is unchanged.
|
|
58
|
+
- `plotting.plot_error_rate(x_axis="ebn0")` replaces `ebn0=True`, as `plot_psd(x_axis=)` chooses its axis; another value raises `ValueError`.
|
|
59
|
+
- `plot_frequency_drift(reference_amplitude=)` and `plot_carrier_phase_characterization(reference_amplitude=)` replace `amp_ref=`.
|
|
60
|
+
- `plot_constellation` draws no grid.
|
|
61
|
+
- Modules moved; import from the packages as documented and nothing changes. `commkit.impairments.channel` is one module (it was the subpackage `channel.linear` / `channel.nonlinear`); `commkit.plotting.sync` is split into `plotting.timing`, `plotting.frequency` and `plotting.recovery`, and `plot_carrier_phase_decomposition` lives in `plotting.analysis`; `Preamble` is defined in `commkit.core.preamble`; `commkit.equalization.sequential` and `commkit.equalization.blind` are private (`_sequential`, `_block`).
|
|
62
|
+
|
|
63
|
+
### Fixed
|
|
64
|
+
|
|
65
|
+
- `ErrorRateCurve` and `ExitCurve` document their fields under Attributes, as every other result class does.
|
|
66
|
+
|
|
67
|
+
### Development
|
|
68
|
+
|
|
69
|
+
- The transfer audit (`tests/plugins/transfer_trace.py`) failed on 3.4.0 for three legitimate copies it did not list (`SingleCarrierFrame.to_signal`, `extract_payload`, `save_npz`); they are documented now. Both audit plugins found commkit by the path fragment `commkit/commkit/`, so in a checkout of another name (a git worktree) they recorded nothing and passed; they now match the installed package's directory.
|
|
70
|
+
- The Numba kernel getters of the equalizers sit in the modules that call them, as in `coding` and `mapping`, and `_kernels_numba.py` is gone.
|
|
71
|
+
- AGENTS.md holds only the rules for changing the code; it gains glossary entries for output scaling (`normalize`, `correct_power`, `*_normalization`) and search windows (`search_range`, `search_band`), and the rule that result classes document their fields under Attributes. The README carries the new logo.
|
|
72
|
+
|
|
7
73
|
## [3.4.0] - 2026-11-03
|
|
8
74
|
|
|
9
75
|
Error-rate curves for every code, decoders that say what they checked, and one noise convention for real and complex samples.
|
|
@@ -395,7 +461,9 @@ See the [GitHub release](https://github.com/lokgar/commkit/releases/tag/v1.1.0)
|
|
|
395
461
|
|
|
396
462
|
First release. See the [GitHub release](https://github.com/lokgar/commkit/releases/tag/v1.0.0).
|
|
397
463
|
|
|
398
|
-
[Unreleased]: https://github.com/lokgar/commkit/compare/v3.
|
|
464
|
+
[Unreleased]: https://github.com/lokgar/commkit/compare/v3.6.0...HEAD
|
|
465
|
+
[3.6.0]: https://github.com/lokgar/commkit/compare/v3.5.0...v3.6.0
|
|
466
|
+
[3.5.0]: https://github.com/lokgar/commkit/compare/v3.4.0...v3.5.0
|
|
399
467
|
[3.4.0]: https://github.com/lokgar/commkit/compare/v3.3.0...v3.4.0
|
|
400
468
|
[3.3.0]: https://github.com/lokgar/commkit/compare/v3.2.1...v3.3.0
|
|
401
469
|
[3.2.1]: https://github.com/lokgar/commkit/compare/v3.2.0...v3.2.1
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: commkit
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.6.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
|
|
@@ -34,18 +34,18 @@ Provides-Extra: notebook
|
|
|
34
34
|
Requires-Dist: jupyter>=1.1.1; extra == 'notebook'
|
|
35
35
|
Description-Content-Type: text/markdown
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
<p align="center">
|
|
38
|
+
<img src="https://raw.githubusercontent.com/lokgar/commkit/main/.github/logo.svg" alt="CommKit" width="520">
|
|
39
|
+
</p>
|
|
38
40
|
|
|
39
|
-
|
|
41
|
+
<p align="center">Digital communications research kit for Python with CUDA acceleration.</p>
|
|
40
42
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
---
|
|
43
|
+
<p align="center">
|
|
44
|
+
<img src="https://img.shields.io/badge/python-3.12%2B-blue" alt="Python 3.12+">
|
|
45
|
+
<img src="https://img.shields.io/badge/backend-NumPy%20%7C%20CuPy-orange" alt="Backends">
|
|
46
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
|
47
|
+
<img src="https://img.shields.io/badge/CUDA-13.x-76B900?logo=nvidia" alt="CUDA">
|
|
48
|
+
</p>
|
|
49
49
|
|
|
50
50
|
## The model
|
|
51
51
|
|
|
@@ -147,8 +147,8 @@ CommKit never picks a device for you: data stays where you put it, and each func
|
|
|
147
147
|
| [`commkit.spectral`](https://github.com/lokgar/commkit/blob/main/commkit/spectral.py) | Welch PSD, spectrograms, frequency shifting, pilot tones. |
|
|
148
148
|
| [`commkit.impairments`](https://github.com/lokgar/commkit/tree/main/commkit/impairments) | AWGN at an Es/N0 (measured as energy per symbol) or of an absolute variance, ASE at an OSNR (`apply_ase`), phase noise, IQ imbalance (blind estimate; Löwdin and Gram-Schmidt correction), chromatic dispersion, PMD and polarization mixing, and nonlinear fiber propagation over amplified spans (split-step Kerr effect with dispersion, loss, PMD and ASE) of a `Fiber`. |
|
|
149
149
|
| [`commkit.timing`](https://github.com/lokgar/commkit/blob/main/commkit/timing.py) | Barker and Zadoff-Chu sequences, `estimate_timing` / `correct_timing`, fractional delay estimation and correction. |
|
|
150
|
-
| [`commkit.frequency`](https://github.com/lokgar/commkit/blob/main/commkit/frequency.py) | `estimate_frequency_offset` / `correct_frequency_offset` with `MthPower`, `MengaliMorelli`, `
|
|
151
|
-
| [`commkit.recovery`](https://github.com/lokgar/commkit/tree/main/commkit/recovery) | `estimate_carrier_phase` / `correct_carrier_phase` with `ViterbiViterbi`, `BPS`, `PLL`, `Tikhonov`, `
|
|
150
|
+
| [`commkit.frequency`](https://github.com/lokgar/commkit/blob/main/commkit/frequency.py) | `estimate_frequency_offset` / `correct_frequency_offset` with `MthPower`, `MengaliMorelli`, `PilotSlope` and `SpectralPeak`; static and blockwise. |
|
|
151
|
+
| [`commkit.recovery`](https://github.com/lokgar/commkit/tree/main/commkit/recovery) | `estimate_carrier_phase` / `correct_carrier_phase` with `ViterbiViterbi`, `BPS`, `PLL`, `Tikhonov`, `ConstantPhase`, `PilotInterpolation`, `PilotTone(s)`; cycle-slip correction; `resolve_phase_ambiguity` and `resolve_channel_permutation`. |
|
|
152
152
|
| [`commkit.equalization`](https://github.com/lokgar/commkit/tree/main/commkit/equalization) | Sequential `lms`, `rls`, `cma`, `rde` (Numba) and frequency-domain `block_lms`, `block_cma`, `block_rde` (CuPy, CUDA graphs), butterfly MIMO, inline carrier recovery (`cpr=PLL()` / `BPS()`), continuation with `state=`, `zf_equalizer`; pilot-aided CMA and RDE from a frame's pilots (`EqualizerPilots`); polarization demultiplexing on pilot tones (`estimate_polarization_tones` / `correct_polarization`). |
|
|
153
153
|
| [`commkit.metrics`](https://github.com/lokgar/commkit/blob/main/commkit/metrics.py) | `evm`, `snr`, `ber`, `fer`, `ser`, `gmi`, `ngmi`, `mi`, including shaped constellations; pre-FEC and post-FEC (`ber(decoded, sig)`); `estimate_noise_variance` for LLRs; host values per channel. |
|
|
154
154
|
| [`commkit.analysis`](https://github.com/lokgar/commkit/tree/main/commkit/analysis) | Laser and carrier-phase characterization: `estimate_linewidth` (increment slope, β-separation, delayed self-heterodyne FM-PSD / increment / Lorentzian), FM-noise PSDs, drift separation, Allan deviation. |
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/lokgar/commkit/main/.github/logo.svg" alt="CommKit" width="520">
|
|
3
|
+
</p>
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<p align="center">Digital communications research kit for Python with CUDA acceleration.</p>
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
---
|
|
7
|
+
<p align="center">
|
|
8
|
+
<img src="https://img.shields.io/badge/python-3.12%2B-blue" alt="Python 3.12+">
|
|
9
|
+
<img src="https://img.shields.io/badge/backend-NumPy%20%7C%20CuPy-orange" alt="Backends">
|
|
10
|
+
<img src="https://img.shields.io/badge/license-MIT-green" alt="License">
|
|
11
|
+
<img src="https://img.shields.io/badge/CUDA-13.x-76B900?logo=nvidia" alt="CUDA">
|
|
12
|
+
</p>
|
|
13
13
|
|
|
14
14
|
## The model
|
|
15
15
|
|
|
@@ -111,8 +111,8 @@ CommKit never picks a device for you: data stays where you put it, and each func
|
|
|
111
111
|
| [`commkit.spectral`](https://github.com/lokgar/commkit/blob/main/commkit/spectral.py) | Welch PSD, spectrograms, frequency shifting, pilot tones. |
|
|
112
112
|
| [`commkit.impairments`](https://github.com/lokgar/commkit/tree/main/commkit/impairments) | AWGN at an Es/N0 (measured as energy per symbol) or of an absolute variance, ASE at an OSNR (`apply_ase`), phase noise, IQ imbalance (blind estimate; Löwdin and Gram-Schmidt correction), chromatic dispersion, PMD and polarization mixing, and nonlinear fiber propagation over amplified spans (split-step Kerr effect with dispersion, loss, PMD and ASE) of a `Fiber`. |
|
|
113
113
|
| [`commkit.timing`](https://github.com/lokgar/commkit/blob/main/commkit/timing.py) | Barker and Zadoff-Chu sequences, `estimate_timing` / `correct_timing`, fractional delay estimation and correction. |
|
|
114
|
-
| [`commkit.frequency`](https://github.com/lokgar/commkit/blob/main/commkit/frequency.py) | `estimate_frequency_offset` / `correct_frequency_offset` with `MthPower`, `MengaliMorelli`, `
|
|
115
|
-
| [`commkit.recovery`](https://github.com/lokgar/commkit/tree/main/commkit/recovery) | `estimate_carrier_phase` / `correct_carrier_phase` with `ViterbiViterbi`, `BPS`, `PLL`, `Tikhonov`, `
|
|
114
|
+
| [`commkit.frequency`](https://github.com/lokgar/commkit/blob/main/commkit/frequency.py) | `estimate_frequency_offset` / `correct_frequency_offset` with `MthPower`, `MengaliMorelli`, `PilotSlope` and `SpectralPeak`; static and blockwise. |
|
|
115
|
+
| [`commkit.recovery`](https://github.com/lokgar/commkit/tree/main/commkit/recovery) | `estimate_carrier_phase` / `correct_carrier_phase` with `ViterbiViterbi`, `BPS`, `PLL`, `Tikhonov`, `ConstantPhase`, `PilotInterpolation`, `PilotTone(s)`; cycle-slip correction; `resolve_phase_ambiguity` and `resolve_channel_permutation`. |
|
|
116
116
|
| [`commkit.equalization`](https://github.com/lokgar/commkit/tree/main/commkit/equalization) | Sequential `lms`, `rls`, `cma`, `rde` (Numba) and frequency-domain `block_lms`, `block_cma`, `block_rde` (CuPy, CUDA graphs), butterfly MIMO, inline carrier recovery (`cpr=PLL()` / `BPS()`), continuation with `state=`, `zf_equalizer`; pilot-aided CMA and RDE from a frame's pilots (`EqualizerPilots`); polarization demultiplexing on pilot tones (`estimate_polarization_tones` / `correct_polarization`). |
|
|
117
117
|
| [`commkit.metrics`](https://github.com/lokgar/commkit/blob/main/commkit/metrics.py) | `evm`, `snr`, `ber`, `fer`, `ser`, `gmi`, `ngmi`, `mi`, including shaped constellations; pre-FEC and post-FEC (`ber(decoded, sig)`); `estimate_noise_variance` for LLRs; host values per channel. |
|
|
118
118
|
| [`commkit.analysis`](https://github.com/lokgar/commkit/tree/main/commkit/analysis) | Laser and carrier-phase characterization: `estimate_linewidth` (increment slope, β-separation, delayed self-heterodyne FM-PSD / increment / Lorentzian), FM-noise PSDs, drift separation, Allan deviation. |
|
|
@@ -54,11 +54,28 @@ def bench_fiber_propagation(benchmark, backend_device, xp, sync, monkeypatch, n,
|
|
|
54
54
|
@pytest.mark.parametrize("path", PATHS)
|
|
55
55
|
@pytest.mark.parametrize("steps", [1, 10])
|
|
56
56
|
def bench_dbp(benchmark, backend_device, xp, sync, monkeypatch, steps, path):
|
|
57
|
+
"""The whole record (``method="whole_record"``), as the 0008 baseline measured."""
|
|
57
58
|
_stages(backend_device, monkeypatch, path)
|
|
58
59
|
x = xp.asarray(fiber_workload(2**20))
|
|
59
60
|
|
|
60
61
|
def run():
|
|
61
|
-
out = correct_fiber_propagation(
|
|
62
|
+
out = correct_fiber_propagation(
|
|
63
|
+
x, steps_per_span=steps, method="whole_record", **LINK
|
|
64
|
+
)
|
|
65
|
+
sync()
|
|
66
|
+
return out
|
|
67
|
+
|
|
68
|
+
benchmark.pedantic(run, **ROUNDS)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
@pytest.mark.parametrize("path", PATHS)
|
|
72
|
+
def bench_dbp_blocks(benchmark, backend_device, xp, sync, monkeypatch, path):
|
|
73
|
+
"""A capture: overlap-save blocks, ten steps per span."""
|
|
74
|
+
_stages(backend_device, monkeypatch, path)
|
|
75
|
+
x = xp.asarray(fiber_workload(2**20))
|
|
76
|
+
|
|
77
|
+
def run():
|
|
78
|
+
out = correct_fiber_propagation(x, steps_per_span=10, **LINK)
|
|
62
79
|
sync()
|
|
63
80
|
return out
|
|
64
81
|
|
|
@@ -126,7 +126,7 @@ def fiber_workload(n_samples: int, seed: int = 0) -> np.ndarray:
|
|
|
126
126
|
|
|
127
127
|
sig = generate(
|
|
128
128
|
Constellation.qam(16),
|
|
129
|
-
n_samples // 2,
|
|
129
|
+
num_symbols=n_samples // 2,
|
|
130
130
|
symbol_rate=32e9,
|
|
131
131
|
sps=2,
|
|
132
132
|
pulse=RRC(0.1),
|
|
@@ -162,7 +162,9 @@ def coded_workload(code, num_codewords: int, esn0_db: float, seed: int = 0):
|
|
|
162
162
|
from commkit.mapping import compute_llr
|
|
163
163
|
|
|
164
164
|
c = Constellation.qam(4)
|
|
165
|
-
sig = generate(
|
|
165
|
+
sig = generate(
|
|
166
|
+
c, num_symbols=num_codewords * code.n // 2, symbol_rate=FS, code=code, rng=seed
|
|
167
|
+
)
|
|
166
168
|
rx = apply_awgn(sig, esn0_db=esn0_db, rng=seed + 1)
|
|
167
169
|
llrs = compute_llr(rx, noise_var=10 ** (-esn0_db / 10))
|
|
168
170
|
return np.asarray(llrs, dtype=np.float32), sig.reference.info_bits
|