PyPNM Python API - PNM Parser Usage Examples¶
This guide shows how to use the PyPNM binary parsers directly from Python and via the example CLI scripts under:
src/pypnm/examples/python/parsers/
All examples assume:
- You are in the project root:
~/Projects/PyPNM - Test fixtures are available in:
tests/files/ - Your virtual environment is active.
Table Of Contents¶
- 3.1 Downstream OFDM RxMER
- 3.2 Downstream OFDM Channel Estimation
- 3.3 Downstream OFDM FEC Summary
- 3.4 Downstream OFDM Modulation Profile
Upstream OFDMA Pre-Equalization Parsers
Programming Patterns And Integration Notes
Overview¶
The examples in this directory exercise the binary parsers that turn raw PNM capture files into typed Pydantic models. Each parser focuses on a specific DOCSIS PNM payload.
Representative parser classes:
CmDsOfdmRxMerCmDsOfdmChanEstimateCoefCmDsOfdmFecSummaryCmDsOfdmModulationProfileCmSpectrumAnalysisCmSpectrumAnalysisSnmpCmUsOfdmaPreEq
Each example script loads a test capture from tests/files/, parses it into the appropriate
model, and prints model_dump_json(indent=2) to stdout.
The example scripts live here:
src/pypnm/examples/python/parsers/pnm-ds-rxmer.pysrc/pypnm/examples/python/parsers/pnm-ds-chan-est-coeff.pysrc/pypnm/examples/python/parsers/pnm-ds-fec-summary.pysrc/pypnm/examples/python/parsers/pnm-ds-modulation-profile.pysrc/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis.pysrc/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis-snmp.pysrc/pypnm/examples/python/parsers/pnm-us-ofdma-preeq.pysrc/pypnm/examples/python/parsers/pnm-us-ofdma-preeq-last-update.py
Common Parser API Pattern¶
All parser classes follow the same basic pattern:
- Constructor accepts a
bytespayload. - Internal parsing/validation happens in
__init__. - Results are exposed via:
| Method | Return Type | Description |
|---|---|---|
to_model() |
Typed Pydantic model (*Model) |
Return the fully validated PNM model. |
to_dict() |
dict[str, Any] |
Convenience wrapper for model_dump(). |
to_json() |
str |
Convenience wrapper for model_dump_json(indent=...). |
Typical usage:
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmDsOfdmRxMer import CmDsOfdmRxMer, CmDsOfdmRxMerModel
pfile = Path("tests/files/rxmer.bin")
raw_payload: bytes = FileProcessor(pfile).read_file()
parser = CmDsOfdmRxMer(raw_payload)
model: CmDsOfdmRxMerModel = parser.to_model()
print(model.model_dump_json(indent=2))
The example CLI scripts only wrap this pattern in a main() function and hard-code the
input path to the test fixture.
Downstream OFDM Parsers¶
3.1 Downstream OFDM RxMER - pnm-ds-rxmer.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-rxmer.py
Parser:
Input PNM file:
tests/files/rxmer.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-rxmer.py
The script will:
- Read
tests/files/rxmer.bin. - Decode it with
CmDsOfdmRxMer. - Print the
CmDsOfdmRxMerModelas prettified JSON.
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmDsOfdmRxMer import CmDsOfdmRxMer, CmDsOfdmRxMerModel
pfile = Path("tests/files/rxmer.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmDsOfdmRxMer(raw_payload)
rxmer_model: CmDsOfdmRxMerModel = parser.to_model()
subcarrier_mer = rxmer_model.rxmer_values # example field name
print(f"Number of subcarriers: {len(subcarrier_mer)}")
You can feed rxmer_model into downstream analysis functions (for example, RxMER statistics
or profile-aligned plots).
3.2 Downstream OFDM Channel Estimation - pnm-ds-chan-est-coeff.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-chan-est-coeff.py
Parser:
Input fixture:
tests/files/channel_estimation.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-chan-est-coeff.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmDsOfdmChanEstimateCoef import (
CmDsOfdmChanEstimateCoef,
CmDsOfdmChanEstimateCoefModel,
)
pfile = Path("tests/files/channel_estimation.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmDsOfdmChanEstimateCoef(raw_payload)
chan_est_model: CmDsOfdmChanEstimateCoefModel = parser.to_model()
tap_values = chan_est_model.values
print(f"Total taps: {len(tap_values)}")
Channel estimation taps can be used as input to echo detection, group delay analysis, or other RF impairment tools.
3.3 Downstream OFDM FEC Summary - pnm-ds-fec-summary.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-fec-summary.py
Parser:
Input fixture:
tests/files/fec_summary.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-fec-summary.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmDsOfdmFecSummary import CmDsOfdmFecSummary, CmDsOfdmFecSummaryModel
pfile = Path("tests/files/fec_summary.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmDsOfdmFecSummary(raw_payload)
fec_model: CmDsOfdmFecSummaryModel = parser.to_model()
print(f"Total codewords: {fec_model.total_codewords}")
print(f"Corrected codewords: {fec_model.corrected_codewords}")
print(f"Uncorrectable codewords: {fec_model.uncorrectable_codewords}")
3.4 Downstream OFDM Modulation Profile - pnm-ds-modulation-profile.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-modulation-profile.py
Parser:
Input fixture:
tests/files/modulation_profile.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-modulation-profile.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmDsOfdmModulationProfile import CmDsOfdmModulationProfile
from pypnm.pnm.parser.model.parser_rtn_models import CmDsOfdmModulationProfileModel
pfile = Path("tests/files/modulation_profile.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmDsOfdmModulationProfile(raw_payload)
profile_model: CmDsOfdmModulationProfileModel = parser.to_model()
for profile in profile_model.modulation_profiles:
print(f"Profile ID: {profile.profile_id}, Modulation: {profile.modulation_order}")
Modulation profiles can be correlated with RxMER and FEC statistics to understand how modulation is allocated across the OFDM channel.
Spectrum Analysis Parsers¶
4.1 PNM Spectrum Analyzer - pnm-ds-spectrum-analysis.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis.py
Parser:
Input fixture:
tests/files/spectrum_analyzer.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmSpectrumAnalysis import CmSpectrumAnalysis, CmSpectrumAnalyzerModel
pfile = Path("tests/files/spectrum_analyzer.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmSpectrumAnalysis(raw_payload)
spec_model: CmSpectrumAnalyzerModel = parser.to_model()
print(f"Bins per segment: {spec_model.num_bins_per_segment}")
print(f"Number of segments: {len(spec_model.amplitude_bin_segments_float)}")
You can feed spec_model.amplitude_bin_segments_float into plotting utilities to visualize
per-segment spectra or stitch them into a full-band sweep.
4.2 SNMP Spectrum Analyzer (AmplitudeData) - pnm-ds-spectrum-analysis-snmp.py¶
Script:
src/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis-snmp.py
Parser:
Input fixture:
tests/files/spectrum_analyzer_snmp.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-ds-spectrum-analysis-snmp.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmSpectrumAnalysisSnmp import (
CmSpectrumAnalysisSnmp,
CmSpectrumAnalysisSnmpModel,
)
pfile = Path("tests/files/spectrum_analyzer_snmp.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmSpectrumAnalysisSnmp(raw_payload)
snmp_spec_model: CmSpectrumAnalysisSnmpModel = parser.to_model()
print(f"Total samples: {snmp_spec_model.total_samples}")
print(f"Start frequency: {snmp_spec_model.spectrum_config.start_frequency} Hz")
print(f"End frequency: {snmp_spec_model.spectrum_config.end_frequency} Hz")
The SNMP version is especially useful when the CM only exposes sweep data via the
docsIf3CmSpectrumAnalysisMeasAmplitudeData object.
Upstream OFDMA Pre-Equalization Parsers¶
5.1 Upstream OFDMA Pre-Equalization - pnm-us-ofdma-preeq.py¶
Script:
src/pypnm/examples/python/parsers/pnm-us-ofdma-preeq.py
Parser:
Input fixture:
tests/files/us_pre_equalizer_coef.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-us-ofdma-preeq.py
Programmatic Usage¶
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmUsOfdmaPreEq import CmUsOfdmaPreEq, CmUsOfdmaPreEqModel
pfile = Path("tests/files/us_pre_equalizer_coef.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmUsOfdmaPreEq(raw_payload)
preeq_model: CmUsOfdmaPreEqModel = parser.to_model()
print(f"Channel ID: {preeq_model.channel_id}")
print(f"Tap count: {len(preeq_model.values)}")
Upstream pre-equalization coefficients are the foundation for group delay, echo detection, and upstream impairment analysis.
5.2 Upstream OFDMA Pre-Equalization Last Update - pnm-us-ofdma-preeq-last-update.py¶
Script:
src/pypnm/examples/python/parsers/pnm-us-ofdma-preeq-last-update.py
Parser:
- Same parser class
CmUsOfdmaPreEq, but operating on theUPSTREAM_PRE_EQUALIZER_COEFFICIENTS_LAST_UPDATEPNM file type.
Input fixture:
tests/files/us_pre_equalizer_coef_last.bin
CLI Usage¶
cd ~/Projects/PyPNM
python3 src/pypnm/examples/python/parsers/pnm-us-ofdma-preeq-last-update.py
Programmatic Usage¶
The usage is identical to the full pre-equalizer capture; only the input file and underlying PNM file type differ.
from pathlib import Path
from pypnm.lib.file_processor import FileProcessor
from pypnm.pnm.parser.CmUsOfdmaPreEq import CmUsOfdmaPreEq, CmUsOfdmaPreEqModel
pfile = Path("tests/files/us_pre_equalizer_coef_last.bin")
raw_payload = FileProcessor(pfile).read_file()
parser = CmUsOfdmaPreEq(raw_payload)
last_update_model: CmUsOfdmaPreEqModel = parser.to_model()
print(f"Tap count (last update): {len(last_update_model.values)}")
Programming Patterns And Integration Notes¶
- All parser examples assume you are working with offline captures stored under
tests/files/. In production, these bytes typically come from PNM bulk data transfers, TFTP, HTTP, or direct SNMP responses. -
The general flow is always:
-
Acquire bytes (
bytes) for a given PNM capture. - Pass them into the parser constructor.
- Use
.to_model()to obtain a typed model. -
Pass the model into analysis, visualization, or FastAPI response payloads.
-
The same parser classes used here are also used internally by the FastAPI endpoints in the
pypnm.api.routestree, so behavior is consistent between CLI, Python API, and REST.
With these examples in place, you can use the PyPNM parsers either as quick CLI tools for inspecting PNM files or as building blocks in larger analysis workflows.