Carrier allocation#

Spectral allocation objects (decisions D15-D21).

An allocation is a frozen CarrierAllocation object carrying a 2D time-frequency mask in physical order (signed subcarrier index, DC at the center) plus its metadata and the clause of the standard it comes from. The conversion to FFT order is explicit and unique (CarrierAllocation.to_fft_order(), decision D16).

Standard allocations come from a registry-backed catalog:

>>> alloc = get_allocation("802.11a")
>>> alloc.N_data, alloc.N_pilots
(48, 4)
class CarrierType(*values)[source]#

Subcarrier roles – no magic integers (decision D21a).

class CarrierAllocation(carrier_type: ndarray, *, subcarrier_spacing: float | None = None, cp_length: int | None = None, standard: str = 'custom', reference: str = '')[source]#

A time-frequency subcarrier allocation (decision D15).

The mask carrier_type has shape (T_p, N_fft): one row per OFDM symbol of the time period \(T_p\), one column per subcarrier in physical order (signed index \(k\), DC at the center). Scattered pilot patterns (DVB-T, LTE CRS, NR DM-RS) are 2D by nature; a pure band allocation has T_p == 1.

Parameters:
  • carrier_type (np.ndarray) – (T_p, N_fft) int8 array of CarrierType values, in physical order.

  • subcarrier_spacing (float, optional, keyword-only) – Subcarrier spacing \(\Delta f\) in Hz.

  • cp_length (int, optional, keyword-only) – Cyclic prefix length in samples.

  • standard (str, keyword-only) – Name of the standard this allocation implements. Default “custom”.

  • reference (str, keyword-only) – Clause of the standard the numbers were copied from.

Examples

>>> mask = np.array([[0, 1, 2, 1, 0]])
>>> alloc = CarrierAllocation(mask)
>>> alloc.N_fft, alloc.N_data, alloc.N_pilots, alloc.period
(5, 2, 1, 1)
>>> print(alloc.k)
[-2 -1  0  1  2]
property N_fft: int#

FFT size (number of subcarriers).

property period: int#

Time period \(T_p\) of the pattern, in OFDM symbols.

property N_data: int#

Number of DATA subcarriers per OFDM symbol.

property N_pilots: int#

Total number of PILOT subcarriers over one period.

property k: ndarray#

Signed subcarrier indices (physical order, DC at index 0).

to_fft_order() → ndarray[source]#

Return the mask in FFT order.

Physical order (DC at the center) maps to FFT order (DC first) through ifftshift – the unique, explicit conversion of decision D16 (fftshift is its inverse; the two differ for odd N_fft).

plot(ax: Any = None) → Any[source]#

Plot the allocation map; returns the axis (decision D25).

Colors, hatches and legend labels come from the frozen semantic table CARRIER_STYLE (decision D27a) – the same source as the ASCII spectral map of __repr__, so the two views cannot diverge.

band_allocation(N_fft: int, k_used: tuple[int, int], k_pilots: Sequence[int] = (), n_dc: int = 0, expect: dict[str, int] | None = None, **meta: Any) → CarrierAllocation[source]#

Build a band allocation from signed subcarrier indices.

Parameters:
  • N_fft (int) – FFT size.

  • k_used (tuple of int) – Inclusive signed range (k_min, k_max) of occupied subcarriers.

  • k_pilots (iterable of int, optional) – Signed indices of pilot subcarriers.

  • n_dc (int, optional) – Number of nulled subcarriers centered on DC. Default 0.

  • expect (dict, optional) – {"data": ..., "pilots": ...} copied verbatim from the standard’s table; checked at construction (decision D20).

  • **meta – Forwarded to CarrierAllocation (subcarrier_spacing, cp_length, standard, reference).

Examples

>>> alloc = band_allocation(8, k_used=(-3, 3), k_pilots=(-2, 2), n_dc=1,
...                         expect={"data": 4, "pilots": 2})
>>> print(alloc.carrier_type[0])
[0 1 2 1 0 1 2 1]
scattered_allocation(N_fft: int, k_used: tuple[int, int], period: int, rule: Callable[[int, int], bool], expect: dict[str, int] | None = None, **meta: Any) → CarrierAllocation[source]#

Build a scattered-pilot allocation from a positional rule.

Parameters:
  • N_fft (int) – FFT size.

  • k_used (tuple of int) – Inclusive signed range of occupied subcarriers.

  • period (int) – Time period \(T_p\) of the pattern, in OFDM symbols.

  • rule (callable) – rule(l, k) -> bool returning True when subcarrier k of symbol l carries a pilot (l in range(period), k signed). Note: callables are not serializable (documented limit of decision D31).

  • expect (dict, optional) – Self-check values copied from the standard (decision D20).

  • **meta – Forwarded to CarrierAllocation.

Examples

>>> alloc = scattered_allocation(8, k_used=(-4, 3), period=2,
...                              rule=lambda l, k: (k + 4 + 2 * l) % 4 == 0)
>>> print(alloc.carrier_type)
[[2 1 1 1 2 1 1 1]
 [1 1 2 1 1 1 2 1]]
get_allocation(standard: str, **kwargs: Any) → CarrierAllocation[source]#

Return a catalog allocation by standard name.

Examples

>>> alloc = get_allocation("802.11a")
>>> alloc.N_fft, alloc.N_data, alloc.N_pilots
(64, 48, 4)
register_allocation(name: str)[source]#

Register a catalog entry; users can add their own standards.

available_allocations() → list[str][source]#

Names accepted by get_allocation().