Chains#

class OFDMTransmitter(N_carrier_data: int, N_cp: int, *, carrier_type: ndarray | CarrierAllocation | None = None, pilots: ndarray | None = None, name: str = 'ofdm_transmitter')[source]#

OFDM transmitter chain: allocation, IFFT, cyclic prefix, serialization.

Signal Model#

The serial data symbols are split into blocks, allocated to the data subcarriers (pilot and null subcarriers are filled according to the allocation mask), and each allocated block \(X_t[k]\) of length \(N\) is brought to the time domain with the orthonormal IDFT:

\[x_t[n] = \frac{1}{\sqrt{N}} \sum_{k=0}^{N-1} X_t[k] \, e^{i 2 \pi k n / N}, \qquad n = 0, \dots, N-1\]

A cyclic prefix of length \(N_{cp}\) (the last \(N_{cp}\) samples of the block) is prepended to each block, and the extended blocks are serialized into the time-domain signal \(y[m]\).

Axes: declared axis – consumes the serial axis -1 (length \(T \, N_{data}\)), produces a serial time-domain signal of length \(T (N + N_{cp})\) on axis -1.

param N_carrier_data:

Number of data subcarriers \(N_{data}\) per OFDM symbol.

type N_carrier_data:

int

param N_cp:

Length \(N_{cp}\) of the cyclic prefix.

type N_cp:

int

param carrier_type:

Subcarrier allocation mask (e.g. data, pilot, null), passed to CarrierAllocator. Default is an all-data mask of length N_carrier_data.

type carrier_type:

CarrierAllocation or np.ndarray, optional, keyword-only

param pilots:

Pilot values, one per pilot subcarrier of the allocation mask.

type pilots:

np.ndarray or list, optional, keyword-only

param name:

Name of the processor instance. Default is "ofdm_transmitter".

type name:

str, optional, keyword-only

References

R. van Nee, R. Prasad, OFDM for Wireless Multimedia Communications, Artech House, 2000, Chapter 2.

Examples

>>> transmitter = OFDMTransmitter(4, 2)
>>> x = np.arange(8) + 0j  # 2 OFDM symbols of 4 data subcarriers
>>> y = transmitter(x)
>>> print(y.shape)  # 2 blocks of length 4 + 2
(12,)
class OFDMReceiver(N_carrier_data: int, N_cp: int, *, h: ndarray = <factory>, carrier_type: ndarray | CarrierAllocation | None = None, name: str = 'ofdm_receiver')[source]#

OFDM receiver chain: prefix removal, FFT, equalization, extraction.

Signal Model#

The serial received signal is split into blocks of length \(N + N_{cp}\), the cyclic prefix is discarded, and each block \(r_t[n]\) is brought to the frequency domain with the orthonormal DFT before one-tap zero-forcing equalization:

\[R_t[k] = \frac{1}{\sqrt{N}} \sum_{n=0}^{N-1} r_t[n] \, e^{-i 2 \pi k n / N}, \qquad Y_t[k] = \frac{R_t[k]}{H[k]}\]

where \(H[k]\) is the \(N\)-point DFT of the channel impulse response \(h[l]\). The data subcarriers are then extracted according to the allocation mask and serialized.

Axes: declared axis – consumes the serial axis -1 (length \(T (N + N_{cp})\)), produces the serial data symbols of length \(T \, N_{data}\) on axis -1.

param N_carrier_data:

Number of data subcarriers \(N_{data}\) per OFDM symbol.

type N_carrier_data:

int

param N_cp:

Length \(N_{cp}\) of the cyclic prefix.

type N_cp:

int

param h:

Channel impulse response \(h[l]\) used by the frequency domain equalizer. Default is the ideal channel [1.0].

type h:

np.ndarray or list, keyword-only

param carrier_type:

Subcarrier allocation mask (e.g. data, pilot, null), passed to CarrierExtractor. Default is an all-data mask of length N_carrier_data.

type carrier_type:

CarrierAllocation or np.ndarray, optional, keyword-only

param name:

Name of the processor instance. Default is "ofdm_receiver".

type name:

str, optional, keyword-only

References

R. van Nee, R. Prasad, OFDM for Wireless Multimedia Communications, Artech House, 2000, Chapter 2.

Examples

>>> x = np.arange(8) + 0j
>>> y = OFDMTransmitter(4, 2)(x)
>>> x_est = OFDMReceiver(4, 2)(y)
>>> print(np.round(x_est.real, 6) + 0.0)
[0. 1. 2. 3. 4. 5. 6. 7.]