Phase Shift Keying Modulation: An Introduction and Simulation in Python
Simulate digital communication in Python
In the world of digital communication, the ability to efficiently and accurately transmit information is of utmost importance. Modulation techniques provide the means to encode and transmit data over various communication channels. In the previous articles, we explored the fundamental concepts of modulation methods classification, delved into the workings of amplitude modulation (AM), and simulated frequency modulation (FM) using Python. Now, it’s time to continue our journey by diving into another essential modulation technique: phase shift keying (PSK).
While AM and FM are analog modulation, PSK is a digital modulation method that enables the transmission of digital data over analog communication channels. While AM and FM focus on varying the amplitude and frequency of the carrier signal, respectively, PSK modulation encodes information by manipulating the phase of the carrier wave. By precisely controlling the phase shifts, PSK allows for the transmission of multiple bits of data per symbol.
In this article, we will build upon the knowledge gained from the previous articles to understand the principles of PSK modulation and explore its implementation using Python simulations. By the end of this article, you will have a solid understanding of how PSK modulation works and how to simulate its behavior using the powerful NumPy library in Python.
PSK Theory
Phase shift keying (PSK) is a digital modulation technique that encodes information in the phase of a carrier signal. As already stated, by varying the phase of the carrier signal, PSK allows for the transmission of multiple bits per symbol, making it an efficient method for digital data communication.
The carrier signal is typically a sinusoidal waveform with a fixed frequency and amplitude. The different phase states of the carrier signal correspond to specific bit patterns, enabling the transmission of binary data. An example for a pattern of bits which modulates a carrier signal to obtain a PSK signal is shown below. As it can be seen, the phase of the signal changes according to the value of the modulation signal.

Mathematically, a PSK signal s(t) is represented by the following equation:

where Ac is the carrier ampligude, fc is the carrier frequency and n is the data to be transmitted.
In the example shown in the Figure, n may be equal to 0 or 1. This kind of modulation is know as BPSK, which results in two possible phases of the carrier signal. This is conveniently respresented in a constellation diagram, which plots all the possible phases in a complex plane where the real and imaginary axes are called the in-phase and quadrature axis. For the BPSK modulation, the constellation diagram is:

However, there are multiple PSK modulations with more possible phase. For example, QPSK admits 4 different phase (corresponding to n = 0,1,2,3) and its constellation is:

In general, the number of possible phase is the order of the modulation, such as 8PSK, 16PSK, etc. The most used PSK modulation are BPSK, QPSK and 8PSK, or variations of them.
Python Simulation
Below there is a Python function that computes a PSK signal based on the sequence of bits, the modulation order and the samples per symbol. Firstly, the bits are mapped to their corresponding phase state. Then, these states are repeated to match the number of samples per symbol. Finally, a carrier with 500Hz is generated at sampling frequency of 10kHz and the phase array is added.
import numpy as np
from matplotlib import pyplot as plt
def psk_modulation(bits, modulation_order, samples_per_symbol):
# Define the phase states for the chosen modulation order
phase_states = np.linspace(0, 2*np.pi, modulation_order, endpoint=False)
# Map the bits to the corresponding phase states
phase_sequence = [phase_states[int(b)] for b in bits]
# Generate the continuous phase signal with the desired samples per symbol
phase_signal = np.repeat(phase_sequence, samples_per_symbol)
# Generate the carrier signal with unit amplitude and frequency of 1khz, Ts = 100khz
t = np.arange(0,len(phase_signal))/10e3
fc = 500
carrier_signal = np.sin(2*np.pi*fc*t+phase_signal)
return carrier_signalAs an example, this code modulate a sequence of bits in BPSK:
# Example inputs
bits = [0, 1, 0, 1, 1, 0] # Sequence of bits
modulation_order = 2 # Modulation order (e.g., 2 for BPSK, 4 for QPSK)
samples_per_symbol = 20 # Number of samples per symbol
# Compute the PSK signal
psk_signal = psk_modulation(bits, modulation_order, samples_per_symbol)
# Print the resulting PSK signal
plt.plot(psk_signal)The result shows how 0 bits have phase = 0 and 1 bits have phase = pi. Furthermore, changes may be noticed every 20 samples. The image below shows the phase changes for the different transmitted bits.

Do you want to learn Python?:
Have you spent your learning budget for this month, you can join Medium here:
Level Up Coding
Thanks for being a part of our community! Before you go:
- 👏 Clap for the story and follow the author 👉
- 📰 View more content in the Level Up Coding publication
🔔 Follow us: Twitter | LinkedIn | Newsletter
🧠 AI Tools ⇒ Become an AI prompt engineer





