Peak-to-average power

import matplotlib.pyplot as plt
import numpy as np

import sdr

%config InlineBackend.print_figure_kwargs = {"facecolor" : "w"}
# %matplotlib widget

BPSK signal with various pulse shapes

bpsk = sdr.PSK(2)
N_symbols = 1_000
s = np.random.randint(0, bpsk.order, N_symbols)
x = bpsk.modulate(s).real
span = 8  # Length of the pulse shape in symbols
sps = 20  # Samples per symbol
def pulse_shape(alpha):
    if alpha is None:
        h = np.zeros(span * sps + 1)
        h[span * sps // 2 - sps // 2 : span * sps // 2 + sps // 2] = 1 / np.sqrt(sps)
    else:
        h = sdr.root_raised_cosine(alpha, span, sps)
    fir = sdr.FIRInterpolator(h, sps)

    bb = fir.filter(x)
    pb = bb * np.exp(1j * np.pi / 5 * np.arange(bb.size)).real

    return bb, sdr.papr(bb), pb, sdr.papr(pb)
x_bb_rect, papr_bb_rect, x_pb_rect, papr_pb_rect = pulse_shape(None)
x_bb_0p1, papr_bb_0p1, x_pb_0p1, papr_pb_0p1 = pulse_shape(0.1)
x_bb_0p5, papr_bb_0p5, x_pb_0p5, papr_pb_0p5 = pulse_shape(0.5)
x_bb_0p9, papr_bb_0p9, x_pb_0p9, papr_pb_0p9 = pulse_shape(0.9)

Examine time domain

plt.figure(figsize=(10, 5))
sdr.plot.time_domain(x_bb_rect, color="k", label=f"Rectangular, PAPR = {papr_bb_rect:.2f} dB")
sdr.plot.time_domain(x_bb_0p9, label=rf"$\alpha = 0.9$, PAPR = {papr_bb_0p9:.2f} dB")
sdr.plot.time_domain(x_bb_0p5, label=rf"$\alpha = 0.5$, PAPR = {papr_bb_0p5:.2f} dB")
sdr.plot.time_domain(x_bb_0p1, label=rf"$\alpha = 0.1$, PAPR = {papr_bb_0p1:.2f} dB")
plt.xlim(25 * sps, 50 * sps)
plt.legend()
plt.title("Baseband BPSK with SRRC pulse shaping")
plt.tight_layout()
plt.show()
../../_images/d833b6810e8d2b39ac5de133749b0fd8b846e889ed0aff37e7dc9ee0eb110abb.png
plt.figure(figsize=(10, 5))
sdr.plot.time_domain(x_pb_rect, color="k", label=f"Rectangular, PAPR = {papr_pb_rect:.2f} dB")
sdr.plot.time_domain(x_pb_0p9, label=rf"$\alpha = 0.9$, PAPR = {papr_pb_0p9:.2f} dB")
sdr.plot.time_domain(x_pb_0p5, label=rf"$\alpha = 0.5$, PAPR = {papr_pb_0p5:.2f} dB")
sdr.plot.time_domain(x_pb_0p1, label=rf"$\alpha = 0.1$, PAPR = {papr_pb_0p1:.2f} dB")
plt.xlim(25 * sps, 50 * sps)
plt.legend()
plt.title("Passband BPSK with SRRC pulse shaping")
plt.tight_layout()
plt.show()
../../_images/f02c8adda44b3575c1aaf757b2797d3c239c8cd5554fc94238e6ea56b6ea57c3.png

Examine frequency domain

plt.figure(figsize=(10, 5))
sdr.plot.periodogram(x_bb_rect, length=1024, overlap=1024 - 256, label=f"Rectangular, PAPR = {papr_bb_rect:.2f} dB")
sdr.plot.periodogram(x_bb_0p9, length=1024, overlap=1024 - 256, label=rf"$\alpha = 0.9$, PAPR = {papr_bb_0p9:.2f} dB")
sdr.plot.periodogram(x_bb_0p5, length=1024, overlap=1024 - 256, label=rf"$\alpha = 0.5$, PAPR = {papr_bb_0p5:.2f} dB")
sdr.plot.periodogram(x_bb_0p1, length=1024, overlap=1024 - 256, label=rf"$\alpha = 0.1$, PAPR = {papr_bb_0p1:.2f} dB")
plt.title("Power spectral density of baseband BPSK with SRRC pulse shaping")
plt.show()
../../_images/634e2883cdbc5dc7af0510c9f5a0474fb6d302e0cfbb90202ee66233d0d7e3f8.png
plt.figure(figsize=(10, 5))
sdr.plot.periodogram(
    x_pb_rect,
    length=1024,
    overlap=1024 - 256,
    x_axis="one-sided",
    label=f"Rectangular, PAPR = {papr_pb_rect:.2f} dB",
)
sdr.plot.periodogram(
    x_pb_0p9,
    length=1024,
    overlap=1024 - 256,
    x_axis="one-sided",
    label=rf"$\alpha = 0.9$, PAPR = {papr_pb_0p9:.2f} dB",
)
sdr.plot.periodogram(
    x_pb_0p5,
    length=1024,
    overlap=1024 - 256,
    x_axis="one-sided",
    label=rf"$\alpha = 0.5$, PAPR = {papr_pb_0p5:.2f} dB",
)
sdr.plot.periodogram(
    x_pb_0p1,
    length=1024,
    overlap=1024 - 256,
    x_axis="one-sided",
    label=rf"$\alpha = 0.1$, PAPR = {papr_pb_0p1:.2f} dB",
)
plt.title("Power spectral density of passband BPSK with SRRC pulse shaping")
plt.show()
../../_images/e0a35eb2a11f20b9683f3e4df5b0469b914f4cd77266758f0f62df8a87f1cafb.png

Plot across excess bandwidth

def sweep_alpha(order):
    bpsk = sdr.PSK(order)
    N_symbols = 1_000
    s = np.random.randint(0, bpsk.order, N_symbols)
    x = bpsk.modulate(s)

    alphas = np.linspace(0, 1, 20)
    bb_papr = []
    pb_papr = []

    for alpha in alphas:
        h = sdr.root_raised_cosine(alpha, span, sps)
        fir = sdr.FIRInterpolator(h, sps)

        bb = fir.filter(x)
        pb = bb * np.exp(1j * np.pi / 5 * np.arange(bb.size)).real

        bb_papr.append(sdr.papr(bb))
        pb_papr.append(sdr.papr(pb))

    return alphas, bb_papr, pb_papr
alpha, bpsk_bb_papr, bpsk_pb_papr = sweep_alpha(2)
alpha, qpsk_bb_papr, qpsk_pb_papr = sweep_alpha(4)
alpha, psk8_bb_papr, psk8_pb_papr = sweep_alpha(8)
alpha, psk16_bb_papr, psk16_pb_papr = sweep_alpha(16)
plt.figure(figsize=(10, 5))
plt.plot(alpha, bpsk_bb_papr, label="BPSK")
plt.plot(alpha, qpsk_bb_papr, label="QPSK")
plt.plot(alpha, psk8_bb_papr, label="8-PSK")
plt.plot(alpha, psk16_bb_papr, label="16-PSK")
plt.grid(True)
plt.legend()
plt.xlabel(r"SRRC excess bandwidth, $\alpha$")
plt.ylabel("Peak-to-average-power (PAPR)")
plt.title("PAPR for baseband PSK across SRRC excess bandwidth")
plt.show()
../../_images/c85d0cee3ad35352719c01885e54015a79d236fc3e1800893dda815d86e18dd8.png
plt.figure(figsize=(10, 5))
plt.plot(alpha, bpsk_pb_papr, label="BPSK")
plt.plot(alpha, qpsk_pb_papr, label="QPSK")
plt.plot(alpha, psk8_pb_papr, label="8-PSK")
plt.plot(alpha, psk16_pb_papr, label="16-PSK")
plt.grid(True)
plt.legend()
plt.xlabel(r"SRRC excess bandwidth, $\alpha$")
plt.ylabel("Peak-to-average-power (PAPR)")
plt.title("PAPR for passband PSK across SRRC excess bandwidth")
plt.show()
../../_images/614446e208c31aa0b487c2ec19bcb1dcce95996e3f67fbb8fa6e732137d775fc.png

Last update: Jul 27, 2023