diff --git a/examples/example_BER_CDMA.jl b/examples/example_BER_CDMA.jl new file mode 100644 index 0000000..4370cc9 --- /dev/null +++ b/examples/example_BER_CDMA.jl @@ -0,0 +1,151 @@ +module example_BER_cdma + + + +# ---------------------------------------------------- +# --- Modules +# ---------------------------------------------------- +using DigitalComm +# --- External Modules +using Plots +using Printf +using FFTW +using Statistics + + + +# ---------------------------------------------------- +# --- Core functions +# ---------------------------------------------------- +function getBER(waveform,mcs,snrVect,nbSymb,nbIt) + if waveform isa DigitalComm.StrucCDMA + # --- Get code allocation + nbSubcarriers = length(waveform.userMask) + else + # --- Getting frequency allocation + allocatedSubcarriers = waveform.allocatedSubcarriers; + nbSubcarriers = length(allocatedSubcarriers); + end + # Deduce number of required bits + nbBits = nbSymb * nbSubcarriers * Int(log2(mcs)); + # --- Init BER vector + nbSNR = length(snrVect); + ber = zeros(Float64,nbSNR); + # --- Iterative PSD calculation + for k = 1 : 1 : nbSNR + # --- Update counters + nbC = 0; + nbE = 0; + powSig = 0; + for iN = 1 : 1 : nbIt + # --- Binary sequence + bitSeq = genBitSequence(nbBits); + # Mapping + qamSeq = bitMappingQAM(mcs,bitSeq); + # --- T/F matrix + qamMat = reshape(qamSeq,nbSubcarriers,nbSymb); + # --- Signal + sigId = genSig(qamMat,waveform); + # ---------------------------------------------------- + # --- Channel + # ---------------------------------------------------- + # --- AWGN + if iN == 1 + # We compute the power based on generated signal + # We troncate the beginning and end of signal to avoid + # estimation biais induced by (potential) filter tails + powSig = mean(abs2.( @views sigId[1+ end÷4 : end - end÷4])); + end + sigNoise, = addNoise(sigId,snrVect[k],powSig); + # ---------------------------------------------------- + # --- Rx Stage + # ---------------------------------------------------- + # --- Waveform demodulator + qamDec = decodeSig(sigNoise,waveform); + # --- Binary demapper + bitDec = bitDemappingQAM(mcs,qamDec[:]); + # --- BER measure + nbE += sum(xor.(bitDec,bitSeq)); + nbC += length(bitSeq); + end + # --- BER measure + # Adding 1e-10 to avoid log plot of zero errors + ber[k] = 1e-10 .+ nbE / nbC; + end + return ber +end + +# ---------------------------------------------------- +# --- Main routine +# ---------------------------------------------------- +function main() + # ---------------------------------------------------- + # --- Overall parameters + # ---------------------------------------------------- + # --- Overall PHY parameters + nbIt = 20; # --- Iteration number + nbSymb = 1400; # --- Number of symbols (one frame) + nFFT = 1024; # --- Base FFT size + samplingFreq = 3.84e6; # --- Frequency value (MHz) + mcs = 16; # --- 16-QAM + snrVect = (-10:30); + # --- Frequency allocation + allocatedSubcarriers= getLTEAlloc(nFFT); + + # ---------------------------------------------------- + # --- Waveform contender + # ---------------------------------------------------- + # --- Init OFDM structure + cdma4 = initCDMA( + 4, + :ovsf + ) + cdma16 = initCDMA( + 16, + :ovsf + ) + cdma32 = initCDMA( + 32, + :ovsf + ) + cdma64 = initCDMA( + 64, + :ovsf + ) + # ---------------------------------------------------- + # --- Merging structures + # ---------------------------------------------------- + # Create a dictionnary to rule them all + waveforms = initWaveforms( + cdma4, + cdma16, + cdma32, + cdma64, + ); + + + # ---------------------------------------------------- + # --- BER main calculation + # ---------------------------------------------------- + # --- Init plot container + plt = plot(reuse=false,yscale=:log10,legend=:bottomleft); + # --- Iterative PSD generation + for (name,struc) in waveforms + # --- Calculate PSD for the configuration + ber = getBER(struc,mcs,snrVect,nbSymb,nbIt); + # --- Plot stuff + plot!(plt,snrVect,ber,label=struc.nbUsers); + end + # --- Adding metata do plot curve + xlabel!("SNR [dB]"); + ylabel!("Bit Error Rate"); + ylims!(1e-6,1); + display(plt); +end + + + +end + + + diff --git a/examples/example_cdma.jl b/examples/example_cdma.jl new file mode 100644 index 0000000..a1e5ac9 --- /dev/null +++ b/examples/example_cdma.jl @@ -0,0 +1,42 @@ +using DigitalComm + + +# ---------------------------------------------------- +# --- Parameters +# ---------------------------------------------------- +nbBits = 32768 +mcs = 4 +nbUsers = 16 +nbActiveUsers = 16 + +# ---------------------------------------------------- +# --- CDMA Generation +# ---------------------------------------------------- +# --- Binary sequence +bitSeq = genBitSequence(nbBits) +# Mapping +qamSeq = bitMappingQAM(mcs,bitSeq); +nbSymb = length(qamSeq) ÷ nbActiveUsers +# --- T/F matrix +qamMat = reshape(qamSeq,nbActiveUsers,nbSymb); +# --- Signal +sigId = cdmaSigGen(qamMat,nbUsers,:ovsf) + + +# ---------------------------------------------------- +# --- Ideal decoding +# ---------------------------------------------------- +# --- Decoding +qamRx = cdmaSigDecode(sigId,nbUsers,:ovsf,1:nbActiveUsers) +sir = getSIR(qamRx,qamMat) +println("SIR between Tx and Rx sequence (no noise) is $sir dB") + + +# ---------------------------------------------------- +# --- Decoding with noise +# ---------------------------------------------------- +snr = 30 +sigRx,_ = addNoise(sigId,snr) +qamRx = cdmaSigDecode(sigRx,nbUsers,:ovsf,1:nbActiveUsers) +sir = getSIR(qamRx,qamMat) +println("SIR between Tx and Rx sequence ($snr dB additive noise) is $sir dB") diff --git a/src/DigitalComm.jl b/src/DigitalComm.jl index 62da9c8..a8ed105 100644 --- a/src/DigitalComm.jl +++ b/src/DigitalComm.jl @@ -64,20 +64,15 @@ export sqrtRaisedCosine # ---------------------------------------------------- # --- Q function definition import SpecialFunctions.erfc -""" ---- -Returns the Q function used for Bit error rate computation in digital system - Q(x)= 1/2 erfc(x/sqrt(2)) -erfc is the Complexmplementary error function, i.e. the accurate version of 1-erf(x) for large x -erfc is inherited from DSP -# --- Syntax -y = qfunc(x) -# --- Input parameters +"""Returns the Q function used for Bit error rate computation in digital system \\ + Q(x)= 1/2 erfc(x/sqrt(2)) \\ +erfc is the Complexmplementary error function, i.e. the accurate version of 1-erf(x) for large x \\ +erfc is inherited from DSP\\ +y = qfunc(x) \\ +Input parameters - x: Input [Float64] -# --- Output parameters +Output parameters - y: Q(x)[Float64] -# --- -# v 1.0 - Robin Gerzaguet. """ function qFunc(x) return 1/2 * erfc.( x / sqrt(2)); @@ -87,21 +82,18 @@ export qFunc; """ ---- -Returns the Signal to interference ratio expressed in dB (or in linear) between a obersvation signal d(n) and a reference signal u(n) -The ratio is expressed as 10*log10( E[ || d(n) - u(n) || / E[||u(n)||^2] ) - with E the expectation wrt to time - The 2 vectors d and u should have the same length L -# --- Syntax - sir = getSIR( d, u , type="dB") -# --- Input parameter -- d : Observation signal [Array{Any}] -- u : Reference signal [Array{Any}] -- type: Output unit [String]: "dB" or "Linear" (default, "dB") -# --- Output parameters +Returns the Signal to interference ratio expressed in dB (or in linear) between a obersvation signal d(n) and a reference signal u(n) \\ +The ratio is expressed as 10*log10( E[ || d(n) - u(n) || / E[||u(n)||^2] ) \\ + with E the expectation wrt to time \\ +The 2 vectors d and u should have the same length L \\ + +sir = getSIR( d, u , type="dB")\\ +Input parameters +- d : Observation signal [`Array`] +- u : Reference signal [`Array`] +- type: Output unit [`String`]: "dB" or "Linear" (default, "dB") +Output parameters - sir : Signal to interference ratio in unit `type` -# --- -# v 1.0 - Robin Gerzaguet. """ function getSIR(d,u,type="dB") # --- Setting type @@ -233,6 +225,14 @@ include("./Waveforms/FBMC/fbmcSigDecode.jl"); export oqamDemapping export fbmcSigDecode +# CDMA Generation +include("./Waveforms/CDMA/cdmaSigGen.jl") +export initCDMA +export ovsf +export cdmaSigGen +export cdmaSigGen! +include("./Waveforms/CDMA/cdmaSigDecode.jl") +export cdmaSigDecode # --- Global waveform alias diff --git a/src/Waveforms/CDMA/cdmaSigDecode.jl b/src/Waveforms/CDMA/cdmaSigDecode.jl new file mode 100644 index 0000000..4e04b1e --- /dev/null +++ b/src/Waveforms/CDMA/cdmaSigDecode.jl @@ -0,0 +1,38 @@ + + +function cdmaSigDecode(sig::AbstractVector{T},nbUsers,code::Symbol,userMask=nothing) where T + # --- Define constant + nbChips = length(sig) + nbSymb = nbChips ÷ nbUsers + # --- Define code + if code == :ovsf + c = ovsf(nbUsers) + else + @error "Code $code is not supported" + end + if isnothing(userMask) + userMask = 1:nbUsers + end + nbActiveUsers = length(userMask) + qamRx = zeros(T,nbActiveUsers,nbSymb) + tmp = zeros(T,nbSymb) # To be optimized as a view of qamRx + for n ∈ eachindex(userMask) + despreading!(tmp,sig,nbUsers,c[:,userMask[n]]) + qamRx[n,:] .= tmp + end + return qamRx +end + +function despreading!(tmp,sig,nbUsers,code) + for n ∈ eachindex(tmp) + tmp[n] = 0 + for k ∈ 1 : nbUsers + tmp[n] += sig[(n-1)*nbUsers + k] * code[k] + end + tmp[n] = tmp[n] / nbUsers + end +end + + +# Dispatch with StrucCDMA +cdmaSigDecode(sig::AbstractVector,cdma::StrucCDMA) = cdmaSigDecode(sig,cdma.nbUsers,cdma.code,cdma.userMask) diff --git a/src/Waveforms/CDMA/cdmaSigGen.jl b/src/Waveforms/CDMA/cdmaSigGen.jl new file mode 100644 index 0000000..c4743be --- /dev/null +++ b/src/Waveforms/CDMA/cdmaSigGen.jl @@ -0,0 +1,106 @@ +struct StrucCDMA <: Waveform + nbUsers::Int # Number of user + code::Symbol # DSSS code + userMask::Vector{Int} +end + + +""" Instantiate a CDMA structure with a code of size `nbUsers`of type `code`(e.g :ovsf) and active for the user defined in `userMask` +""" +function initCDMA(nbUsers::Number,code::Symbol,userMask::Union{Nothing,AbstractVector}=nothing) + isnothing(userMask) && (userMask=1:nbUsers) + @assert length(userMask) ≤ nbUsers "Number of users should ($(length(nbActiveUser))) be ≤ to the code size ($nbUsers)" + return StrucCDMA(nbUsers,code,userMask) +end + +""" Orthogonal Variable Spreading Factor (OVSF) code generation +It generates N codes that are orthogonal and follows the OVSF code pattern +codes = ovsf(N,initState::UInt8=1) \\ +Input +- N = Number of generated codes (should be a power of 2) +- initState : Initial state value (default 1) +Output +- codes : Matrix of size code_size x N with type UInt8 +[1] Yuh-Shyan Chen and Ting-Lung Lin, "Code placement and replacement schemes for WCDMA Rotated-OVSF code tree management," in IEEE Transactions on Mobile Computing, vol. 5, no. 3, pp. 224-239, March 2006, doi: 10.1109/TMC.2006.30. +""" +function ovsf(N,initState::Int8=Int8(1)) + n = Int(log2(N)) + C = [initState] + for _ in 0 : n - 1 + newC = Int8[] + for c in eachrow(C) + c_0 = vcat(c,c) + c_1 = vcat(c,-c) + newC = _hcat_empty(newC,c_0) + newC = _hcat_empty(newC,c_1) + end + C = newC + end + return C +end + +# A custom concat operator that handle empty input vector +function _hcat_empty(a,b) + isempty(a) ? b : hcat(a,b) +end + + +""" Generates a Code Division Multiplexing Access signal from a Symbol matrix `qamMat` and using code family `code`. \\ +cdmaSigGen(qamMat::AbstractMatrix{T},nbUsers::Number,code::Symbol,userMask=nothing) \\ +Input parameters +- qamMat : Matrix of symbols of size nbActiveUser x nbSymb. Each line corresponds to a user stream and there is at least nbActiveUser colunm. nbActiveUser should be ≤ than the number of code we have +- nbUsers : Maximal number of user that can be multiplexed. Used for code generation +- code : Type of code used as a Symbol. We support `:ovsf` +- userMask: Optional parameter, a vector of the code used. Should be of size nbActiveUser. For example, if we have 16 max users but we only want to encode 1000 symbols for user 2 and user 12, we should call `cdmaSigGen` with a matrix `qamMat` of size (1000,2), `nbUsers` = 16 and `userMask` = [2;12] +""" +function cdmaSigGen!(sigOut::AbstractVector,qamMat::AbstractMatrix{T},nbUsers::Number,code::Symbol,userMask=nothing) where T + # ---------------------------------------------------- + # --- Code generation + # ---------------------------------------------------- + if code == :ovsf + # --- Generate the code base + c = ovsf(nbUsers) + else + @error "Code $code is unsupported. We currently inly support OVSF" + end + nbActiveUser = size(qamMat,1) + nbSymb = size(qamMat,2) + # Check we can encode users (more codes than uers) + @assert nbActiveUser ≤ nbUsers "Number of active users ($nbActiveUser) should be lower than the code size ($nbUsers)." + # Check output is of enough size + @assert length(sigOut) == nbUsers * nbSymb "Size of output vector ($(length(sigOut)) does not match input size x code size ($(nbSymb)x$(nbUsers)= $(nbUsers*nbSymb))" + # Code selection + if isnothing(userMask) + # We use the first codes as codeset + userMask = 1 : nbActiveUser + end + # ---------------------------------------------------- + # --- Scramling + # ---------------------------------------------------- + for n = 1 : 1 : nbActiveUser + # Apply the spreading and accumulate + _spread_accum!(sigOut,qamMat[n,:],c[:,userMask[n]],nbUsers) + end + return sigOut +end +function cdmaSigGen(qamMat::AbstractMatrix{T},nbUsers::Number,code::Symbol,userMask=nothing) where T + sigOut = zeros(T,size(qamMat,2)*nbUsers) + cdmaSigGen!(sigOut,qamMat,nbUsers,code,userMask) +return sigOut +end + +""" Apply a spreading of input signal `seq` using `code` and accumulate the result in `tmp` +""" +function _spread_accum!(tmp,seq,code,sF) + @inbounds @simd for n ∈ eachindex(seq) + for k ∈ 1 : sF + tmp[(n-1)*sF + k] += seq[n] * code[k] + end + end +end + + +# Dispatch with StrucCDMA structure +cdmaSigGen(qamMat::AbstractMatrix,cdma::StrucCDMA) = cdmaSigGen(qamMat,cdma.nbUsers,cdma.code,cdma.userMask) +cdmaSigGen!(sigOut::AbstractVector,qamMat::AbstractMatrix,cdma::StrucCDMA) = cdmaSigGen!(sigOut,qamMat,cdma.N,cdma.code,cdma.userMask) + diff --git a/src/Waveforms/genSig.jl b/src/Waveforms/genSig.jl index b57accf..062527c 100644 --- a/src/Waveforms/genSig.jl +++ b/src/Waveforms/genSig.jl @@ -29,7 +29,9 @@ end function genSig(qamMat,struc::StrucFBMC) return fbmcSigGen(qamMat,struc); end - +function genSig(qamMat,cdma::StrucCDMA) + return cdmaSigGen(qamMat,cdma) +end """ @@ -62,7 +64,9 @@ end function decodeSig(signal,struc::StrucFBMC) return fbmcSigDecode(signal,struc); end - +function decodeSig(signal,struc::StrucCDMA) + return cdmaSigDecode(signal,struc) +end """ --- @@ -89,6 +93,8 @@ function getWaveformName(s::Waveform) name = "FBMC"; elseif typeof(s) == StrucBFOFDM name = "BFOFDM"; + elseif typeof(s) == StrucCDMA + name = "CDMA" end end diff --git a/test/test_waveforms.jl b/test/test_waveforms.jl index 55de3c6..f003683 100644 --- a/test/test_waveforms.jl +++ b/test/test_waveforms.jl @@ -25,89 +25,205 @@ nbSubcarriers = length(allocatedSubcarriers); # ---------------------------------------------------- # --- Init OFDM structure ofdm = initOFDM( - nFFT, # --- nFFT : FFT size - 72, # --- nCP : CP size - allocatedSubcarriers # --- allocatedSubcarriers : Subcarrier allocation - ); + 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 - ); + 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 - ); + 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 - ); + 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 - ); + 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 - ); + 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, - ); + scfdma, + ufofdm, + bfofdm, + wola, + fbmc, + ); for (name,struc) in waveforms - @testset "$name" begin - for mcs=[4,16,64,256] - nbBits = nbSymb * nbSubcarriers * Int(log2(mcs)); - # --- Binary sequence - bitSeq = genBitSequence(nbBits); - # Mapping - qamSeq = bitMappingQAM(mcs,bitSeq); - # --- T/F matrix - qamMat = reshape(qamSeq,nbSubcarriers,nbSymb); - # --- Signal - sigId = genSig(qamMat,struc); - # --- Waveform demodulator - qamDec = decodeSig(sigId,struc); - # --- Binary demapper - bitDec = bitDemappingQAM(mcs,qamDec[:]); - # --- BER measure - nbE = sum(xor.(bitDec,bitSeq)); - @test nbE == 0 - end - end + @testset "$name" begin + for mcs=[4,16,64,256] + nbBits = nbSymb * nbSubcarriers * Int(log2(mcs)); + # --- Binary sequence + bitSeq = genBitSequence(nbBits); + # Mapping + qamSeq = bitMappingQAM(mcs,bitSeq); + # --- T/F matrix + qamMat = reshape(qamSeq,nbSubcarriers,nbSymb); + # --- Signal + sigId = genSig(qamMat,struc); + # --- Waveform demodulator + qamDec = decodeSig(sigId,struc); + # --- Binary demapper + bitDec = bitDemappingQAM(mcs,qamDec[:]); + # --- BER measure + nbE = sum(xor.(bitDec,bitSeq)); + @test nbE == 0 + end + end end + + +@testset "OVSF CDMA " begin + # Testing OVSF code + for N = [4,8,16,64] + c = ovsf(N) + for cn ∈ 1 : N + for ck ∈ 1 : N + # --- Code correlation + γ = sum(c[cn,:] .* conj(c[ck,:]) ) + if cn == ck + # Autocorrelation + @test γ == N + else + # Zero correlation + @test γ == 0 + end + end + end + end +end + + +@testset "CDMA generator" begin + N = 16 + C = ovsf(N) + # --- Spreading + for n ∈ 1 : N + c = C[:,n] + # Check spreading with one as input, we should obtain the code + in = [1] + out = zeros(16) + DigitalComm._spread_accum!(out,in,c,N) + @test all(out .== c) + # Check that accumulation is Ok + DigitalComm._spread_accum!(out,in,c,N) + @test all(out .== 2 .*c) + end + # --- True generator + nS = 100 + qamMat = ones(N,nS) + sigId = cdmaSigGen(qamMat,N,:ovsf) + @test sigId isa Vector + @test length(sigId) == nS * N + for n = 1 : 1 : N + @test sigId[n] == sum(C[n,:]) + end + # --- Generate only user 8 + qamMat = ones(1,nS) # Equivalent to a one subcarrier OFDM system + sigId = cdmaSigGen(qamMat,N,:ovsf,[8]) + @test sigId isa Vector + @test length(sigId) == nS * N + for n = 1 : 1 : N + @test sigId[n] == C[n,8] + end + # Testing with struct + cdma = initCDMA(N,:ovsf,[8]) + @test cdma isa Waveform + @test cdma isa DigitalComm.StrucCDMA + sigId2 = cdmaSigGen(qamMat,cdma) + @test all(sigId2 .≈ sigId) +end + + +@testset "CDMA receiver" begin + nS = 32768 + N = 16 + mcs = 4 + nbSymb = nS ÷ N ÷ Int(log2(mcs)) + # Mapping + bitSeq = genBitSequence(nS); + qamSeq = bitMappingQAM(mcs,bitSeq); + # --- T/F matrix + qamMat = reshape(qamSeq,N,nbSymb); + sigId = cdmaSigGen(qamMat,N,:ovsf) + # Testing global decoding method + qamRx = cdmaSigDecode(sigId,N,:ovsf,1:N) + @test all(qamRx .≈ qamMat) + # Testing one user decoding + for n = 1 : 1 : N + qamRx = cdmaSigDecode(sigId,N,:ovsf,[n]) + @test all(qamRx[1,:] .≈ qamMat[n,:]) + end + # Testing with struct + cdma = initCDMA(N,:ovsf,[8]) + @test cdma isa Waveform + @test cdma isa DigitalComm.StrucCDMA + qamRx0 = cdmaSigDecode(sigId,N,:ovsf,[8]) + qamRx1 = cdmaSigDecode(sigId,cdma) + @test all(qamRx0 .≈ qamRx1) +end + + +@testset "CDMA through genSig/decodeSig" begin + nbSymb = 14 + nbUsers = 16 + cdma = initCDMA(nbUsers,:ovsf) + for mcs=[4,16,64,256] + nbBits = nbSymb * nbUsers * Int(log2(mcs)); + # --- Binary sequence + bitSeq = genBitSequence(nbBits); + # Mapping + qamSeq = bitMappingQAM(mcs,bitSeq); + # --- T/F matrix + qamMat = reshape(qamSeq,nbUsers,nbSymb); + # --- Signal + sigId = genSig(qamMat,cdma); + # --- Waveform demodulator + qamDec = decodeSig(sigId,cdma); + # --- Binary demapper + bitDec = bitDemappingQAM(mcs,qamDec[:]); + # --- BER measure + nbE = sum(xor.(bitDec,bitSeq)); + @test nbE == 0 + end +end