Predistorders#

class HardClipper(cr_dB: float, *, name: str = 'hard_clipping')[source]#

Implements a hard clipping method to reduce the Peak-to-Average Power Ratio (PAPR) of a signal.

Signal Model#

Hard clipping limits the amplitude of the signal to a threshold \(T_m\) while preserving the phase, reducing the peaks of the signal while keeping the average power relatively unchanged:

\[\begin{split}y[n] = \left\{\begin{array}{cl} x[n] & \text{if } |x[n]| \le T_m,\\ T_m \, e^{i \angle x[n]} & \text{if } |x[n]| > T_m, \end{array}\right. \qquad T_m = \gamma \sqrt{P_x}\end{split}\]

where:

  • \(x[n]\) is the input signal and \(y[n]\) the clipped output,

  • \(P_x = \mathbb{E}\left[|x[n]|^2\right]\) is the mean input power,

  • \(\gamma = 10^{\mathrm{CR_{dB}}/20}\) is the clipping ratio.

For real-valued inputs, \(T_m \, \mathrm{sign}(x[n])\) replaces the polar form.

Axes: axis -1 – the clipping is applied pointwise, but the threshold \(T_m\) is computed from the mean power along the last axis, so each row of a batch is clipped against its own power – one transmitter per trial (D51).

param cr_dB:

Clipping ratio \(\mathrm{CR_{dB}}\) in decibels (dB). Determines the threshold for clipping.

type cr_dB:

float

param name:

Name of the processor. Default is "hard_clipping".

type name:

str, optional, keyword-only

References

Y. Rahmatallah, S. Mohan, “Peak-To-Average Power Ratio Reduction in OFDM Systems: A Survey And Taxonomy”, IEEE Communications Surveys & Tutorials, vol. 15, no. 4, pp. 1567-1592, 2013, doi: 10.1109/SURV.2013.021313.00164.

Examples

>>> x = np.array([0.5, 2.0, -3.0])
>>> clipper = HardClipper(cr_dB=0)
>>> print(np.round(clipper(x), 3))
[ 0.5    2.    -2.102]
class IctPaprReductor(PAPR_max_dB: float, filter_weight: float, *, N_it: int = 16, shift: bool = False, norm: str = 'ortho', name: str = 'ICT')[source]#

Implements the Iterative Clipping and Filtering (ICT) method for Peak-to-Average Power Ratio (PAPR) reduction in OFDM signals.

Signal Model#

The frequency-domain input is iteratively transformed to the time domain, clipped, transformed back and filtered. Starting from \(X^{(0)}[k] = X[k]\), each iteration \(i = 1, \dots, N_{it}\) computes:

\[s^{(i)}[n] = \mathrm{IDFT}\{X^{(i-1)}\}[n], \qquad X^{(i)}[k] = w \, \mathrm{DFT}\{\mathrm{clip}(s^{(i)})\}[k]\]

where \(\mathrm{clip}(\cdot)\) is the phase-preserving amplitude clipping of HardClipper with the per-block threshold:

\[T_m = \gamma \sqrt{P_s}, \qquad \gamma = \sqrt{10^{\mathrm{PAPR_{max}}/10}},\]

and where:

  • \(X[k]\) is the frequency-domain input at subcarrier \(k\),

  • \(P_s\) is the mean power of the current time-domain block \(s^{(i)}[n]\),

  • \(\mathrm{PAPR_{max}}\) is the target maximum PAPR in dB,

  • \(w\) is the filtering weight applied in the frequency domain.

The output is the time-domain signal \(y[n] = \mathrm{IDFT}\{X^{(N_{it})}\}[n]\).

Axes: axis -1 – each block of the Block layout (..., T, F) is processed along the block content axis.

param PAPR_max_dB:

Target maximum PAPR \(\mathrm{PAPR_{max}}\) in decibels (dB).

type PAPR_max_dB:

float

param filter_weight:

Weighting factor \(w\) applied during the filtering step.

type filter_weight:

float

param N_it:

Number of iterations \(N_{it}\) for the clipping and filtering process. Default is 16.

type N_it:

int, optional, keyword-only

param shift:

Whether to apply an inverse FFT shift before the final IFFT. Default is False.

type shift:

bool, optional, keyword-only

param norm:

Normalization mode for the final IFFT. Default is “ortho”.

type norm:

str, optional, keyword-only

param name:

Name of the processor. Default is “ICT”.

type name:

str, optional, keyword-only

References

Y.-C. Wang, Z.-Q. Luo, “Optimized iterative clipping and filtering for PAPR reduction of OFDM signals”, IEEE Transactions on Communications, vol. 59, no. 1, pp. 33-37, 2011.

Examples

>>> X = np.array([[1, 1, -1, 1, 1, -1, -1, 1]], dtype=complex)
>>> reductor = IctPaprReductor(PAPR_max_dB=2.0, filter_weight=1.0)
>>> y = reductor(X)
>>> print(round(float(compute_papr(y[0], unit="dB")), 2))
2.0
class PtsPaprReductor(phase_alphabet: list[complex] | None = None, *, N_sub: int = 16, name: str = 'PTS')[source]#

Implements the Partial Transmit Sequences (PTS) method for Peak-to-Average Power Ratio (PAPR) reduction in OFDM signals.

Signal Model#

Each frequency-domain block \(X[k]\) of length \(N\) is partitioned into \(M\) disjoint adjacent sub-blocks \(X_m[k]\) (each keeping its \(N/M\) contiguous subcarriers and zeros elsewhere). The transmitted time-domain block is the phase-rotated combination:

\[y[n] = \sum_{m=1}^{M} \hat{b}_m \, \mathrm{IDFT}\{X_m\}[n]\]

where the phase factors are selected by exhaustive search over the phase alphabet \(\mathcal{B}\) to minimize the PAPR:

\[(\hat{b}_1, \dots, \hat{b}_M) = \arg\min_{b_m \in \mathcal{B}} \mathrm{PAPR}\left(\sum_{m=1}^{M} b_m \, \mathrm{IDFT}\{X_m\}\right)\]

and where:

  • \(X[k]\) is the frequency-domain input at subcarrier \(k\),

  • \(M\) is the number of sub-blocks,

  • \(\mathcal{B}\) is the phase factor alphabet,

  • \(y[n]\) is the time-domain output block.

Axes: declared axis – expects the 2-D Block layout (T, F), validated in prepare(); one phase combination is optimized per block and the IDFT runs along the block content axis.

param phase_alphabet:

Phase factor alphabet \(\mathcal{B}\) used in the PTS method. Default is [1, -1].

type phase_alphabet:

list, optional

param N_sub:

Number of sub-blocks \(M\) the OFDM signal is divided into. Default is 16.

type N_sub:

int, optional, keyword-only

param name:

Name of the processor. Default is “PTS”.

type name:

str, optional, keyword-only

References

L. J. Cimini, N. R. Sollenberger, “Peak-to-average power ratio reduction of an OFDM signal using partial transmit sequences”, 1999 IEEE International Conference on Communications, Vancouver, BC, Canada, 1999, pp. 511-515 vol. 1, doi: 10.1109/ICC.1999.767992.

Examples

>>> reductor = PtsPaprReductor([1, -1], N_sub=2)
>>> Y = reductor(np.ones((1, 4), dtype=complex))
>>> print(np.round(Y, 3) + 0.0)
[[0.+0.j 1.+1.j 0.+0.j 1.-1.j]]
>>> print(round(float(compute_papr(Y[0], unit="dB")), 2))
3.01