OFDM modulation and demodulation on IP cores in Engee
In the example, let's consider the transmission of BPSK and QPSK signals through an OFDM modulator and demodulator on Engee IP cores. Let's check the data recovery, evaluate the EVM, and see the constellations. The model works without noise, so the result shows the error of the calculations with a fixed point.
OFDM distributes data across orthogonal subcarriers. The transmitter generates the symbol using IFFT and adds a cyclic prefix; the receiver removes the prefix and performs FFT. In our model, 2048 subcarriers are used for data
The rest are reserved for protective bands and a zero subcarrier.
The generator in C outputs complex BPSK or QPSK samples in the Q14 format. After conversion to Fixed-point, the signal passes through OFDM Modulator and OFDM Demodulator.
The FFT size is 2048, the cyclic prefix is 64 samples, and the window is 32. The protection bands contain 128 and 127 subcarriers, the DC subcarrier is disabled. A factor of 0.5 at the input creates an amplitude margin, and a factor of 2 at the output restores the scale. StartupReset resets cores in the first four clock cycles.
Parameters and preparation
The sampling frequency is 30.72 MHz, and the simulation time is 1 ms. One character with a prefix takes 2112 clock cycles. First, let's download the launch and analysis functions of the model.
using Main: engee, plot, plot!, histogram, hline!, savefig, Animation, frame, gif
using JSON
if !isdefined(Main, :OFDMIPDemo)
Base.include(Main, joinpath(@__DIR__, "ofdm_demo.jl"))
end
using Main: OFDMIPDemo
ofdm_dir = @__DIR__
ofdm_output = mktempdir(; prefix="ofdm_ip_results_")
println("Results: ", ofdm_output)
println("FFT = ", OFDMIPDemo.NFFT, "; useful subcarriers = ", OFDMIPDemo.ND)
The model, the auxiliary script, and the source code of the generator are located next to this script. The paths are determined relative to its folder.
BPSK Verification
Let's run the BPSK model. Let's compare the transmitted and restored characters and check the number of bit errors.
bpsk_result = OFDMIPDemo.run_case(ofdm_dir; modulation=0)
println(JSON.json(bpsk_result.metrics))
write(joinpath(ofdm_output, "bpsk_metrics.json"), JSON.json(bpsk_result.metrics))
Seven complete OFDM symbols were obtained: 12544 complex samples. The EVM is about 0.46%, there are no bit errors. The initial zero count is not involved in checking the bits.
EVM is calculated using full blocks with an active valid signal, without adjusting the phase and scale:
BPSK Analysis
Let's plot the constellations, the recovery error, and the valid signals.
bpsk_figure = OFDMIPDemo.result_plot(bpsk_result)
savefig(bpsk_figure, joinpath(ofdm_output, "bpsk_results.png"))
display(bpsk_figure)
The restored points are located next to the original ones. The error graph shows the calculation error, and the valid signals show the intervals of data output by the cores.
Checking the QPSK
Let's repeat the launch for QPSK. The bits are determined by the signs of the real and imaginary parts of the reconstructed signal.
qpsk_result = OFDMIPDemo.run_case(ofdm_dir; modulation=1)
println(JSON.json(qpsk_result.metrics))
qpsk_figure = OFDMIPDemo.result_plot(qpsk_result)
savefig(qpsk_figure, joinpath(ofdm_output, "qpsk_results.png"))
display(qpsk_figure)
For QPSK, we get four groups of points, an EVM of about 0.47% and not a single error among the 25086 checked bits.
Repeatability and retention of results
Let's run BPSK again and compare the results. We will save the data of the three launches for further analysis.
bpsk_repeat = OFDMIPDemo.run_case(ofdm_dir; modulation=0)
@assert bpsk_repeat.metrics["evm_percent"] == bpsk_result.metrics["evm_percent"]
@assert bpsk_repeat.metrics["bit_errors"] == 0
ofdm_report = Dict("status"=>"passed", "notebook_executed"=>true, "channel"=>"direct noiseless IP-core loopback", "runs"=>[bpsk_result.metrics, qpsk_result.metrics, bpsk_repeat.metrics])
write(joinpath(ofdm_output, "verification.json"), JSON.json(ofdm_report))
string("OFDM IP demo passed; BPSK EVM=", round(bpsk_result.metrics["evm_percent"];digits=4), "%; QPSK EVM=", round(qpsk_result.metrics["evm_percent"];digits=4), "%; bit errors=0")
Running it again gives the same data and metrics. This confirms the reproducibility of the model with the same parameters and core reset.
Conclusion
The model demonstrates OFDM transmission with BPSK and QPSK subcarrier modulation on Engee IP cores. In a noise–free channel, data is recovered without bit errors, and the EVM is about 0.46-0.47%. The slight deviation of the accepted symbols is due to calculations at a fixed point.