Skip to content

Commit 5e45616

Browse files
committed
Updating documentation and adding examples.
1 parent e6286bf commit 5e45616

File tree

13 files changed

+579
-91
lines changed

13 files changed

+579
-91
lines changed

doc/make.jl

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
push!(LOAD_PATH, "../src/")
22
using Documenter, DigitalComm
33

4-
makedocs(sitename="DigitalComm")
4+
makedocs(sitename="DigitalComm.jl",
5+
format = Documenter.HTML(prettyurls = false),
6+
pages = Any[
7+
"Introduction to DigitalComm" => "index.md",
8+
"Function list" => "base.md",
9+
"Examples" => Any[
10+
"Examples/example_AWGN.md",
11+
"Examples/example_BER.md",
12+
"Examples/example_PSD.md",
13+
],
14+
],
15+
);
16+
517
#makedocs(sitename="My Documentation", format = Documenter.HTML(prettyurls = false))

doc/src/Examples/example_AWGN.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Transmission of xQAM with additive white Gaussian noise
2+
3+
To simulate a transmission of QPSK // 16QAM // 64QAM // 256QAM other a
4+
white additive Gaussian noise and display the received constellation,
5+
the following code can be used
6+
7+
# ----------------------------------------------------
8+
# --- Transmitter
9+
# ----------------------------------------------------
10+
using DigitalComm
11+
using Plots
12+
# --- Parameters
13+
snr = 20;
14+
mcs = 16;
15+
nbBits = 1024* Int(log2(mcs));
16+
# --- Binary sequence generation
17+
bitSeq = genBitSequence(nbBits);
18+
# --- QPSK mapping
19+
qamSeq = bitMappingQAM(mcs,bitSeq);
20+
# ----------------------------------------------------
21+
# --- Channel
22+
# ----------------------------------------------------
23+
# --- AWGN
24+
# Theoretical power is 1 (normalized constellation)
25+
qamNoise, = addNoise(qamSeq,snr,1);
26+
# ----------------------------------------------------
27+
# --- Rx Stage: SRRC
28+
# ----------------------------------------------------
29+
# --- Binary demapper
30+
bitDec = bitDemappingQAM(mcs,qamNoise);
31+
# --- BER measure
32+
ber = sum(xor.(bitDec,bitSeq)) /length(bitSeq);
33+
# --- Display constellation
34+
plt = scatter(real(qamNoise),imag(qamNoise),label="Noisy");
35+
scatter!(plt,real(qamSeq),imag(qamSeq),label="Ideal");
36+
xlabel!("Real part");
37+
ylabel!("Imag part");
38+
display(plt);
39+
40+
It plots the received constellation impaired by noise (here a 20dB SNR is used)
41+
![Constellation](./../img/constellation.png)
42+
43+
44+

