Source code for at_py.readwrite.pat

"""Source beam pattern ``.sbp`` reader (port of Matlab ``readpat.m``)."""

from __future__ import annotations

from dataclasses import dataclass

import numpy as np


[docs] @dataclass(frozen=True) class BeamPatternRead: """``power_linear`` is ``10 ** (dB / 20)`` per Matlab ``readpat``.""" n_points: int angle_deg: np.ndarray power_linear: np.ndarray
[docs] def read_beam_pattern_bytes(data: bytes) -> BeamPatternRead: """Parse ``.sbp`` bytes: count ``N``, then ``N`` rows of ``angle_deg``, ``power_dB``.""" text = data.decode("utf-8", errors="replace") lines = [ ln.strip() for ln in text.splitlines() if ln.strip() and not ln.strip().startswith("!") ] if not lines: raise ValueError("empty .sbp file") n = int(lines[0].split()[0]) if len(lines) < 1 + n: raise ValueError(f".sbp: expected {n} data rows after count") ang = np.empty(n, dtype=np.float64) pdb = np.empty(n, dtype=np.float64) for i in range(n): parts = lines[1 + i].replace(",", " ").split() if len(parts) < 2: raise ValueError(f".sbp row {i + 1}: expected 2 floats") ang[i] = float(parts[0]) pdb[i] = float(parts[1]) plin = np.power(10.0, pdb / 20.0) return BeamPatternRead(n_points=n, angle_deg=ang, power_linear=plin)
[docs] def omni_beam_pattern() -> BeamPatternRead: """Omni-directional default when Matlab ``SBP ~= '*'`` (two endpoints, 0 dB).""" ang = np.array([-180.0, 180.0], dtype=np.float64) pdb = np.array([0.0, 0.0], dtype=np.float64) plin = np.power(10.0, pdb / 20.0) return BeamPatternRead(n_points=2, angle_deg=ang, power_linear=plin)