From e73c04a9591fcb72272cf17466c017d56d212f6b Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 11:47:33 +0100 Subject: [PATCH 01/10] readme: fix linter warnings Signed-off-by: Erik Buer --- readme.md | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/readme.md b/readme.md index da8e830..e660f11 100644 --- a/readme.md +++ b/readme.md @@ -1,36 +1,37 @@
-Makie.jl + Makie.jl
-# DigitalCom.jl +# DigitalCom.jl [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliatelecom.github.io/DigitalComm.jl/dev/index.html) [![Run tests](https://github.com/JuliaTelecom/DigitalComm.jl/actions/workflows/test.yml/badge.svg)](https://github.com/JuliaTelecom/DigitalComm.jl/actions/workflows/test.yml) -## Purpose +## Purpose This package aims to provide some usefull tools to manipulate digital -communication blocks in Julia. -Currently, the package support the following elements -- Bit manipulation - * Generation of random binary sequence - * Conversion between binary sequences and octal sequences +communication blocks in Julia. +Currently, the package support the following elements + +- Bit manipulation + - Generation of random binary sequence + - Conversion between binary sequences and octal sequences - Modulation // demodulation - * Quadrature Amplitude Modulation (QAM) with 4-QAM (QPSK), 16-QAM, 64-QAM and 256-QAM. - * Hard demapper for the x-QAM formats - * Max log Soft demapper for the x-QAM formats -- Single carrier pulses shapes - * Raised Cosine pulse shape - * Square root raised Cosine pulse shape -- Multicarrier Waveform generation and decoding - * Support of multicarrier Waveforms: OFDM, UF-OFDM, WOLA, BF-OFDM + - Quadrature Amplitude Modulation (QAM) with 4-QAM (QPSK), 16-QAM, 64-QAM and 256-QAM. + - Hard demapper for the x-QAM formats + - Max log Soft demapper for the x-QAM formats +- Single carrier pulses shapes + - Raised Cosine pulse shape + - Square root raised Cosine pulse shape +- Multicarrier Waveform generation and decoding + - Support of multicarrier Waveforms: OFDM, UF-OFDM, WOLA, BF-OFDM ## Installation The package can be installed with the Julia package manager. From the Julia REPL, type `]` to enter the Pkg REPL mode and run: -``` +```pkg pkg> add DigitalComm ``` From 8f9b1506c0adc41402e86a6180019b5f8bfed192 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 11:52:03 +0100 Subject: [PATCH 02/10] docs: correct linter warnings Signed-off-by: Erik Buer --- docs/src/base.md | 46 ++++++++++++++++++++-------------------------- 1 file changed, 20 insertions(+), 26 deletions(-) diff --git a/docs/src/base.md b/docs/src/base.md index 632598c..58e3a3f 100644 --- a/docs/src/base.md +++ b/docs/src/base.md @@ -1,97 +1,91 @@ - - ## Common functions ```@autodocs Modules = [DigitalComm] Pages = ["DigitalComm.jl"] Order = [:function, :type] -Depth = 1 +Depth = 1 ``` - -## Quadrature Amplitude Modulation +## Quadrature Amplitude Modulation ```@autodocs Modules = [DigitalComm] Pages = ["genBitSequence.jl","bitMapping.jl","bitDeMapping.jl","hardConstellation.jl","symbolDemapper.jl"] Order = [:function, :type] -Depth = 1 +Depth = 1 ``` - -## Channels +## Channels ```@autodocs Modules = [DigitalComm] Pages = ["Channel/addNoise.jl","Channel/rayleighChan.jl","Channel/getChannel.jl"] Order = [:function, :type] -Depth = 1 +Depth = 1 ``` -# Waveforms +# Waveforms -## Common functions +## Common functions ```@autodocs Modules = [DigitalComm] Pages = ["genSig.jl","genZCSequence.jl","getLTEAlloc.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` -## BF-OFDM +## BF-OFDM ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/BFOFDM/BFOFDM_filter.jl","Waveforms/BFOFDM/bfofdmSigGen.jl","Waveforms/BFOFDM/bfofdmSigDecode.jl","Waveforms/BFOFDM/carrierManipulation.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` -## FBMC +## FBMC ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/FBMC/fbmcSigGen.jl","Waveforms/FBMC/fbmcSigDecode.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` - -## OFDM +## OFDM ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/OFDM/ofdmSigGen.jl","Waveforms/OFDM/ofdmSigDecode.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` -## SC-FDMA +## SC-FDMA ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/UFOFDM/ufofdmSigGen.jl","Waveforms/UFOFDM/ufofdmSigDecode.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` -## UF-OFDM +## UF-OFDM ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/filterUFOFDM.jl","Waveforms/SCFDMA/scfdmaSigGen.jl","Waveforms/SCFDMA/scfdmaSigDecode.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` - -## WOLA +## WOLA ```@autodocs Modules = [DigitalComm] Pages = ["Waveforms/WOLA/wolaSigGen.jl","Waveforms/WOLA/wolaSigDecode.jl"] Order = [:function, :type] -Depth = 0 +Depth = 0 ``` From 314b4256fc79c6eb3efed208c83ceda15f7a5a30 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 12:15:36 +0100 Subject: [PATCH 03/10] docs: fix docs, so it builds Signed-off-by: Erik Buer --- .gitignore | 2 ++ docs/make.jl | 27 ++++++++++++++------------- src/Channel/getChannel.jl | 2 +- 3 files changed, 17 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index 91451c1..c2fcdc1 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ *.log Manifest.toml docs/build/ + +*.vscode/ \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 2d41472..4dbd232 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,20 +1,21 @@ push!(LOAD_PATH, "../src/") using Documenter, DigitalComm -makedocs(sitename="DigitalComm.jl", - format = Documenter.HTML(), - pages = Any[ - "Introduction to DigitalComm" => "index.md", - "Function list" => "base.md", - "Examples" => Any[ - "Examples/example_AWGN.md", - "Examples/example_BER.md", - "Examples/example_PSD.md", - ], - ], - ); -#makedocs(sitename="My Documentation", format = Documenter.HTML(prettyurls = false)) +makedocs( + #modules = [DigitalComm], + sitename="DigitalComm.jl", + format = Documenter.HTML(), + pages = Any[ + "Introduction to DigitalComm" => "index.md", + "Function list" => "base.md", + "Examples" => Any[ + "Examples/example_AWGN.md", + "Examples/example_BER.md", + "Examples/example_PSD.md", + ], + ], +); deploydocs( repo = "github.com/JuliaTelecom/DigitalComm.jl", diff --git a/src/Channel/getChannel.jl b/src/Channel/getChannel.jl index b0659c1..6d60ec4 100644 --- a/src/Channel/getChannel.jl +++ b/src/Channel/getChannel.jl @@ -11,7 +11,7 @@ Channel model object - samplingFreq : Sampling frequency [Union{Int,Float64}] - speed : Desired speed (km/h) [Union{Int,Float64}] - powerProfile : Distribution of power values in dB [Array{Float64}] -- delayProfile : Distribution of delay values in s [Array{Float64}] (same size as powerProfile) +- delayProfile : Distribution of delay values in s [Array{Float64}], same size as powerProfile - dopplerFreq : Doppler frequency (inherited from samplingFreq and speed) - delaySpread : Max support of CIR in samples [Int] # --- From 19a1c896757a1cbfac445df4f994c70646fabb94 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 13:43:23 +0100 Subject: [PATCH 04/10] docs: fix linter warnings Signed-off-by: Erik Buer --- docs/src/Examples/example_AWGN.md | 31 ++- docs/src/Examples/example_BER.md | 214 +++++++++--------- docs/src/Examples/example_PSD.md | 357 +++++++++++++++--------------- docs/src/base.md | 12 +- docs/src/index.md | 38 ++-- 5 files changed, 311 insertions(+), 341 deletions(-) diff --git a/docs/src/Examples/example_AWGN.md b/docs/src/Examples/example_AWGN.md index 9154783..c46bae2 100644 --- a/docs/src/Examples/example_AWGN.md +++ b/docs/src/Examples/example_AWGN.md @@ -1,8 +1,8 @@ -# Transmission of xQAM with additive white Gaussian noise +# Transmission of xQAM with additive white Gaussian noise To simulate a transmission of QPSK // 16QAM // 64QAM // 256QAM other a white additive Gaussian noise and display the received constellation, -the following code can be used +the following code can be used # ---------------------------------------------------- # --- Transmitter @@ -10,13 +10,13 @@ the following code can be used using DigitalComm using Plots # --- Parameters - snr = 20; - mcs = 16; - nbBits = 1024* Int(log2(mcs)); + snr = 20; + mcs = 16; + nbBits = 1024* Int(log2(mcs)); # --- Binary sequence generation - bitSeq = genBitSequence(nbBits); + bitSeq = genBitSequence(nbBits); # --- QPSK mapping - qamSeq = bitMappingQAM(mcs,bitSeq); + qamSeq = bitMappingQAM(mcs,bitSeq); # ---------------------------------------------------- # --- Channel # ---------------------------------------------------- @@ -27,18 +27,15 @@ the following code can be used # --- Rx Stage: SRRC # ---------------------------------------------------- # --- Binary demapper - bitDec = bitDemappingQAM(mcs,qamNoise); + bitDec = bitDemappingQAM(mcs,qamNoise); # --- BER measure - ber = sum(xor.(bitDec,bitSeq)) /length(bitSeq); + ber = sum(xor.(bitDec,bitSeq)) /length(bitSeq); # --- Display constellation - plt = scatter(real(qamNoise),imag(qamNoise),label="Noisy"); - scatter!(plt,real(qamSeq),imag(qamSeq),label="Ideal"); - xlabel!("Real part"); - ylabel!("Imag part"); + plt = scatter(real(qamNoise),imag(qamNoise),label="Noisy"); + scatter!(plt,real(qamSeq),imag(qamSeq),label="Ideal"); + xlabel!("Real part"); + ylabel!("Imag part"); display(plt); -It plots the received constellation impaired by noise (here a 20dB SNR is used) +It plots the received constellation impaired by noise (here a 20dB SNR is used) ![Constellation](./../img/constellation.png) - - - diff --git a/docs/src/Examples/example_BER.md b/docs/src/Examples/example_BER.md index bd9a89f..4c2d118 100644 --- a/docs/src/Examples/example_BER.md +++ b/docs/src/Examples/example_BER.md @@ -1,121 +1,109 @@ -# Compute the theoretical BER for AWGN channel and various constellation size +# Compute the theoretical BER for AWGN channel and various constellation size 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. -As a gentle reminder, the theoretical bit error rate can be approximated as +As a gentle reminder, the theoretical bit error rate can be approximated as ``\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}}`` - -First of all let's call the modules - - - using DigitalComm - using PGFPlotsX - - -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) - - - function monteCarlo(snr,mcs,nbSymb) - # Number of bits - nbBits = nbSymb * Int(log2(mcs)); - # --- Binary sequence generation - bitSeq = genBitSequence(nbBits); - # --- QPSK mapping - qamSeq = bitMappingQAM(mcs,bitSeq); - # ---------------------------------------------------- - # --- Channel - # ---------------------------------------------------- - # --- AWGN - # Theoretical power is 1 (normalized constellation) - qamNoise, = addNoise(qamSeq,snr,1); - # ---------------------------------------------------- - # --- Rx Stage: SRRC - # ---------------------------------------------------- - # --- Binary demapper - bitDec = bitDemappingQAM(mcs,qamNoise); - # --- Error counter - nbE = sum(xor.(bitDec,bitSeq)); - # --- Return Error and bits - return (nbE,nbBits); - end - - -A function to plot the BER versus the SNR, for different mcs and compare to theory - - - function doPlot(snrVect,ber,qamVect) - a = 0; - @pgf a = Axis({ - ymode = "log", - height ="3in", - width ="4in", - grid, - xlabel = "SNR [dB]", - ylabel = "Bit Error Rate ", - ymax = 1, - ymin = 10.0^(-5), - title = "AWGN BER for QAM", - legend_style="{at={(0,0)},anchor=south west,legend cell align=left,align=left,draw=white!15!black}" - }, - Plot({color="red",mark="square*"},Table([snrVect,ber[1,:]])), - LegendEntry("QPSK"), - Plot({color="green",mark="*"},Table([snrVect,ber[2,:]])), - LegendEntry("16-QAM"), - - Plot({color="purple",mark="triangle*"},Table([snrVect,ber[3,:]])), - LegendEntry("64-QAM"), - Plot({color="blue",mark="diamond*"},Table([snrVect,ber[4,:]])), - LegendEntry("256-QAM"), - ); - # --- Adding theoretical curve - snrLin = (10.0).^(snrVect/10) - for qamScheme = qamVect - ebNo = snrLin / log2(qamScheme); - # This approximation is only valid for high SNR (one symbol error is converted to one bit error with Gray coding). - berTheo = 4 * ( 1 - 1 / sqrt(qamScheme)) / log2(qamScheme) * qFunc.(sqrt.( 2*ebNo * 3 * log2(qamScheme) / (2*(qamScheme-1) ))); - @pgf push!(a,Plot({color="black"},Table([snrVect,berTheo]))); - end - display(a); - end - - -Then, the main routine to compute the BER for a given number of iterations and a range of SNR - - - function main() - # --- Parameters - nbIt = 10000; # Number of iterations - nbSymb = 1024; # Number of symbols per iterations - mcs = [4,16,64,256]; # Constellation size - snrRange = (-1:26); # SNR, expressed in dB - # --- Init performance metrics - nbSNR = length(snrRange); - ber = zeros(Float64,length(mcs),nbSNR); - for iMcs = 1 : 1 : length(mcs) - for iSNR = 1 : 1 : nbSNR - # --- Create BER counters - nbE = 0; - nbB = 0; - for iN = 1 : 1 : nbIt - # --- Elementary MC call - # Corresponds to a given SNR and a given iteration - # As we are ergodic in AWGN, it is only nbSymb*nbIt that matters for BER computation - (a,b) = monteCarlo(snrRange[iSNR],mcs[iMcs],nbSymb); - # --- Update counters - nbE += a; # Increment errors - nbB += b; # Increment bit counters - end - ber[iMcs,iSNR] = nbE / nbB; - end - end - # --- Plotting routine - doPlot(snrRange,ber,mcs); - end - +First of all let's call the modules + + using DigitalComm + using PGFPlotsX + +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) + + function monteCarlo(snr,mcs,nbSymb) + # Number of bits + nbBits = nbSymb * Int(log2(mcs)); + # --- Binary sequence generation + bitSeq = genBitSequence(nbBits); + # --- QPSK mapping + qamSeq = bitMappingQAM(mcs,bitSeq); + # ---------------------------------------------------- + # --- Channel + # ---------------------------------------------------- + # --- AWGN + # Theoretical power is 1 (normalized constellation) + qamNoise, = addNoise(qamSeq,snr,1); + # ---------------------------------------------------- + # --- Rx Stage: SRRC + # ---------------------------------------------------- + # --- Binary demapper + bitDec = bitDemappingQAM(mcs,qamNoise); + # --- Error counter + nbE = sum(xor.(bitDec,bitSeq)); + # --- Return Error and bits + return (nbE,nbBits); + end + +A function to plot the BER versus the SNR, for different mcs and compare to theory + + function doPlot(snrVect,ber,qamVect) + a = 0; + @pgf a = Axis({ + ymode = "log", + height ="3in", + width ="4in", + grid, + xlabel = "SNR [dB]", + ylabel = "Bit Error Rate ", + ymax = 1, + ymin = 10.0^(-5), + title = "AWGN BER for QAM", + legend_style="{at={(0,0)},anchor=south west,legend cell align=left,align=left,draw=white!15!black}" + }, + Plot({color="red",mark="square*"},Table([snrVect,ber[1,:]])), + LegendEntry("QPSK"), + Plot({color="green",mark="*"},Table([snrVect,ber[2,:]])), + LegendEntry("16-QAM"), + + Plot({color="purple",mark="triangle*"},Table([snrVect,ber[3,:]])), + LegendEntry("64-QAM"), + Plot({color="blue",mark="diamond*"},Table([snrVect,ber[4,:]])), + LegendEntry("256-QAM"), + ); + # --- Adding theoretical curve + snrLin = (10.0).^(snrVect/10) + for qamScheme = qamVect + ebNo = snrLin / log2(qamScheme); + # This approximation is only valid for high SNR (one symbol error is converted to one bit error with Gray coding). + berTheo = 4 * ( 1 - 1 / sqrt(qamScheme)) / log2(qamScheme) * qFunc.(sqrt.( 2*ebNo * 3 * log2(qamScheme) / (2*(qamScheme-1) ))); + @pgf push!(a,Plot({color="black"},Table([snrVect,berTheo]))); + end + display(a); + end + +Then, the main routine to compute the BER for a given number of iterations and a range of SNR + + function main() + # --- Parameters + nbIt = 10000; # Number of iterations + nbSymb = 1024; # Number of symbols per iterations + mcs = [4,16,64,256]; # Constellation size + snrRange = (-1:26); # SNR, expressed in dB + # --- Init performance metrics + nbSNR = length(snrRange); + ber = zeros(Float64,length(mcs),nbSNR); + for iMcs = 1 : 1 : length(mcs) + for iSNR = 1 : 1 : nbSNR + # --- Create BER counters + nbE = 0; + nbB = 0; + for iN = 1 : 1 : nbIt + # --- Elementary MC call + # Corresponds to a given SNR and a given iteration + # As we are ergodic in AWGN, it is only nbSymb*nbIt that matters for BER computation + (a,b) = monteCarlo(snrRange[iSNR],mcs[iMcs],nbSymb); + # --- Update counters + nbE += a; # Increment errors + nbB += b; # Increment bit counters + end + ber[iMcs,iSNR] = nbE / nbB; + end + end + # --- Plotting routine + doPlot(snrRange,ber,mcs); + end 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). ![BER](./../img/BER_AWGN.png) - - - diff --git a/docs/src/Examples/example_PSD.md b/docs/src/Examples/example_PSD.md index 8dd1f8f..1bb064f 100644 --- a/docs/src/Examples/example_PSD.md +++ b/docs/src/Examples/example_PSD.md @@ -1,184 +1,181 @@ -# Plotting PSD of several multicarrier waveforms +# Plotting PSD of several multicarrier waveforms -The purpose is to compre the Power spectral density of several multicarrier waveform. The following module can be used: +The purpose is to compre the Power spectral density of several multicarrier waveform. The following module can be used: - module example_PSD_waveform - # ---------------------------------------------------- - # --- Modules - # ---------------------------------------------------- - using DigitalComm - # --- External Modules - using Plots - gr(); - using Printf - using FFTW - # ---------------------------------------------------- - # --- Core functions - # ---------------------------------------------------- - """ psdWaveform.m - --- - 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. - The frequency allocation is the one inherited from the waveform structure (i.e waveform.allocatedSubcarriers). - # --- Syntax - ( freq,psd ) = psdWaveform(waveform,nbSymb,allocatedSubcarriers); - # --- Input parameters - - waveform : Structure associated to transmitted waveform - - nbSymb : Number of symbol to be transmitted [Int] - - nbIt : Monte carlo parameter for PSD evaluation (should be > 1) - # --- Output parameters - - freq : Vector of frequency evaluation (between -0.5 and 0.5). [Array{Float64,L}] - - psd : Spectrum evaluated on freq [Array{Complex{Float64}},L] - # --- Input parameters - - - # --- Output parameters - - - # --- - # v 1.0 - Robin Gerzaguet. - """ - function psdWaveform(waveform,nbSymb,nbIt) - # ---------------------------------------------------- - # --- PSD calculation - # ---------------------------------------------------- - # --- Getting frequency allocation - allocatedSubcarriers = waveform.allocatedSubcarriers; - # --- Getting number of bits - # First, frequency size - nbSubcarriers = length(allocatedSubcarriers); - # Force a fiven mcs - mcs = 4; # QPSK. - # Deduce number of required bits - nbBits = nbSymb * nbSubcarriers * Int(log2(mcs)); - # --- Init psd evaluator - psd = 0; - # --- Iterative PSD calculation - for iN = 1 : 1 : nbIt - # --- Binary sequence - bitSeq = genBitSequence(nbBits); - # Mapping - qamSeq = bitMappingQAM(mcs,bitSeq); - # --- T/F matrix - qamMat = reshape(qamSeq,nbSubcarriers,nbSymb); - # --- Signal - sigPSD = genSig(qamMat,waveform); - # --- Mean PSD: - psd = psd .+ 1/nbIt*1/length(sigPSD)*abs.(fftshift(fft(sigPSD))).^2; - end - # --- Calculating sampling frequency - # Returns Nyquist frequency - fe = 1; - Basefe = (0:(length(psd) .-1))./length(psd)*fe .-fe/2; - return (Basefe,psd); - end - # ---------------------------------------------------- - # --- Main routine - # ---------------------------------------------------- - function main() - # ---------------------------------------------------- - # --- Overall parameters - # ---------------------------------------------------- - # --- Overall PHY parameters - nbIt = 50; # --- Iteration number - nbSymb = 14; # --- Number of symbols (one frame) - nFFT = 1024; # --- Base FFT size - samplingFreq = 15.36; # --- Frequency value (MHz) - # --- Frequency allocation - #allocatedSubcarriers= getLTEAlloc(nFFT); - #allocatedSubcarriers = (1:12*4); - # 4 RB alloc. 1 RB space. 4 RB allocated - allocatedSubcarriers = [1:12*4; 12*5 .+ (1:12*4)]; - # ---------------------------------------------------- - # --- Waveform contender - # ---------------------------------------------------- - # --- Init OFDM structure - ofdm = initOFDM( - nFFT, # --- nFFT : FFT size - 72, # --- nCP : CP size - allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation - ); - # --- Init SCFDMA structure - scfdma = initSCFDMA( - nFFT, # --- nFFT : FFT size - 72, # --- nCP : CP size - allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation - 12; # --- sizeDFT : DFT preprocessing size - ); - # --- Init UF-OFDM structure - ufofdm = initUFOFDM( - nFFT, # --- nFFT : FFT size - 73, # --- L : Filter length (same size +1 due to conv) - allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation - applyPD=1, # --- applyPD : Do predistortion at Tx stage - attenuation=40, # --- attenuation : Filter attenuation in dB - ); - # --- Init BF-OFDM structure - bfofdm = initBFOFDM( - 32, # --- nFBMC : PPN size (max number of carriers) - 64, # --- nOFDM : Precoder size (OFDM sizer) - 3, # --- K : Overlapping factor - 9, # --- GI : CP size of precoder - 0.5, # --- δ : compression factor - allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation - "gaussian", # --- filterName : Pulse shape name - BT=0.36, # --- BT : Potential BT value for Gaussian - filterStopBand = 110, # --- filterStopBand : DC stopband value - fS=[], # --- fS : Potential frequency coefficient for FS filter - nFFT= 1024, # --- nFFT : associated FFT value in Rx - nCP= 72, # --- nCP : extended CP size - ); - # --- Init WOLA-OFDM structure - wola = initWOLA( - nFFT, # --- nFFT : FFT size - 72, # --- nCP : CP size - allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation - "triangle", # --- Window type @Tx side - 20, # --- Window size @Tx side - "triangle", # --- Window type @Rx side - 20, # --- Window size @Rx side - ); - fbmc = initFBMC( - nFFT, # --- nFFT : FFT size - 4, # --- K : Overlapping factor - allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation - ); - # ---------------------------------------------------- - # --- Merging structures - # ---------------------------------------------------- - # Create a dictionnary to rule them all - waveforms = initWaveforms(ofdm, - scfdma, - ufofdm, - bfofdm, - wola, - fbmc, - ); - # ---------------------------------------------------- - # --- PSD main calculation - # ---------------------------------------------------- - # --- Init plot container - plt = plot(reuse=false); - decim = 1; # decimation for light plots - # --- Iterative PSD generation - for (name,struc) in waveforms - # --- Calculate PSD for the configuration - (fe,psd) = psdWaveform(struc,nbSymb,nbIt); - # Plot the result - plot!(plt,fe[1:decim:end].*samplingFreq,10 .* log10.(psd[1:decim:end]/maximum(psd)),label=name,legend=:topleft); - end - # --- Update plot and adding labels - # Purpose is to zoom out on allocated region. - scsN = (1/1024)*samplingFreq; # Subscarrier spacing (normalized) - rbV = (12*12); # See several RB for psd fall-off - ylims!(-120,5); - xlims!(-rbV*scsN,maximum(allocatedSubcarriers)*scsN+2*12*scsN); - xlabel!("Frequency [MHz]"); - ylabel!("Spectrum"); - display(plt) - end - end - -By running `example_PSD_waveform.main();` a comparison plot between the different PSD can be obtained + module example_PSD_waveform + # ---------------------------------------------------- + # --- Modules + # ---------------------------------------------------- + using DigitalComm + # --- External Modules + using Plots + gr(); + using Printf + using FFTW + # ---------------------------------------------------- + # --- Core functions + # ---------------------------------------------------- + """ psdWaveform.m + --- + 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. + The frequency allocation is the one inherited from the waveform structure (i.e waveform.allocatedSubcarriers). + # --- Syntax + ( freq,psd ) = psdWaveform(waveform,nbSymb,allocatedSubcarriers); + # --- Input parameters + - waveform : Structure associated to transmitted waveform + - nbSymb : Number of symbol to be transmitted [Int] + - nbIt : Monte carlo parameter for PSD evaluation (should be > 1) + # --- Output parameters + - freq : Vector of frequency evaluation (between -0.5 and 0.5). [Array{Float64,L}] + - psd : Spectrum evaluated on freq [Array{Complex{Float64}},L] + # --- Input parameters + - + # --- Output parameters + - + # --- + # v 1.0 - Robin Gerzaguet. + """ + function psdWaveform(waveform,nbSymb,nbIt) + # ---------------------------------------------------- + # --- PSD calculation + # ---------------------------------------------------- + # --- Getting frequency allocation + allocatedSubcarriers = waveform.allocatedSubcarriers; + # --- Getting number of bits + # First, frequency size + nbSubcarriers = length(allocatedSubcarriers); + # Force a fiven mcs + mcs = 4; # QPSK. + # Deduce number of required bits + nbBits = nbSymb * nbSubcarriers * Int(log2(mcs)); + # --- Init psd evaluator + psd = 0; + # --- Iterative PSD calculation + for iN = 1 : 1 : nbIt + # --- Binary sequence + bitSeq = genBitSequence(nbBits); + # Mapping + qamSeq = bitMappingQAM(mcs,bitSeq); + # --- T/F matrix + qamMat = reshape(qamSeq,nbSubcarriers,nbSymb); + # --- Signal + sigPSD = genSig(qamMat,waveform); + # --- Mean PSD: + psd = psd .+ 1/nbIt*1/length(sigPSD)*abs.(fftshift(fft(sigPSD))).^2; + end + # --- Calculating sampling frequency + # Returns Nyquist frequency + fe = 1; + Basefe = (0:(length(psd) .-1))./length(psd)*fe .-fe/2; + return (Basefe,psd); + end + # ---------------------------------------------------- + # --- Main routine + # ---------------------------------------------------- + function main() + # ---------------------------------------------------- + # --- Overall parameters + # ---------------------------------------------------- + # --- Overall PHY parameters + nbIt = 50; # --- Iteration number + nbSymb = 14; # --- Number of symbols (one frame) + nFFT = 1024; # --- Base FFT size + samplingFreq = 15.36; # --- Frequency value (MHz) + # --- Frequency allocation + #allocatedSubcarriers= getLTEAlloc(nFFT); + #allocatedSubcarriers = (1:12*4); + # 4 RB alloc. 1 RB space. 4 RB allocated + allocatedSubcarriers = [1:12*4; 12*5 .+ (1:12*4)]; + # ---------------------------------------------------- + # --- Waveform contender + # ---------------------------------------------------- + # --- Init OFDM structure + ofdm = initOFDM( + nFFT, # --- nFFT : FFT size + 72, # --- nCP : CP size + allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation + ); + # --- Init SCFDMA structure + scfdma = initSCFDMA( + nFFT, # --- nFFT : FFT size + 72, # --- nCP : CP size + allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation + 12; # --- sizeDFT : DFT preprocessing size + ); + # --- Init UF-OFDM structure + ufofdm = initUFOFDM( + nFFT, # --- nFFT : FFT size + 73, # --- L : Filter length (same size +1 due to conv) + allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation + applyPD=1, # --- applyPD : Do predistortion at Tx stage + attenuation=40, # --- attenuation : Filter attenuation in dB + ); + # --- Init BF-OFDM structure + bfofdm = initBFOFDM( + 32, # --- nFBMC : PPN size (max number of carriers) + 64, # --- nOFDM : Precoder size (OFDM sizer) + 3, # --- K : Overlapping factor + 9, # --- GI : CP size of precoder + 0.5, # --- δ : compression factor + allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation + "gaussian", # --- filterName : Pulse shape name + BT=0.36, # --- BT : Potential BT value for Gaussian + filterStopBand = 110, # --- filterStopBand : DC stopband value + fS=[], # --- fS : Potential frequency coefficient for FS filter + nFFT= 1024, # --- nFFT : associated FFT value in Rx + nCP= 72, # --- nCP : extended CP size + ); + # --- Init WOLA-OFDM structure + wola = initWOLA( + nFFT, # --- nFFT : FFT size + 72, # --- nCP : CP size + allocatedSubcarriers, # --- allocatedSubcarriers : Subcarrier allocation + "triangle", # --- Window type @Tx side + 20, # --- Window size @Tx side + "triangle", # --- Window type @Rx side + 20, # --- Window size @Rx side + ); + fbmc = initFBMC( + nFFT, # --- nFFT : FFT size + 4, # --- K : Overlapping factor + allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation + ); + # ---------------------------------------------------- + # --- Merging structures + # ---------------------------------------------------- + # Create a dictionnary to rule them all + waveforms = initWaveforms(ofdm, + scfdma, + ufofdm, + bfofdm, + wola, + fbmc, + ); + # ---------------------------------------------------- + # --- PSD main calculation + # ---------------------------------------------------- + # --- Init plot container + plt = plot(reuse=false); + decim = 1; # decimation for light plots + # --- Iterative PSD generation + for (name,struc) in waveforms + # --- Calculate PSD for the configuration + (fe,psd) = psdWaveform(struc,nbSymb,nbIt); + # Plot the result + plot!(plt,fe[1:decim:end].*samplingFreq,10 .* log10.(psd[1:decim:end]/maximum(psd)),label=name,legend=:topleft); + end + # --- Update plot and adding labels + # Purpose is to zoom out on allocated region. + scsN = (1/1024)*samplingFreq; # Subscarrier spacing (normalized) + rbV = (12*12); # See several RB for psd fall-off + ylims!(-120,5); + xlims!(-rbV*scsN,maximum(allocatedSubcarriers)*scsN+2*12*scsN); + xlabel!("Frequency [MHz]"); + ylabel!("Spectrum"); + display(plt) + end + end -![PSD](./../img/psd.png) +By running `example_PSD_waveform.main();` a comparison plot between the different PSD can be obtained - - +![PSD](./../img/psd.png) diff --git a/docs/src/base.md b/docs/src/base.md index 58e3a3f..d356b7f 100644 --- a/docs/src/base.md +++ b/docs/src/base.md @@ -1,10 +1,9 @@ -## Common functions +## Common functions ```@autodocs Modules = [DigitalComm] Pages = ["DigitalComm.jl"] Order = [:function, :type] -Depth = 1 ``` ## Quadrature Amplitude Modulation @@ -13,7 +12,6 @@ Depth = 1 Modules = [DigitalComm] Pages = ["genBitSequence.jl","bitMapping.jl","bitDeMapping.jl","hardConstellation.jl","symbolDemapper.jl"] Order = [:function, :type] -Depth = 1 ``` ## Channels @@ -22,7 +20,6 @@ Depth = 1 Modules = [DigitalComm] Pages = ["Channel/addNoise.jl","Channel/rayleighChan.jl","Channel/getChannel.jl"] Order = [:function, :type] -Depth = 1 ``` # Waveforms @@ -33,7 +30,6 @@ Depth = 1 Modules = [DigitalComm] Pages = ["genSig.jl","genZCSequence.jl","getLTEAlloc.jl"] Order = [:function, :type] -Depth = 0 ``` ## BF-OFDM @@ -42,7 +38,6 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/BFOFDM/BFOFDM_filter.jl","Waveforms/BFOFDM/bfofdmSigGen.jl","Waveforms/BFOFDM/bfofdmSigDecode.jl","Waveforms/BFOFDM/carrierManipulation.jl"] Order = [:function, :type] -Depth = 0 ``` ## FBMC @@ -51,7 +46,6 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/FBMC/fbmcSigGen.jl","Waveforms/FBMC/fbmcSigDecode.jl"] Order = [:function, :type] -Depth = 0 ``` ## OFDM @@ -60,7 +54,6 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/OFDM/ofdmSigGen.jl","Waveforms/OFDM/ofdmSigDecode.jl"] Order = [:function, :type] -Depth = 0 ``` ## SC-FDMA @@ -69,7 +62,6 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/UFOFDM/ufofdmSigGen.jl","Waveforms/UFOFDM/ufofdmSigDecode.jl"] Order = [:function, :type] -Depth = 0 ``` ## UF-OFDM @@ -78,7 +70,6 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/filterUFOFDM.jl","Waveforms/SCFDMA/scfdmaSigGen.jl","Waveforms/SCFDMA/scfdmaSigDecode.jl"] Order = [:function, :type] -Depth = 0 ``` ## WOLA @@ -87,5 +78,4 @@ Depth = 0 Modules = [DigitalComm] Pages = ["Waveforms/WOLA/wolaSigGen.jl","Waveforms/WOLA/wolaSigDecode.jl"] Order = [:function, :type] -Depth = 0 ``` diff --git a/docs/src/index.md b/docs/src/index.md index 5729cb3..0a57d9e 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -1,30 +1,30 @@ -# DigitalComm.jl documentation - -## Summary +# DigitalComm.jl documentation +## Summary This package aims to provide some usefull tools to manipulate digital -communication blocks in Julia. -Currently, the package support the following elements -- Bit manipulation - * Generation of random binary sequence - * Conversion between binary sequences and octal sequences +communication blocks in Julia. +Currently, the package support the following elements + +- Bit manipulation + - Generation of random binary sequence + - Conversion between binary sequences and octal sequences - Modulation // demodulation - * Quadrature Amplitude Modulation (QAM) with 4-QAM (QPSK), 16-QAM, 64-QAM and 256-QAM. - * Hard demapper for the x-QAM formats - * Max log Soft demapper for the x-QAM formats -- Single carrier pulses shapes - * Raised Cosine pulse shape - * Square root raised Cosine pulse shape -- Multicarrier Waveform generation and decoding - * Support of multicarrier Waveforms: OFDM, UF-OFDM, WOLA, BF-OFDM + - Quadrature Amplitude Modulation (QAM) with 4-QAM (QPSK), 16-QAM, 64-QAM and 256-QAM. + - Hard demapper for the x-QAM formats + - Max log Soft demapper for the x-QAM formats +- Single carrier pulses shapes + - Raised Cosine pulse shape + - Square root raised Cosine pulse shape +- Multicarrier Waveform generation and decoding + - Support of multicarrier Waveforms: OFDM, UF-OFDM, WOLA, BF-OFDM ## Installation The package can be installed with the Julia package manager. From the Julia REPL, type `]` to enter the Pkg REPL mode and run: -``` +```pkg pkg> add DigitalComm ``` @@ -34,9 +34,7 @@ Or, equivalently, via the `Pkg` API: julia> import Pkg; Pkg.add("DigitalComm") ``` - -## Documentation - +## Documentation - The base documentation with the different functions can be found [in the base section](base.md) - Different examples are described in [in the example section](example.md). Other examples are provided in the example subfolder of the project. From 3731d481981536db4b361db2a3741c2a4c835574 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 14:26:22 +0100 Subject: [PATCH 05/10] docs: add 7 docstrings Signed-off-by: Erik Buer --- .gitignore | 3 ++- docs/make.jl | 3 ++- docs/src/base.md | 10 +++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index c2fcdc1..b3aa07f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ Manifest.toml docs/build/ -*.vscode/ \ No newline at end of file +*.vscode/ +*.DS_Store \ No newline at end of file diff --git a/docs/make.jl b/docs/make.jl index 4dbd232..9474187 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,9 +1,10 @@ push!(LOAD_PATH, "../src/") using Documenter, DigitalComm +#DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) # for doc tests makedocs( - #modules = [DigitalComm], + modules = [DigitalComm], sitename="DigitalComm.jl", format = Documenter.HTML(), pages = Any[ diff --git a/docs/src/base.md b/docs/src/base.md index d356b7f..656c018 100644 --- a/docs/src/base.md +++ b/docs/src/base.md @@ -18,7 +18,15 @@ Order = [:function, :type] ```@autodocs Modules = [DigitalComm] -Pages = ["Channel/addNoise.jl","Channel/rayleighChan.jl","Channel/getChannel.jl"] +Pages = ["Channel/addNoise.jl","Channel/rayleighChan.jl","Channel/getChannel.jl", "Channel/addCFO.jl"] +Order = [:function, :type] +``` + +## Windows and filters + +```@autodocs +Modules = [DigitalComm] +Pages = ["raisedCosine.jl", "UFOFDM/filterUFOFDM.jl", "WOLA/getWolaWindow.jl"] Order = [:function, :type] ``` From c78f79e3826645ff286c26b7278054e22e58e274 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 16:21:16 +0100 Subject: [PATCH 06/10] test: add support for doctest Signed-off-by: Erik Buer --- Project.toml | 8 ++++++-- docs/make.jl | 3 ++- src/raisedCosine.jl | 30 +++++++++++++++++++++++------- test/runtests.jl | 7 ++++--- test/test_doctest.jl | 5 +++++ 5 files changed, 40 insertions(+), 13 deletions(-) create mode 100644 test/test_doctest.jl diff --git a/Project.toml b/Project.toml index 6b285df..200261d 100644 --- a/Project.toml +++ b/Project.toml @@ -11,11 +11,15 @@ Printf = "de0858da-6303-5e67-8744-51eddeeeb8d7" Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [compat] -Parameters = "0.10,0.11,0.12" DSP = "0.7" FFTW = "1.4.5" SpecialFunctions = "2.0" julia = "1.6" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/docs/make.jl b/docs/make.jl index 9474187..24dc9ee 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,7 +1,7 @@ push!(LOAD_PATH, "../src/") using Documenter, DigitalComm -#DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) # for doc tests +DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) makedocs( modules = [DigitalComm], @@ -16,6 +16,7 @@ makedocs( "Examples/example_PSD.md", ], ], + doctest = true, ); deploydocs( diff --git a/src/raisedCosine.jl b/src/raisedCosine.jl index 76474b4..3ba2afe 100644 --- a/src/raisedCosine.jl +++ b/src/raisedCosine.jl @@ -6,11 +6,19 @@ SRRC definition is based on [1] \n Syntax \n h = raisedCosine(N,beta,ovS) Input parameters \n -- N : Symbol span (Int16) +- N : Symbol span (Int16) - beta : Roll-off factor (Float64) -- ovS : Oversampling rate (Int16) +- ovS : Oversampling rate (Int16) + +## Examples +```jldoctest +julia> h = raisedCosine(12,0.5,16); + +julia> sum(h) +16.002451134661918 +``` """ -function raisedCosine(N,beta,ovS) +function raisedCosine(N,beta,ovS)::Vector{Float64} # --- Final size of filter nbTaps = 2 * N * ovS + 1; # --- Init output @@ -37,17 +45,25 @@ end """ Returns the Finite Impulse Response of a Square Root Raised Cosine (SRRC) filter. \n The filter is defined by its span (evaluated in number of symbol N), its Roll-Off factor and its oversampling factor. The span corresponds to the number of symbol affected by filter before and after the center point.\n -Output is a Vector{Float64} array of size L= 2KN+1\n +Output is a `Vector{Float64}` array of size L= 2KN+1\n SRRC definition is based on [1]\n [1] 3GPP TS 25.104 V6.8.0 (2004-12). http://www.3gpp.org/ftp/ Specs/archive/25_series/25.104/25104-680.zip\n Syntax\n h = sqrtRaisedCosine(N,beta,ovS) \n Input parameters \n -- N : Symbol span (Int16) +- N : Symbol span (Int16) - beta : Roll-off factor (Float64) -- ovS : Oversampling rate (Int16) +- ovS : Oversampling rate (Int16) + +## Examples +```jldoctest +julia> h = sqrtRaisedCosine(12,0.5,16); + +julia> sum(h) +14.07688841517184 +``` """ -function sqrtRaisedCosine(N,beta,ovS) +function sqrtRaisedCosine(N,beta,ovS)::Vector{Float64} # --- Final size of filter nbTaps = 2 * N * ovS + 1; # --- Init output diff --git a/test/runtests.jl b/test/runtests.jl index 58faab4..41f7cbc 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,13 +1,14 @@ # ---------------------------------------------------- # --- Tests # ---------------------------------------------------- -import Printf -import Test +import Printf, Test + +# Run DocTests +include("test_doctest.jl") # Binary sequence include("test_genBitSequence.jl"); - # Bit Mapping include("test_bitMapping.jl"); diff --git a/test/test_doctest.jl b/test/test_doctest.jl new file mode 100644 index 0000000..a5e2e5d --- /dev/null +++ b/test/test_doctest.jl @@ -0,0 +1,5 @@ +using Documenter, DigitalComm + +# Runs the doctests (the jldoctest) in funciton documentation. +DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) +Documenter.doctest(DigitalComm) \ No newline at end of file From 2bf8150976eab77c03934cf5c9ec0aabac16c787 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 18:13:13 +0100 Subject: [PATCH 07/10] docs: implements plot generation in docs Signed-off-by: Erik Buer --- Project.toml | 4 +- docs/Project.toml | 5 +++ docs/make.jl | 6 ++- docs/src/Examples/example_AWGN.md | 72 +++++++++++++++++-------------- readme.md | 2 +- src/raisedCosine.jl | 8 ++-- 6 files changed, 57 insertions(+), 40 deletions(-) diff --git a/Project.toml b/Project.toml index 200261d..6d45470 100644 --- a/Project.toml +++ b/Project.toml @@ -20,6 +20,8 @@ julia = "1.6" [extras] Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" + [targets] -test = ["Test"] +test = ["Test", "Documenter"] diff --git a/docs/Project.toml b/docs/Project.toml index dfa65cd..c3a8da9 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -1,2 +1,7 @@ [deps] +DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341" +Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" +PyPlot = "d330b81b-6aea-500a-939a-2ce795aea3ee" +SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" diff --git a/docs/make.jl b/docs/make.jl index 24dc9ee..4a0f38b 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,5 +1,9 @@ push!(LOAD_PATH, "../src/") -using Documenter, DigitalComm + +using Documenter + +include("../src/DigitalComm.jl") # Ensures that the docs is built using the latest version of the package +using .DigitalComm DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) diff --git a/docs/src/Examples/example_AWGN.md b/docs/src/Examples/example_AWGN.md index c46bae2..2c88835 100644 --- a/docs/src/Examples/example_AWGN.md +++ b/docs/src/Examples/example_AWGN.md @@ -4,38 +4,44 @@ To simulate a transmission of QPSK // 16QAM // 64QAM // 256QAM other a white additive Gaussian noise and display the received constellation, the following code can be used - # ---------------------------------------------------- - # --- Transmitter - # ---------------------------------------------------- - using DigitalComm - using Plots - # --- Parameters - snr = 20; - mcs = 16; - nbBits = 1024* Int(log2(mcs)); - # --- Binary sequence generation - bitSeq = genBitSequence(nbBits); - # --- QPSK mapping - qamSeq = bitMappingQAM(mcs,bitSeq); - # ---------------------------------------------------- - # --- Channel - # ---------------------------------------------------- - # --- AWGN - # Theoretical power is 1 (normalized constellation) - qamNoise, = addNoise(qamSeq,snr,1); - # ---------------------------------------------------- - # --- Rx Stage: SRRC - # ---------------------------------------------------- - # --- Binary demapper - bitDec = bitDemappingQAM(mcs,qamNoise); - # --- BER measure - ber = sum(xor.(bitDec,bitSeq)) /length(bitSeq); - # --- Display constellation - plt = scatter(real(qamNoise),imag(qamNoise),label="Noisy"); - scatter!(plt,real(qamSeq),imag(qamSeq),label="Ideal"); - xlabel!("Real part"); - ylabel!("Imag part"); - display(plt); +## Transmitter + +```@example AWG +using ..DigitalComm # hide +using Plots +# --- Parameters +snr = 20; +mcs = 16; +nbBits = 1024* Int(log2(mcs)); +# --- Binary sequence generation +bitSeq = genBitSequence(nbBits); +# --- QPSK mapping +qamSeq = bitMappingQAM(mcs,bitSeq); nothing +``` + +## Channel + +```@example AWG +# --- AWGN +# Theoretical power is 1 (normalized constellation) +qamNoise, = addNoise(qamSeq,snr,1); nothing +``` + +## Recevicer + +```@example AWG +# --- Binary demapper +bitDec = bitDemappingQAM(mcs,qamNoise); +# --- BER measure +ber = sum(xor.(bitDec,bitSeq)) /length(bitSeq); +# --- Display constellation +plt = scatter(real(qamNoise),imag(qamNoise),label="Noisy"); +scatter(plt,real(qamSeq),imag(qamSeq),label="Ideal"); +xlabel!("Real part"); +ylabel!("Imag part"); + +savefig("constellation.svg"); nothing # hide +``` It plots the received constellation impaired by noise (here a 20dB SNR is used) -![Constellation](./../img/constellation.png) +![Constellation](constellation.svg) diff --git a/readme.md b/readme.md index e660f11..dc3362d 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@ Makie.jl -# DigitalCom.jl +# DigitalComm.jl [![](https://img.shields.io/badge/docs-stable-blue.svg)](https://juliatelecom.github.io/DigitalComm.jl/dev/index.html) [![Run tests](https://github.com/JuliaTelecom/DigitalComm.jl/actions/workflows/test.yml/badge.svg)](https://github.com/JuliaTelecom/DigitalComm.jl/actions/workflows/test.yml) diff --git a/src/raisedCosine.jl b/src/raisedCosine.jl index 3ba2afe..f22e2db 100644 --- a/src/raisedCosine.jl +++ b/src/raisedCosine.jl @@ -14,8 +14,8 @@ Input parameters \n ```jldoctest julia> h = raisedCosine(12,0.5,16); -julia> sum(h) -16.002451134661918 +julia> length(h) +385 ``` """ function raisedCosine(N,beta,ovS)::Vector{Float64} @@ -59,8 +59,8 @@ Input parameters \n ```jldoctest julia> h = sqrtRaisedCosine(12,0.5,16); -julia> sum(h) -14.07688841517184 +julia> length(h) +385 ``` """ function sqrtRaisedCosine(N,beta,ovS)::Vector{Float64} From 314256a5e85a8d0776be0b321335fa1e15914b4d Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 20:29:27 +0100 Subject: [PATCH 08/10] CI: add document building dry-run on PR Signed-off-by: Erik Buer --- .github/workflows/BuildDocDryRun.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/BuildDocDryRun.yml diff --git a/.github/workflows/BuildDocDryRun.yml b/.github/workflows/BuildDocDryRun.yml new file mode 100644 index 0000000..43b09ae --- /dev/null +++ b/.github/workflows/BuildDocDryRun.yml @@ -0,0 +1,17 @@ +name: DocumentationDryRun + +on: [push, pull_request] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@latest + with: + version: '1.6' + - name: Install dependencies + run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - name: Build and deploy + run: julia --project=docs/ docs/make.jl + From 413ab0bc6b23edb087ecc3dcf1446263d1a0250d Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Fri, 29 Dec 2023 20:53:54 +0100 Subject: [PATCH 09/10] docs: make script to easily run make.jl locally Signed-off-by: Erik Buer --- docs/make_local.jl | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 docs/make_local.jl diff --git a/docs/make_local.jl b/docs/make_local.jl new file mode 100644 index 0000000..7f30eaa --- /dev/null +++ b/docs/make_local.jl @@ -0,0 +1,7 @@ +# Assumes its being run from project root. + +using Pkg +Pkg.activate("docs/") +Pkg.instantiate() + +include("make.jl") \ No newline at end of file From f8e8c81b4b83e03947bded9bf8863df86e86b029 Mon Sep 17 00:00:00 2001 From: Erik Buer Date: Sat, 30 Dec 2023 15:46:23 +0100 Subject: [PATCH 10/10] docs: revert to typical make Signed-off-by: Erik Buer --- docs/make.jl | 5 +---- docs/make_local.jl | 7 ------- 2 files changed, 1 insertion(+), 11 deletions(-) delete mode 100644 docs/make_local.jl diff --git a/docs/make.jl b/docs/make.jl index 4a0f38b..b2d73de 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -1,9 +1,6 @@ push!(LOAD_PATH, "../src/") -using Documenter - -include("../src/DigitalComm.jl") # Ensures that the docs is built using the latest version of the package -using .DigitalComm +using Documenter, DigitalComm DocMeta.setdocmeta!(DigitalComm, :DocTestSetup, :(using DigitalComm); recursive=true) diff --git a/docs/make_local.jl b/docs/make_local.jl deleted file mode 100644 index 7f30eaa..0000000 --- a/docs/make_local.jl +++ /dev/null @@ -1,7 +0,0 @@ -# Assumes its being run from project root. - -using Pkg -Pkg.activate("docs/") -Pkg.instantiate() - -include("make.jl") \ No newline at end of file