doc/src/Examples/example_BER.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# Compute the theoretical BER for AWGN channel and various constellation size
2+
3+
Based on the previous skeleton, we can now compute an iterative testbench to compute the Bit Error Rate for various constellation size, and compare the simulation with the theory.
4+
As a gentle reminder, the theoretical bit error rate can be approximated as
5+
6+
``\mathrm{BER} = \frac{ 4 \left( 1 - \frac{1}{\sqrt{M}} \right) }{ \log_2(M)} \times Q( \sqrt{ \frac{6 \log_2(M)}{2(M-1)} \frac{Eb}{N_0}}``
7+
8+
9+
First of all let's call the modules
10+
11+
12+
using DigitalComm
13+
using PGFPlotsX
14+
15+
16+
We define first the main monte-carlo function that compute an elementary Tx-Rx link, and returns the number of error and number of bit computed (to be accumulated)
17+
18+
19+
function monteCarlo(snr,mcs,nbSymb)
20+
# Number of bits
21+
nbBits = nbSymb * Int(log2(mcs));
22+
# --- Binary sequence generation
23+
bitSeq = genBitSequence(nbBits);
24+
# --- QPSK mapping
25+
qamSeq = bitMappingQAM(mcs,bitSeq);
26+
# ----------------------------------------------------
27+
# --- Channel
28+
# ----------------------------------------------------
29+
# --- AWGN
30+
# Theoretical power is 1 (normalized constellation)
31+
qamNoise, = addNoise(qamSeq,snr,1);
32+
# ----------------------------------------------------
33+
# --- Rx Stage: SRRC
34+
# ----------------------------------------------------
35+
# --- Binary demapper
36+
bitDec = bitDemappingQAM(mcs,qamNoise);
37+
# --- Error counter
38+
nbE = sum(xor.(bitDec,bitSeq));
39+
# --- Return Error and bits
40+
return (nbE,nbBits);
41+
end
42+
43+
44+
A function to plot the BER versus the SNR, for different mcs and compare to theory
45+
46+
47+
function doPlot(snrVect,ber,qamVect)
48+
a = 0;
49+
@pgf a = Axis({
50+
ymode = "log",
51+
height ="3in",
52+
width ="4in",
53+
grid,
54+
xlabel = "SNR [dB]",
55+
ylabel = "Bit Error Rate ",
56+
ymax = 1,
57+
ymin = 10.0^(-5),
58+
title = "AWGN BER for QAM",
59+
legend_style="{at={(0,0)},anchor=south west,legend cell align=left,align=left,draw=white!15!black}"
60+
},
61+
Plot({color="red",mark="square*"},Table([snrVect,ber[1,:]])),
62+
LegendEntry("QPSK"),
63+
Plot({color="green",mark="*"},Table([snrVect,ber[2,:]])),
64+
LegendEntry("16-QAM"),
65+
66+
Plot({color="purple",mark="triangle*"},Table([snrVect,ber[3,:]])),
67+
LegendEntry("64-QAM"),
68+
Plot({color="blue",mark="diamond*"},Table([snrVect,ber[4,:]])),
69+
LegendEntry("256-QAM"),
70+
);
71+
# --- Adding theoretical curve
72+
snrLin = (10.0).^(snrVect/10)
73+
for qamScheme = qamVect
74+
ebNo = snrLin / log2(qamScheme);
75+
# This approximation is only valid for high SNR (one symbol error is converted to one bit error with Gray coding).
76+
berTheo = 4 * ( 1 - 1 / sqrt(qamScheme)) / log2(qamScheme) * qFunc.(sqrt.( 2*ebNo * 3 * log2(qamScheme) / (2*(qamScheme-1) )));
77+
@pgf push!(a,Plot({color="black"},Table([snrVect,berTheo])));
78+
end
79+
display(a);
80+
end
81+
82+
83+
Then, the main routine to compute the BER for a given number of iterations and a range of SNR
84+
85+
86+
function main()
87+
# --- Parameters
88+
nbIt = 10000; # Number of iterations
89+
nbSymb = 1024; # Number of symbols per iterations
90+
mcs = [4,16,64,256]; # Constellation size
91+
snrRange = (-1:26); # SNR, expressed in dB
92+
# --- Init performance metrics
93+
nbSNR = length(snrRange);
94+
ber = zeros(Float64,length(mcs),nbSNR);
95+
for iMcs = 1 : 1 : length(mcs)
96+
for iSNR = 1 : 1 : nbSNR
97+
# --- Create BER counters
98+
nbE = 0;
99+
nbB = 0;
100+
for iN = 1 : 1 : nbIt
101+
# --- Elementary MC call
102+
# Corresponds to a given SNR and a given iteration
103+
# As we are ergodic in AWGN, it is only nbSymb*nbIt that matters for BER computation
104+
(a,b) = monteCarlo(snrRange[iSNR],mcs[iMcs],nbSymb);
105+
# --- Update counters
106+
nbE += a; # Increment errors
107+
nbB += b; # Increment bit counters
108+
end
109+
ber[iMcs,iSNR] = nbE / nbB;
110+
end
111+
end
112+
# --- Plotting routine
113+
doPlot(snrRange,ber,mcs);
114+
end
115+
116+
117+
The output plot is the following, showing adequacy between theory and practise for high SNR (the theoretical curve is under the assumption that one symbol error leads to one erroneous bit (gray coding) which is true only with intermediate noise levels).
118+
![BER](./../img/BER_AWGN.png)
119+
120+
121+

doc/src/Examples/example_PSD.md

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
# Plotting PSD of several multicarrier waveforms
2+
3+
The purpose is to compre the Power spectral density of several multicarrier waveform. The following module can be used:
4+
5+
module example_PSD_waveform
6+
# ----------------------------------------------------
7+
# --- Modules
8+
# ----------------------------------------------------
9+
using DigitalComm
10+
# --- External Modules
11+
using Plots
12+
gr();
13+
using Printf
14+
using FFTW
15+
# ----------------------------------------------------
16+
# --- Core functions
17+
# ----------------------------------------------------
18+
""" psdWaveform.m
19+
---
20+
Compute the power spectral density (i.e the spectrum here) of the signal parametrized by the waveform structure waveform, for a number of symbol nbSymb.
21+
The frequency allocation is the one inherited from the waveform structure (i.e waveform.allocatedSubcarriers).
22+
# --- Syntax
23+
( freq,psd ) = psdWaveform(waveform,nbSymb,allocatedSubcarriers);
24+
# --- Input parameters
25+
- waveform : Structure associated to transmitted waveform
26+
- nbSymb : Number of symbol to be transmitted [Int]
27+
- nbIt : Monte carlo parameter for PSD evaluation (should be > 1)
28+
# --- Output parameters
29+
- freq : Vector of frequency evaluation (between -0.5 and 0.5). [Array{Float64,L}]
30+
- psd : Spectrum evaluated on freq [Array{Complex{Float64}},L]
31+
# --- Input parameters
32+
-
33+
# --- Output parameters
34+
-
35+
# ---
36+
# v 1.0 - Robin Gerzaguet.
37+
"""
38+
function psdWaveform(waveform,nbSymb,nbIt)
39+
# ----------------------------------------------------
40+
# --- PSD calculation
41+
# ----------------------------------------------------
42+
# --- Getting frequency allocation
43+
allocatedSubcarriers = waveform.allocatedSubcarriers;
44+
# --- Getting number of bits
45+
# First, frequency size
46+
nbSubcarriers = length(allocatedSubcarriers);
47+
# Force a fiven mcs
48+
mcs = 4; # QPSK.
49+
# Deduce number of required bits
50+
nbBits = nbSymb * nbSubcarriers * Int(log2(mcs));
51+
# --- Init psd evaluator
52+
psd = 0;
53+
# --- Iterative PSD calculation
54+
for iN = 1 : 1 : nbIt
55+
# --- Binary sequence
56+
bitSeq = genBitSequence(nbBits);
57+
# Mapping
58+
qamSeq = bitMappingQAM(mcs,bitSeq);
59+
# --- T/F matrix
60+
qamMat = reshape(qamSeq,nbSubcarriers,nbSymb);
61+
# --- Signal
62+
sigPSD = genSig(qamMat,waveform);
63+
# --- Mean PSD:
64+
psd = psd .+ 1/nbIt*1/length(sigPSD)*abs.(fftshift(fft(sigPSD))).^2;
65+
end
66+
# --- Calculating sampling frequency
67+
# Returns Nyquist frequency
68+
fe = 1;
69+
Basefe = (0:(length(psd) .-1))./length(psd)*fe .-fe/2;
70+
return (Basefe,psd);
71+
end
72+
# ----------------------------------------------------
73+
# --- Main routine
74+
# ----------------------------------------------------
75+
function main()
76+
# ----------------------------------------------------
77+
# --- Overall parameters
78+
# ----------------------------------------------------
79+
# --- Overall PHY parameters
80+
nbIt = 50; # --- Iteration number
81+
nbSymb = 14; # --- Number of symbols (one frame)
82+
nFFT = 1024; # --- Base FFT size
83+
samplingFreq = 15.36; # --- Frequency value (MHz)
84+
# --- Frequency allocation
85+
#allocatedSubcarriers= getLTEAlloc(nFFT);
86+
#allocatedSubcarriers = (1:12*4);
87+
# 4 RB alloc. 1 RB space. 4 RB allocated
88+
allocatedSubcarriers = [1:12*4; 12*5 .+ (1:12*4)];
89+
# ----------------------------------------------------
90+
# --- Waveform contender
91+
# ----------------------------------------------------
92+
# --- Init OFDM structure
93+
ofdm = initOFDM(
94+
nFFT, # --- nFFT : FFT size
95+
72, # --- nCP : CP size
96+
allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation
97+
);
98+
# --- Init SCFDMA structure
99+
scfdma = initSCFDMA(
100+
nFFT, # --- nFFT : FFT size
101+
72, # --- nCP : CP size
102+
allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation
103+
12; # --- sizeDFT : DFT preprocessing size
104+
);
105+
# --- Init UF-OFDM structure
106+
ufofdm = initUFOFDM(
107+
nFFT, # --- nFFT : FFT size
108+
73, # --- L : Filter length (same size +1 due to conv)
109+
allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation
110+
applyPD=1, # --- applyPD : Do predistortion at Tx stage
111+
attenuation=40, # --- attenuation : Filter attenuation in dB
112+
);
113+
# --- Init BF-OFDM structure
114+
bfofdm = initBFOFDM(
115+
32, # --- nFBMC : PPN size (max number of carriers)
116+
64, # --- nOFDM : Precoder size (OFDM sizer)
117+
3, # --- K : Overlapping factor
118+
9, # --- GI : CP size of precoder
119+
0.5, # --- δ : compression factor
120+
allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation
121+
"gaussian", # --- filterName : Pulse shape name
122+
BT=0.36, # --- BT : Potential BT value for Gaussian
123+
filterStopBand = 110, # --- filterStopBand : DC stopband value
124+
fS=[], # --- fS : Potential frequency coefficient for FS filter
125+
nFFT= 1024, # --- nFFT : associated FFT value in Rx
126+
nCP= 72, # --- nCP : extended CP size
127+
);
128+
# --- Init WOLA-OFDM structure
129+
wola = initWOLA(
130+
nFFT, # --- nFFT : FFT size
131+
72, # --- nCP : CP size
132+
allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation
133+
"triangle", # --- Window type @Tx side
134+
20, # --- Window size @Tx side
135+
"triangle", # --- Window type @Rx side
136+
20, # --- Window size @Rx side
137+
);
138+
fbmc = initFBMC(
139+
nFFT, # --- nFFT : FFT size
140+
4, # --- K : Overlapping factor
141+
allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation
142+
);
143+
# ----------------------------------------------------
144+
# --- Merging structures
145+
# ----------------------------------------------------
146+
# Create a dictionnary to rule them all
147+
waveforms = initWaveforms(ofdm,
148+
scfdma,
149+
ufofdm,
150+
bfofdm,
151+
wola,
152+
fbmc,
153+
);
154+
# ----------------------------------------------------
155+
# --- PSD main calculation
156+
# ----------------------------------------------------
157+
# --- Init plot container
158+
plt = plot(reuse=false);
159+
decim = 1; # decimation for light plots
160+
# --- Iterative PSD generation
161+
for (name,struc) in waveforms
162+
# --- Calculate PSD for the configuration
163+
(fe,psd) = psdWaveform(struc,nbSymb,nbIt);
164+
# Plot the result
165+
plot!(plt,fe[1:decim:end].*samplingFreq,10 .* log10.(psd[1:decim:end]/maximum(psd)),label=name,legend=:topleft);
166+
end
167+
# --- Update plot and adding labels
168+
# Purpose is to zoom out on allocated region.
169+
scsN = (1/1024)*samplingFreq; # Subscarrier spacing (normalized)
170+
rbV = (12*12); # See several RB for psd fall-off
171+
ylims!(-120,5);
172+
xlims!(-rbV*scsN,maximum(allocatedSubcarriers)*scsN+2*12*scsN);
173+
xlabel!("Frequency [MHz]");
174+
ylabel!("Spectrum");
175+
display(plt)
176+
end
177+
end
178+
179+
By running `example_PSD_waveform.main();` a comparison plot between the different PSD can be obtained
180+
181+
![PSD](./../img/psd.png)
182+
183+
184+

doc/src/assets/logo.png

167 KB
Loading

0 commit comments

Comments
 (0)