QPSK communication system with adaptive alignment
The model presented in this example demonstrates a practical QPSK modulated digital communication system that combats the real problems of wireless channels: frequency offsets, multipath fading, and noise. The main goal is to show the effectiveness of adaptive channel alignment using an RLS filter to compensate for distortion.
Full data transmission path:
- Generation of bits → Modulation → Pulse shaping
- Passing through a realistic communication channel
- Reception → Alignment → Demodulation → Error estimation
Key channel effects:
- Phase and frequency shift (Doppler up to 10 Hz+ fixed 120° shift)
- Multipath propagation (two paths with different delays and attenuations)
- Additive white Gaussian noise (SNR = 30 dB)
Frame structure
- Training sequence (30 characters) — used to "train" the adaptive filter
- Useful data (50 characters) — real information
- This structure simulates practical communication systems (Wi-Fi, LTE), where pilot signals are periodically transmitted.
Two-stage processing
Frame → [Training part] → RLS filter (training) → [Data] → FIR filter (application of scales)
- Training stage: The RLS filter adjusts coefficients based on a known training sequence
- Operation stage: The adjusted weights are used in the FIR filter to align the useful data
What the model demonstrates
-
The viability of QPSK in difficult conditions — even with frequency shifts and fades, the system remains operational
-
Adaptive equalization efficiency — how a properly tuned filter can "clean up" a distorted signal
-
A practical approach to synchronization is to use training sequences instead of ideal assumptions.
-
Compromise between efficiency and overhead — 30 characters of training per 50 characters of data (37.5% overhead)
Application areas
- Educational demonstration of the principles of digital communication
- Testing of alignment and compensation algorithms
- Evaluation of the noise immunity of various modulation schemes
- Prototyping solutions for wireless systems
Now let's move on to initializing and running the model. The code below initializes the parameters of the QPSK communication system with adaptive alignment: sets the transmission rate of 1 Mbit/s, the frame structure (100 bits, including 30 training characters), the parameters of the modulation and shaping filter, adjusts the channel with a frequency offset of up to 10 Hz and double-beam fading, and determines the parameters of the RLS filter (15 weights and a forgetting factor of 0.95) and prepares a training sequence for adjusting the equalizer.
bitRate = 1000000;
numBitsPerFrame = 100;
bitsPerSymbol = 2;
numTrainSyms = 30;
pulseDelay = 8;
oversampleFactor = 8;
rolloffFactor = 0.2;
modOrder = 2^bitsPerSymbol;
numDataSymsPerFrame = numBitsPerFrame / bitsPerSymbol;
numSymsPerFrame = numDataSymsPerFrame + numTrainSyms;
qpskmod = EngeeComms.QPSKBasebandModulator(PhaseOffset = pi/4);
trainSig = qpskmod(rand(0:modOrder-1,numTrainSyms));
maxDoppler = 10;
numEqWeights = 15;
refTap = 8;
lambda = 0.95;
snrdB = 30;
symbolPeriod = bitsPerSymbol/bitRate;
chanSamplePeriod = symbolPeriod/oversampleFactor * 50/80;
pathDelays = [0 chanSamplePeriod];
pathGains = [0 -6];
numDataSymsPerFrame = numBitsPerFrame / bitsPerSymbol;
numSymsPerFrame = numDataSymsPerFrame + numTrainSyms;
initEqWeights = complex(zeros(numEqWeights));
eqDelay = refTap - 1;
trimTrainSig = trainSig[1:end-eqDelay];
println("Speed: $(bitRate/1e6) Mbps, Frame: $(numBitsPerFrame) bits")
println("Structure: $(Int.(numDataSymsPerFrame)) data + $(numTrainSyms) training characters")
println("Channel: Doppler $(maxDoppler) Hz, 2 beams, SNR$(snrdB) dB")
println("Equalizer: RLS filter of $(numEqWeights) samples, λ=$(lambda)")
function run_model( name_model)
Path = (@__DIR__) * "/" * name_model * ".engee"
if name_model in [m.name for m in engee.get_all_models()] # Checking the condition for loading a model into the kernel
model = engee.open( name_model ) # Open the model
model_output = engee.run( model, verbose=true ); # Launch the model
else
model = engee.load( Path, force=true ) # Upload a model
model_output = engee.run( model, verbose=true ); # Launch the model
engee.close( name_model, force=true ); # Close the model
end
sleep(0.1)
return model_output
end
run_model("qpsk_freqfade")
WorkspaceArrays.plot_wa(WorkspaceArray{Vector{Float64}}("qpsk_freqfade/Error Rate Calculation.Output_1"))
Output
Analyzing the BER graph, we clearly see that with our channel parameters, the error is zero. The system shows that even relatively simple adaptive filtering methods (RLS+ pilot training) can effectively combat serious distortions in real communication channels, making high-speed data transmission possible in non-ideal conditions. The model illustrates a fundamental principle of digital communications: processing on the receiving side can compensate for many of the problems of the physical channel, turning a "dirty" analog signal into pure digital data.