Skip to main content

pyPhyNR

Python tools for NR resource grids, PDSCH/DMRS and complex OFDM waveform generation.

Version 0.3.0 adds 1024-QAM modulation and bundled example notebooks. Select modulation="QAM1024" in add_pdsch() to use 1024-QAM. Supported PDSCH modulations are QPSK, QAM16, QAM64, QAM256 and QAM1024. 1024-QAM maps 10 bits per symbol using TS 38.211 section 5.1.7, normalized by sqrt(682) for unit average constellation power.

Version 0.2.0 adds composite waveform generation, relative carrier gains and optional equal average PSD. Carrier RB counts are selected from bandwidth and numerology; FFT size is derived from sampling rate divided by subcarrier spacing.

Installation

python -m pip install --upgrade pyPhyNR

Python 3.9 or later is required. Runtime dependencies are NumPy, SciPy and Matplotlib. Starting with 0.3.0, example notebooks are bundled with the installed package. The notebooks extra also installs Jupyter dependencies. Copy the examples into a working folder and open them with:

python -m pip install "pyPhyNR[notebooks]"
python -m pyPhyNR.examples
jupyter lab pyphynr-examples

Use python -m pyPhyNR.examples my-folder to choose a destination. Existing files are kept, so running the command again preserves your edits. Select a Python kernel with pyPhyNR installed. For 0.2.0, download notebooks from its source distribution on PyPI or from this repository.

For a source checkout, use python -m pip install -e ".[notebooks]" from the repository root.

Single carrier

import pyPhyNR as pynr

signal = pynr.NRSignalBuilder(bandwidth_mhz=100, numerology=1, cell_id=1)
signal.configure_carrier(sample_rate=245.76e6).initialize_grid()
signal.add_pdsch(
    start_rb=0,
    num_rb=signal.carrier_config.n_resource_blocks,
    start_symbol=0,
    num_symbols=14,
    slot_pattern=list(range(signal.carrier_config.numerology.slots_per_frame)),
    modulation="QAM256",
).add_dmrs(dmrs_positions=[2, 11], clear_full_symbol=False)

iq = signal.generate_signal(target_rms=1.0)
pynr.utils.plot_frequency_domain(iq, signal.carrier_config)

Numerology 0 selects 15 kHz SCS and numerology 1 selects 30 kHz. For the example above, the carrier has 273 RBs and an 8192-point FFT. PDSCH can fill the carrier using its derived RB count, or occupy a smaller allocation using an explicit count.

Composite waveform

Populate a second carrier independently, then combine the two resource grids:

second = pynr.NRSignalBuilder(bandwidth_mhz=100, numerology=1, cell_id=2)
second.configure_carrier(sample_rate=245.76e6).initialize_grid()
second.add_pdsch(
    start_rb=0,
    num_rb=second.carrier_config.n_resource_blocks,
    start_symbol=0,
    num_symbols=14,
    slot_pattern=list(range(second.carrier_config.numerology.slots_per_frame)),
    modulation="QAM256",
).add_dmrs(dmrs_positions=[2, 11], clear_full_symbol=False)

composite = pynr.NRCompositeSignalBuilder(sample_rate=245.76e6, equal_psd=True)
composite.add_carrier(signal, frequency_offset_hz=-50e6)
composite.add_carrier(second, frequency_offset_hz=50e6, gain_db=0.0)
iq = composite.generate_signal(target_rms=1.0)
pynr.utils.plot_frequency_domain(iq, composite)

Frequency offsets are relative to output DC. gain_db=-3 lowers a carrier by 3 dB. equal_psd=True sets each carrier's average power in proportion to its allocated bandwidth; use it for mixed bandwidths such as NR100 + NR10 + NR5. Leave per-carrier target_rms unset in this mode. The final target_rms sets the composite RMS while preserving relative carrier powers. IQ amplitudes are not clipped.

Composite generation supports a common 15 or 30 kHz SCS, normal CP and one 10 ms frame. Carriers are synthesized directly at the output sampling rate without changing their input configurations. Overlapping allocations and carriers outside the output Nyquist interval are rejected. Equal PSD refers to average power per allocated Hz; differently loaded or bursty grids can have different active-symbol PSD.

Examples

  • Two adjacent NR100 carriers: notebooks/nr_2x100mhz_composite.ipynb
  • Mixed NR100 + NR10 + NR5: notebooks/nr100_nr10_nr5_composite.ipynb
  • Single-carrier 64-QAM: notebooks/nr20m_64qam_test.ipynb
  • Single-carrier 256-QAM: notebooks/nr20m_256qam_test.ipynb
  • Single-carrier 1024-QAM: notebooks/nr20m_1024qam_test.ipynb
  • TDD waveform: notebooks/nr20m_tdd_udc38_test.ipynb

Notebooks use the installed library and its plotting helpers. Optional TXT export uses NumPy. Copy the bundled notebooks with python -m pyPhyNR.examples, download the source distribution from PyPI, or use this repository; generated IQ files and saved notebook outputs are excluded from the release.

Compatibility notes for 0.2.0

The existing pynr.NRSignalBuilder and pyPhyNR.core imports remain available. Omit fft_size for automatic selection, including non-power-of-two FFTs such as 1920 at 57.6 Msps / 30 kHz. An explicit FFT size must equal sampling rate / SCS; inconsistent values now raise an error instead of changing the waveform's SCS. Notebook tools are an optional dependency via the notebooks extra. The historical matlab_to_python_nr_gen helpers remain available for compatibility; new examples use NRSignalBuilder.

This is an experimental signal-generation library, not a complete encoded NR link or an RF conformance certification tool. RF band/raster compatibility and other physical channels remain outside the composite generator's scope.

Build and release

python -m pip install ".[dev]"
python -m build
python -m twine check dist/*
python -m twine upload --repository-url https://upload.pypi.org/legacy/ dist/*

Use a PyPI API token through Twine's supported credential configuration.

License

MIT. Copyright kir812.

Metadata

Release files for pyPhyNR 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pyPhyNR 0.3.0
File Size Uploaded Provenance
pyphynr-0.3.0.tar.gz 43.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for pyPhyNR 0.3.0
File Interpreter ABI Platform
pyphynr-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 104.4 kB

Release files / pyphynr-0.3.0.tar.gz

Download URL pyphynr-0.3.0.tar.gz
Size 43.6 kB
Tags Source
SHA-256 checksum
How to use checksums
29aaa919c71841b981bd960491f0cb9d34eab8e2e5e356f30365480ac4432010
BLAKE2b-256 checksum
How to use checksums
ba3da9781994f6b2289cdf19fa34f3dd4afeed14ba5d139b10d82a2dd5898c73
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.5

Release files / pyphynr-0.3.0-py3-none-any.whl

Download URL pyphynr-0.3.0-py3-none-any.whl
Size 60.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
19cf52675db3e2bc0dd3a3ca2e82a99523e1b5c34fa5ca6cb6b4a5a3d34b7a1b
BLAKE2b-256 checksum
How to use checksums
ec9139dcdd03010f9ab7df5e184f1adccb142a1204ae1e3e8b229feb0609cac7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.11.5

Security for pyPhyNR 0.3.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page