Phase-shift keying¶
import matplotlib.pyplot as plt
import numpy as np
import sdr
%config InlineBackend.print_figure_kwargs = {"facecolor" : "w"}
# %matplotlib widget
In the sdr
library, phase-shift keying modulation is available in the sdr.PSK
class.
def analyze_psk(order, esn0, offset=0):
# Create a PSK modulation object
psk = sdr.PSK(order, phase_offset=offset)
# Generate random decimal symbols
s = np.random.randint(0, order, 100_000)
# Modulate decimal symbols to complex symbols
x = psk.modulate(s)
# Add AWGN to complex symbols to achieve desired Es/N0
snr = sdr.esn0_to_snr(esn0, sps=1)
x_hat = sdr.awgn(x, snr)
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
# sdr.plot.constellation(x_hat, linestyle="none")
sdr.plot.symbol_map(psk.symbol_map, limits=(-2, 2))
plt.subplot(1, 2, 2)
sdr.plot.constellation(x_hat, bins=75, heatmap=True, limits=(-2, 2))
plt.title(f"Constellation at {esn0} dB $E_s/N_0$")
plt.suptitle(f"{order}-PSK constellation")
plt.tight_layout()
plt.show()
h_srrc = sdr.root_raised_cosine(0.1, 6, 10)
tx_mf = sdr.FIRInterpolator(h_srrc, 10)
y = tx_mf.filter(x)
plt.figure(figsize=(10, 5))
sdr.plot.time_domain(y[0:1000])
plt.show()
Constellations¶
BPSK¶
analyze_psk(2, 6)


QPSK¶
analyze_psk(4, 9, offset=45)


8-PSK¶
analyze_psk(8, 12)


16-PSK¶
analyze_psk(16, 18)


Error rate curves¶
def error_rates(order):
psk = sdr.PSK(order)
k = int(np.log2(order)) # Bits per symbol
ebn0 = np.linspace(0, 10, 20)
esn0 = ebn0 + 10 * np.log10(k)
ber = sdr.ErrorRate()
ser = sdr.ErrorRate()
for i in range(esn0.size):
N_symbols = int(1e6)
s = np.random.randint(0, psk.order, N_symbols)
x = psk.modulate(s)
x_hat = sdr.awgn(x, snr=esn0[i])
s_hat = psk.demodulate(x_hat)
ber.add(ebn0[i], sdr.unpack(s, k), sdr.unpack(s_hat, k))
ser.add(esn0[i], s, s_hat)
return ber, ser
bpsk_ber, bpsk_ser = error_rates(2)
qpsk_ber, qpsk_ser = error_rates(4)
psk8_ber, psk8_ser = error_rates(8)
psk16_ber, psk16_ser = error_rates(16)
plt.figure(figsize=(10, 5))
sdr.plot.ber(*bpsk_ber.error_rates(), label="BPSK")
sdr.plot.ber(*qpsk_ber.error_rates(), label="QPSK")
sdr.plot.ber(*psk8_ber.error_rates(), label="8-PSK")
sdr.plot.ber(*psk16_ber.error_rates(), label="16-PSK")
plt.ylim(1e-5, 1e0)
plt.title("Bit error rate curves for PSK modulation in AWGN")
plt.tight_layout()
plt.show()

plt.figure(figsize=(10, 5))
sdr.plot.ser(*bpsk_ser.error_rates(), label="BPSK")
sdr.plot.ser(*qpsk_ser.error_rates(), label="QPSK")
sdr.plot.ser(*psk8_ser.error_rates(), label="8-PSK")
sdr.plot.ser(*psk16_ser.error_rates(), label="16-PSK")
plt.ylim(1e-5, 1e0)
plt.title("Symbol error rate curves for PSK modulation in AWGN")
plt.tight_layout()
plt.show()

Last update:
Jul 29, 2023