├── SFFT.m ├── ISFFT.m ├── demodOFDM.m ├── modOFDM.m ├── plotGraphs.m ├── equaliser.m ├── multipathChannel.m ├── dataGen.m └── main.m /SFFT.m: -------------------------------------------------------------------------------- 1 | function [outSig] = SFFT(inSig) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Performs The Symplectic Fast Fourier Transform 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % inSig Input N x M matrix to be transformed 10 | %-------------------------------------------------------------------------- 11 | % Function returns: 12 | % outSig Output N x M matrix 13 | %-------------------------------------------------------------------------- 14 | % 15 | % Author: Bradley Bates 16 | % University of Bristol, UK 17 | % email address: bb16177@bristol.ac.uk 18 | % May 2020 19 | % 20 | % Copyright (c) 2020, Bradley Bates 21 | % 22 | %-------------------------------------------------------------------------- 23 | 24 | [N, M] = size(inSig); % Calculate N and M 25 | outSig = sqrt(M/N) * ifft( fft(inSig, [], 1), [], 2); % Apply transform 26 | 27 | end -------------------------------------------------------------------------------- /ISFFT.m: -------------------------------------------------------------------------------- 1 | function [outSig] = ISFFT(inSig) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Performs Inverse Symplectic Fast Fourier Transform 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % inSig Input N x M matrix to be transformed 10 | %-------------------------------------------------------------------------- 11 | % Function returns: 12 | % outSig Output N x M matrix of doppler-Delay domain symbols 13 | %-------------------------------------------------------------------------- 14 | % 15 | % Author: Bradley Bates 16 | % University of Bristol, UK 17 | % email address: bb16177@bristol.ac.uk 18 | % May 2020 19 | % 20 | % Copyright (c) 2020, Bradley Bates 21 | % 22 | %-------------------------------------------------------------------------- 23 | 24 | [N, M] = size(inSig); % Calculate N and M 25 | outSig = sqrt(N/M) * fft( ifft(inSig, [], 1), [], 2); % Apply inverse transform 26 | 27 | end -------------------------------------------------------------------------------- /demodOFDM.m: -------------------------------------------------------------------------------- 1 | function [dataOut] = demodOFDM(dataIn,cpLen,ofdmSym) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Demodulates OFDM symbols into serial data 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Definition of input arguments 9 | % 10 | % dataIn Input data vector 11 | % cpLen Length of the cyclic prefix 12 | % ofdmSym No. of ofdm symbols per subframe 13 | % 14 | %-------------------------------------------------------------------------- 15 | % Function returns: 16 | % 17 | % dataOut Output time domain symbols 18 | % 19 | %-------------------------------------------------------------------------- 20 | % 21 | % Author: Bradley Bates 22 | % University of Bristol, UK 23 | % email address: bb16177@bristol.ac.uk 24 | % May 2020 25 | % 26 | % Code and algorithm originally from: 27 | % 28 | % Baher Mohammed (2020). OFDM signal generation, transmission and reception 29 | % (https://www.mathworks.com/matlabcentral/fileexchange/28368-ofdm-signal-generation-transmission-and-reception) 30 | % MATLAB Central File Exchange. Retrieved May 10, 2020. 31 | % 32 | %-------------------------------------------------------------------------- 33 | 34 | % OFDM receiever reshapes serial data to parallel 35 | parallelRx = reshape(dataIn, numel(dataIn)/ofdmSym, ofdmSym); 36 | % Removing the cyclic Prefix 37 | parallelRx(1:(cpLen), :) = []; 38 | 39 | % Perform FFT 40 | dataOut = fft(parallelRx,[],2); 41 | 42 | 43 | end -------------------------------------------------------------------------------- /modOFDM.m: -------------------------------------------------------------------------------- 1 | function [dataOut] = modOFDM(dataIn,numSC,cpLen,ofdmSym) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Modulates random input data into OFDM symbols 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input Arguments: 9 | % dataIn Input data vector 10 | % numSC The number of subcarriers used 11 | % cpLen Length of the cyclic prefix 12 | % ofdmSym No. of ofdm symbols per subframe 13 | %-------------------------------------------------------------------------- 14 | % Function returns: 15 | % dataOut Output OFDM symbols 16 | %-------------------------------------------------------------------------- 17 | % 18 | % Author: Bradley Bates 19 | % University of Bristol, UK 20 | % email address: bb16177@bristol.ac.uk 21 | % May 2020 22 | % 23 | % Code and algorithm originally from: 24 | % 25 | % Baher Mohammed (2020). OFDM signal generation, transmission and reception 26 | % (https://www.mathworks.com/matlabcentral/fileexchange/28368-ofdm-signal-generation-transmission-and-reception) 27 | % MATLAB Central File Exchange. Retrieved May 10, 2020. 28 | % 29 | %-------------------------------------------------------------------------- 30 | 31 | % Calculate variables 32 | cyclicPrefix_start = numSC - cpLen; 33 | 34 | % Perform IFFT 35 | ifftSubcarrier = ifft(dataIn,[],2); 36 | 37 | %Finding cyclic prefix for each subcarrier 38 | for i=1:cpLen 39 | for j=1:ofdmSym 40 | cyclicPrefix_data(i,j) = ifftSubcarrier(i+cyclicPrefix_start,j); 41 | end 42 | end 43 | 44 | % Add cyclic prefix to the data 45 | appendedCP = vertcat(cyclicPrefix_data, ifftSubcarrier); 46 | 47 | % Convert to serial 48 | dataOut = reshape(appendedCP,[numel(appendedCP),1]); 49 | 50 | 51 | 52 | end 53 | -------------------------------------------------------------------------------- /plotGraphs.m: -------------------------------------------------------------------------------- 1 | function [] = plotGraphs(berOFDM, berCOFDM, berOTFS, berCOTFS, M, numSC, EbNo) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Plots and formats BER graphs of the input BER vectors 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % 10 | % berOFDM OFDM ber vector 11 | % berCOFDM coded-OFDM ber vector 12 | % berOTFS OTFS ber vector 13 | % berCOTFS coded-OFDM ber vector 14 | % M Modulation order 15 | % numSC no. subcarriers used in system 16 | % 17 | %-------------------------------------------------------------------------- 18 | % Function returns: 19 | % 20 | % void 21 | % 22 | %-------------------------------------------------------------------------- 23 | % 24 | % Author: Bradley Bates 25 | % University of Bristol, UK 26 | % email address: bb16177@bristol.ac.uk 27 | % May 2020 28 | % 29 | % Copyright (c) 2020, Bradley Bates 30 | % 31 | %-------------------------------------------------------------------------- 32 | 33 | % Set error rates of 0 to a very low value which can be plotted on graph 34 | berCOFDM(~berCOFDM)=1e-12; 35 | berCOTFS(~berCOTFS)=1e-12; 36 | 37 | % Plotting 38 | figure 39 | 40 | % Plot non-coded results 41 | semilogy(EbNo,berOFDM(:,1),'-g'); %Plot simulated BER w/ OFDM 42 | hold on; 43 | semilogy(EbNo,berOTFS(:,1),'-r'); %Plot simulated BER w/ OTFS 44 | % Plot coded results 45 | semilogy(EbNo,berCOFDM(:,1),'--g'); %Plot simulated BER w/ C-OFDM 46 | semilogy(EbNo,berCOTFS(:,1),'--r'); %Plot simulated BER w/ C-OTFS 47 | 48 | % Formatting graph 49 | axis([0 30 0.0005 0.5]) 50 | title(['BER for ', num2str(M), '-QAM in Wideband Rayleigh Fading with ', num2str(numSC),' Subcarriers']); 51 | ylabel('Bit Error Rate'); 52 | xlabel('EbNo (dB)'); 53 | legend('OFDM', 'OTFS','C-OFDM','C-OTFS'); 54 | grid on; 55 | hold off; 56 | 57 | 58 | end -------------------------------------------------------------------------------- /equaliser.m: -------------------------------------------------------------------------------- 1 | function [eqSig] = equaliser(rxSig,fadedSig,txSig,ofdmSym) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Equalises a faded signal 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % 10 | % rxSig The received faded signal w/ noise applied 11 | % fadedSig The received faded signal, NO noise 12 | % txSig Transmitted signal prior to channel 13 | % ofdmSym Totol ofdm symbols per subframe 14 | % 15 | %-------------------------------------------------------------------------- 16 | % Function returns: 17 | % 18 | % eqSig The equalised output signal (serial vector) 19 | % 20 | %-------------------------------------------------------------------------- 21 | % 22 | % Author: Bradley Bates 23 | % University of Bristol, UK 24 | % email address: bb16177@bristol.ac.uk 25 | % May 2020 26 | % 27 | % Copyright (c) 2020, Bradley Bates 28 | % 29 | %-------------------------------------------------------------------------- 30 | 31 | % Input parameters 32 | pilotSpacing = 4; % Subcarrier sampling period (4 is best) 33 | noSamples = numel(rxSig)/ofdmSym; % No. of times the channel is sampled 34 | numSC = pow2(floor(log2(noSamples))); % Calc. no. of OFDM subcarrier 35 | 36 | % Reformat input data into a matrix to make sampling easier 37 | fadedSig_matrix = reshape(fadedSig, [noSamples,ofdmSym]); 38 | txSig_matrix = reshape(txSig, [noSamples,ofdmSym]); 39 | 40 | % Remove cyclic prefix as do no need to equalise it 41 | fadedSig_matrix(1:(noSamples-numSC),:) = []; % Remove cp 42 | txSig_matrix(1:(noSamples-numSC),:) = []; % Remove cp 43 | 44 | % Sample signal 45 | h = zeros(size(txSig_matrix)); % Pre allocate matrix 46 | for i = 1:size(txSig_matrix,1) % Loop rows 47 | for j = 1:size(txSig_matrix,2) % Loop Columns 48 | % Sample every pilotSpacing subcarrier (incuding first and last subcarriers) 49 | if i==1 50 | sample(i,j) = fadedSig_matrix(i,j)./txSig_matrix(i,j); 51 | elseif 0 == mod(i,pilotSpacing) 52 | sample(i/pilotSpacing+1,j) = fadedSig_matrix(i,j)./txSig_matrix(i,j); 53 | end 54 | end 55 | end 56 | 57 | % Linearly Interpolate samples between subcarriers 58 | interpPoints = ( (1+(1/pilotSpacing)) : (1/pilotSpacing) : size(sample,1) );% Calc. points to interpolate 59 | for j = 1:size(txSig_matrix,2) 60 | h(:,j) = interp1(sample(:,j),interpPoints); 61 | end 62 | 63 | % Keep only 1st, 7th and 14th samples per carrier 64 | h1 = [h(:,1)';h(:,7)';h(:,14)']'; 65 | 66 | % Linearly Interpolate samples between symbols 67 | interpPoints1 = ( 1 : (1/6) : 2 ); % Calc. points to interpolate 68 | interpPoints2 = ( (2+(1/7)) : (1/7) : 3 ); 69 | for i = 1:size(txSig_matrix,1) 70 | h17(i,:) = interp1(h1(i,:),interpPoints1); % Interpolate 1-7 71 | h714(i,:) = interp1(h1(i,:),interpPoints2); % interpolate 7-14 72 | end 73 | 74 | % Concatenate matracies 75 | h = [h17';h714']'; 76 | 77 | % Set eq of CP carriers to same as 1st carrier 78 | for k = 1:(noSamples-numSC) 79 | h = [h(1,:);h]; 80 | end 81 | 82 | % Convert back into serial 83 | H = reshape(h,[numel(h),1]); 84 | H(isnan(H)) = 1; % Set all NaN's to 1 85 | 86 | % Equalise the signal 87 | eqSig = rxSig ./ H; 88 | eqSig(isnan(eqSig))=0; % Set all NaN's to 0 89 | 90 | end -------------------------------------------------------------------------------- /multipathChannel.m: -------------------------------------------------------------------------------- 1 | function [outSig] = multipathChannel(cpSize, delta_f, inSig, velocity) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Generates and encodes random binary data 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % 10 | % cpSize Size of the cyclic prefix 11 | % delta_f OFDM subcarrier spacing (Hz) 12 | % inSig Input signal dimensions used to generate channel dimensions 13 | % totalBits The approximate total bits to be simulated by the system 14 | % velocity Channel mobility in km/hr 15 | % 16 | %-------------------------------------------------------------------------- 17 | % Function returns: 18 | % 19 | % outSig Channel impulse response (serial vector) 20 | % 21 | %-------------------------------------------------------------------------- 22 | % 23 | % Author: Bradley Bates 24 | % University of Bristol, UK 25 | % email address: bb16177@bristol.ac.uk 26 | % May 2020 27 | % 28 | % Copyright (c) 2020, Bradley Bates 29 | % 30 | %-------------------------------------------------------------------------- 31 | 32 | 33 | % Create N x M channel matrix 34 | [N, M]= size(inSig'); % Size of inSig is used to create channel model 35 | n = zeros(1,N); % delay_Doppler rows (doppler) 36 | m = zeros(1,M); % delay_Doppler cols (delay) 37 | H = transpose(n).*m; % Create matrix 38 | 39 | % Generate Channel Parameter 40 | maxDelayspread = 0.5*((cpSize)/delta_f); % Calculate max delay spread with 1/2 rule pf thumb 41 | L = round(2*maxDelayspread * M*delta_f); % Calculate necesary paths from bandwidth 42 | step = maxDelayspread/L; % calculate difference between delays 43 | pathDelays = (0:step:maxDelayspread); % Discrete even delays of L-path channel 44 | range shuffle; % Shuffle random no. generator 45 | avgPathGains_dB = -(randi([3,7],[L,1])); % Generate random path gains in dB 46 | avgPathGains = 10.^(0.1*avgPathGains_dB); % Convert to linear 47 | 48 | % Calculate Max Doppler Shift 49 | v = velocity*1e3/3600; % Mobile speed (m/s) 50 | fc = 3.5e9; % Carrier frequency 51 | fd = round(v*fc/physconst('lightspeed'));% Maximum Doppler shift to nearest Hz 52 | 53 | % Generate doppler spreads w/ Jake's model 54 | for l=0:L-1 55 | Vi(l+1) = fd* cos( (2*pi*l)/(L-1) ); 56 | end 57 | 58 | % Initialize channel variables 59 | T = 1/delta_f; % unextended OFDM symbol period 60 | Ts = (1+cpSize)/delta_f; % OFDM symbol period) 61 | Ti = pathDelays; % Path delays 62 | hi = avgPathGains; % Path gains 63 | 64 | % Create matrix representation of channel 65 | for m=1:M % Loop along the rows 66 | for n=1:N % Loop down the cols 67 | 68 | for x=1:L % Loop to sum terms in the channel memory 69 | % Define terms of model 70 | expTerm = (-2*1i*(pi)) * ((m+M/2).*delta_f.*Ti(x) - Vi(x).*(n).*Ts); 71 | hiPrime = hi(x)*(1 + 1i*(pi).*Vi(x).*T); 72 | % Produce channel impulse response model 73 | H(n, m) = H(n, m) + exp(expTerm) * hiPrime; 74 | 75 | end 76 | end 77 | 78 | end 79 | 80 | 81 | % % 3D plot of channnel model 82 | % figure 83 | % absH = 10*log10(abs(H)); 84 | % mesh(absH) 85 | % surf(absH) 86 | % colormap(jet) % change color map 87 | % shading interp % interpolate colors across lines and faces 88 | % hold on; 89 | % title(['Time-Frequency Plot of The Fading Channel']); 90 | % xlabel('Frequency (MHz)'); 91 | % xticks([8 142 274 408 540]) 92 | % xticklabels({'3.496','3.498','3.500','3.502','3.504'}) 93 | % ylabel('Time (ms)'); 94 | % yticks([0 14 28 42 56 70 84 98 112 126 140]) 95 | % yticklabels({'0','1','2','3','4','5','6','7','8','9','10'}) 96 | % zlabel('Power (dB'); 97 | % hold off; 98 | 99 | 100 | % Convert to serial 101 | outSig = reshape(H',[n*m,1]); 102 | end 103 | -------------------------------------------------------------------------------- /dataGen.m: -------------------------------------------------------------------------------- 1 | function [dataIn, dataBits_in, codedData_in, packetSize, numPackets, numCB] = dataGen(k,numDC,ofdmSym,totalBits,codeRate, ldpcEncoder) 2 | 3 | %-------------------------------------------------------------------------- 4 | % 5 | % Generates and encodes random binary data 6 | % 7 | %-------------------------------------------------------------------------- 8 | % Input arguments: 9 | % 10 | % k Bits/Symbol 11 | % numDC Number of data subcarriers 12 | % ofdmSym Totol ofdm symbols per subframe 13 | % totalBits The approximate total bits to be simulated by the system 14 | % codeRate LDPC code rate 15 | % ldpcEncoder LDPC encode system object 16 | % 17 | %-------------------------------------------------------------------------- 18 | % Function returns: 19 | % 20 | % dataIn The input encoded data to the modulator 21 | % dataBits_in The binary generated initial data before coding 22 | % codedData_in The binary codewords 23 | % packetSize No. of subframes / "packet" 24 | % numPackets Number of packets required to satisfy totalBits 25 | % numCB No. of code blocks / "subframe" 26 | % 27 | %-------------------------------------------------------------------------- 28 | % 29 | % Author: Bradley Bates 30 | % University of Bristol, UK 31 | % email address: bb16177@bristol.ac.uk 32 | % May 2020 33 | % 34 | % Copyright (c) 2020, Bradley Bates 35 | % 36 | %-------------------------------------------------------------------------- 37 | 38 | % Calculate subframe size 39 | % Initialise information about frames to be transmitted 40 | packetSize = 1; % No. of subframes / "packet" 41 | numCB = 1; % No. of code blocks / "subframe" 42 | noCodedbits = 64800; % Codeword length 43 | 44 | % Calculate exact no. of frames and bits required for simulation 45 | subframeSize = [k*numDC*ofdmSym 1]; % Calculate size of a subframe 46 | maxSubframes = ceil(totalBits./subframeSize(1)); % Total no. of subframes to be transmitted 47 | 48 | % Determine number of code block and number of subframes/packet 49 | if subframeSize(1) == noCodedbits % If same size do nothing 50 | numCB = 1; 51 | packetSize = 1; 52 | 53 | elseif subframeSize(1) > noCodedbits % Match for when subframe > codeword 54 | [numCB, packetSize] = rat(subframeSize(1)./ noCodedbits,1e-1); 55 | 56 | elseif subframeSize(1) < noCodedbits % Match for when subframe < codeword 57 | [packetSize, numCB] = rat(noCodedbits./ subframeSize(1),1e-1); 58 | end 59 | 60 | % Ensure theres always enough data bit capacity 61 | while numCB*noCodedbits >= subframeSize(1)*packetSize 62 | packetSize = packetSize + 1; 63 | % Divide both by 2 if possible 64 | if (rem(numCB,2) == 0) && (rem(packetSize,2) == 0) && numCB*noCodedbits <= subframeSize(1)*packetSize 65 | packetSize = packetSize./2; 66 | numCB = numCB./2; 67 | end 68 | end 69 | 70 | % Calculate the pad bits required to round up to the nearest whole subframe 71 | padBits = zeros((subframeSize(1)*packetSize - numCB*noCodedbits),1);% Calculate the number of pad bits 72 | numPackets = round(maxSubframes./packetSize); % Total no. of "packets" to be transmitted 73 | numPackets(~numPackets)=1; % If 0 packets set to 1 74 | 75 | % Generate Random Input Data 76 | range shuffle; % Shuffle random no. generator 77 | codedData_in = []; % Initialse arrays 78 | dataBits_in = []; 79 | for q = 1:numCB 80 | dataBits = randi([0,1],[noCodedbits*codeRate,1]); % Generate binary datafor each frame of the burst 81 | dataBits_in = [dataBits_in;dataBits]; % Concatenate binary data 82 | codedData_in = [codedData_in; ldpcEncoder(dataBits)]; % Generate LDPC codeblocks 83 | end 84 | paddedData_in = [codedData_in; padBits]; % Append pad bits to coded bits 85 | dataIn = randintrlv(paddedData_in,4831); % Interleave paddedData randdeintrlv 86 | 87 | 88 | % Print info about data output 89 | % fprintf(['\n',num2str(numCB),' code block(s)\n', num2str(packetSize), ' subframes/packet \n']) 90 | % fprintf([ num2str(numel(padBits)),' pad bits out of ', num2str((subframeSize(1)*packetSize)),' data bits = ', num2str(100*(numel(padBits)/(subframeSize(1)*packetSize))),' percent pad bits!\n']) 91 | % fprintf(['Total packets: ', num2str(numPackets),'\n']) 92 | % fprintf(['Total bits: ', num2str(numPackets*packetSize*(subframeSize(1))),'\n']) 93 | 94 | end -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | clear; 2 | close all; 3 | 4 | %-------------------------------------------------------------------------- 5 | % 6 | % This code forms a simulation of a wideband wireless communications system 7 | % in multipath fading. It simulates: OFDM, OTFS, coded-OFDM and coded-OTFS 8 | % 9 | % The following files are required: 10 | % dataGen.m 11 | % multipathChannel.m 12 | % modOFDM.m 13 | % demodOFDM.m 14 | % ISFFT.m 15 | % SFFT.m 16 | % equaliser.m 17 | % plotGraphs.m 18 | % 19 | %-------------------------------------------------------------------------- 20 | % 21 | % Author: Bradley Bates 22 | % University of Bristol, UK 23 | % email address: bb16177@bristol.ac.uk 24 | % May 2020 25 | % 26 | % Copyright (c) 2020, Bradley Bates 27 | % 28 | %-------------------------------------------------------------------------- 29 | 30 | %-------------------------------------------------------------------------- 31 | % Define simulation parameters 32 | %-------------------------------------------------------------------------- 33 | M = 16; % Modulation alphabet 34 | k = log2(M); % Bits/symbol 35 | cpSize = 0.07; % OFDM cyclic prefix size 36 | scs = 15e3; % Subcarrier spacing Hz 37 | Bw = 10e6; % System bandwidth Hz 38 | ofdmSym = 14; % No. OFDM symbols / subframe 39 | EbNo = (-3:1:30)'; % Range of energy/bit to noise power ratio 40 | velocity = 120; % Velocity of mobile rx relative tx km/hr 41 | codeRate = 2/4; % FEC code rate used 42 | maxIterations = 25; % Set maximum no. of iterations for LDPC decoder 43 | totalBits = 1e6; % The approx. total no. of bits simulated 44 | repeats = 1; % Number of simulation repetitions 45 | 46 | 47 | %-------------------------------------------------------------------------- 48 | % Initialise Simulation Components 49 | %-------------------------------------------------------------------------- 50 | 51 | % Initialise OFDM Mod/Demod variables 52 | numSC = pow2(ceil(log2(Bw/scs))); % Calc. nearest base-2 no. of OFDM subcarriers 53 | cpLen = floor(cpSize * numSC); % Calc. cyclic prefix length 54 | numDC = (numSC - 12); % Calc. number of data carriers 55 | 56 | % Initialise the AWGN channel 57 | awgnChannel = comm.AWGNChannel('NoiseMethod','Variance', 'VarianceSource','Input port'); 58 | errorRate = comm.ErrorRate('ResetInputPort',true); 59 | errorRate1 = comm.ErrorRate('ResetInputPort',true); 60 | 61 | % Initialise the LDPC coder/decoder 62 | parityCheck_matrix = dvbs2ldpc(codeRate); % Generate DVB-S.2 paraity check matrix 63 | ldpcEncoder = comm.LDPCEncoder(parityCheck_matrix); % Create encoder system object 64 | ldpcDecoder = comm.LDPCDecoder(parityCheck_matrix); % Create decoder system object 65 | ldpcDecoder.MaximumIterationCount = maxIterations; % Assign decoder's maximum iterations 66 | noCodedbits = size(parityCheck_matrix,2); % Find the Codeword length 67 | 68 | % Create Vectors for storing error data 69 | berOFDM = zeros(length(EbNo),3); berCOFDM = zeros(length(EbNo),3); berOTFS = zeros(length(EbNo),3); berCOTFS = zeros(length(EbNo),3); 70 | errorStats_coded = zeros(1,3); errorStats_uncoded = zeros(1,3); 71 | 72 | for repetition=1:repeats % Repeat simulation multiple times with a unqique channel for each repeat 73 | 74 | % Generate and Encode data 75 | [dataIn, dataBits_in, codedData_in, packetSize, numPackets, numCB] = dataGen(k,numDC,ofdmSym,totalBits,codeRate,ldpcEncoder); 76 | 77 | % Generate Rayleigh Fading Channel Impulse Response 78 | txSig_size = zeros((numSC+cpLen),ofdmSym); % Assign the size of the channel 79 | rayChan = multipathChannel(cpSize, scs, txSig_size, velocity); % Create fading channel impulse response 80 | 81 | % QAM Modulator 82 | qamTx = qammod(dataIn,M,'InputType','bit','UnitAveragePower',true); % Apply QAM modulation 83 | parallelTx = reshape(qamTx,[numDC,ofdmSym*packetSize]); % Convert to parallel 84 | 85 | % Add nulls at index 1 86 | guardbandTx = [zeros(1,ofdmSym*packetSize); parallelTx]; 87 | % Add 11 nulls around DC 88 | guardbandTx = [guardbandTx(1:(numDC/2),:); zeros(11,ofdmSym*packetSize); guardbandTx((numDC/2)+1:end,:)]; 89 | 90 | 91 | %-------------------------------------------------------------------------- 92 | % OFDM BER Calculation 93 | %-------------------------------------------------------------------------- 94 | 95 | % Calculate SNR 96 | snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC))); 97 | 98 | % Multicarrier Modulation 99 | frameBuffer = guardbandTx; % Create a 'buffer' so subframes can be individually modulated 100 | txframeBuffer = []; % Initilaise matrix 101 | for w = 1:packetSize 102 | ofdmTx = modOFDM(frameBuffer(:,1:ofdmSym),numSC,cpLen,ofdmSym); % Apply OFDM modulation to a subframe of data 103 | frameBuffer(:, 1:ofdmSym) = []; % Delete modulated data from frameBuffer 104 | txframeBuffer = [txframeBuffer;ofdmTx]; % Add modulated subframe to transmit buffer 105 | end 106 | 107 | 108 | % Loop through different values of EbNo 109 | for m = 1:length(EbNo) 110 | % Loop through the of packets to be transmitted 111 | for j = 1:numPackets 112 | rxframeBuffer = []; % Initialise matrix 113 | 114 | % Transmit each subframe individually 115 | for u = 1:packetSize 116 | 117 | % Remove next subframe from the transmit buffer 118 | txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) ); 119 | 120 | % Apply Channel to input signal 121 | fadedSig = zeros(size(txSig)); % Pre-allocate vector size 122 | for i = 1:size(txSig,1) % Perform elementwise... 123 | for j = 1:size(txSig,2) % ...matrix multiplication 124 | fadedSig(i,j) = txSig(i,j).*rayChan(i,j); 125 | end 126 | end 127 | 128 | % AWGN Channel 129 | release(awgnChannel); 130 | powerDB = 10*log10(var(fadedSig)); % Calculate Tx signal power 131 | noiseVar = 10.^(0.1*(powerDB-snr(m))); % Calculate the noise variance 132 | rxSig = awgnChannel(fadedSig,noiseVar); % Pass the signal through a noisy channel 133 | 134 | % Equalisation 135 | eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym); 136 | 137 | % Demodulation 138 | rxSubframe = demodOFDM(eqSig,cpLen,ofdmSym); % Apply OFDM demodulation 139 | rxframeBuffer = [rxframeBuffer';rxSubframe']'; % Store demodulated subframe in rx buffer 140 | end 141 | % Remove all null carriers 142 | parallelRx = rxframeBuffer; 143 | parallelRx((numDC/2)+1:(numDC/2)+11, :) = []; % Remove nulls around the DC input 144 | parallelRx(1:1, :) = []; % Remove nulls at index 1 145 | qamRx = reshape(parallelRx,[numel(parallelRx),1]);% Convert to serial 146 | 147 | % Uncoded demodulation of entire packet 148 | dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);% Apply QAM demodulation 149 | codedData_out = randdeintrlv(dataOut,4831); % De-interleave data 150 | codedData_out(numel(codedData_in)+1:end) = []; % Remove pad bits 151 | errorStats_uncoded = errorRate(codedData_in,codedData_out,0); % Collect error statistics 152 | 153 | % Coded demodulation of entire packet 154 | powerDB = 10*log10(var(qamRx)); % Calculate Rx signal power 155 | noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC))))); % Calculate the noise variance 156 | dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);% Apply QAM demodulation 157 | codedData_out1 = randdeintrlv(dataOut,4831); % De-interleave data 158 | codedData_out1(numel(codedData_in)+1:end) = []; % Remove pad bits 159 | 160 | % Decode individual code blocks 161 | dataBits_out = []; % Initialise matrix 162 | dataOut_buffer = codedData_out1; 163 | for q = 1:numCB 164 | dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))]; % Decode data & add it to the data bits out matrix 165 | dataOut_buffer(1:noCodedbits) = []; % Delete decoded data from buffer 166 | end 167 | dataBits_out = double(dataBits_out); % Convert to a double compatible w/ errorStats 168 | errorStats_coded = errorRate1(dataBits_in,dataBits_out,0); % Collect error statistics 169 | 170 | end 171 | berOFDM(m,:) = errorStats_uncoded; % Save uncoded BER data 172 | berCOFDM(m,:) = errorStats_coded; % Save coded BER data 173 | errorStats_uncoded = errorRate(codedData_in,codedData_out,1); % Reset the error rate calculator 174 | errorStats_coded = errorRate1(dataBits_in,dataBits_out,1); % Reset the error rate calculator 175 | 176 | end 177 | 178 | 179 | %-------------------------------------------------------------------------- 180 | % OTFS BER Calculation 181 | %-------------------------------------------------------------------------- 182 | 183 | % Calculate SNR 184 | snr = EbNo + 10*log10(codeRate*k) + 10*log10(numDC/((numSC))) + 10*log10(sqrt(ofdmSym)); 185 | 186 | % Multicarrier Modulation 187 | frameBuffer = guardbandTx; % Create a 'buffer' so subframes can be individually modulated 188 | txframeBuffer = []; % Initilaise matrix 189 | for w = 1:packetSize 190 | otfsTx = ISFFT(frameBuffer(:,1:ofdmSym)); % Apply OTFS modulation to a subframe of data 191 | ofdmTx = modOFDM(otfsTx,numSC,cpLen,ofdmSym); % Apply OFDM modulation 192 | frameBuffer(:, 1:ofdmSym) = []; % Delete modulated data from frameBuffer 193 | txframeBuffer = [txframeBuffer;ofdmTx]; % Add modulated subframe to transmit buffer 194 | end 195 | 196 | % Loop through different values of EbNo 197 | for m = 1:length(EbNo) 198 | % Loop through the of packets to be transmitted 199 | for j = 1:numPackets 200 | rxframeBuffer = []; % Initialise matrix 201 | 202 | % Transmit each subframe individually 203 | for u = 1:packetSize 204 | 205 | % Remove next subframe from the transmit buffer 206 | txSig = txframeBuffer( ((u-1)*numel(ofdmTx)+1) : u*numel(ofdmTx) ); 207 | 208 | % Apply Channel to input signal 209 | fadedSig = zeros(size(txSig)); % Pre-allocate vector size 210 | for i = 1:size(txSig,1) % Perform elementwise... 211 | for j = 1:size(txSig,2) % ...matrix multiplication 212 | fadedSig(i,j) = txSig(i,j).*rayChan(i,j); 213 | end 214 | end 215 | 216 | % AWGN Channel 217 | release(awgnChannel); 218 | powerDB = 10*log10(var(fadedSig)); % Calculate Tx signal power 219 | noiseVar = 10.^(0.1*(powerDB-snr(m))); % Calculate the noise variance 220 | rxSig = awgnChannel(fadedSig,noiseVar); % Pass the signal through a noisy channel 221 | 222 | % Equalisation 223 | eqSig = equaliser(rxSig,fadedSig,txSig,ofdmSym); 224 | 225 | % Demodulation 226 | otfsRx = demodOFDM(eqSig,cpLen,ofdmSym); % Apply OFDM demodulation 227 | rxSubframe = SFFT(otfsRx); % Apply OTFS demodulation 228 | rxframeBuffer = [rxframeBuffer';rxSubframe']'; % Store demodulated subframe in rx buffer 229 | end 230 | % Remove all null carriers 231 | parallelRx = rxframeBuffer; 232 | parallelRx((numDC/2)+1:(numDC/2)+11, :) = []; % Remove nulls around the DC input 233 | parallelRx(1:1, :) = []; % Remove nulls at index 1 234 | qamRx = reshape(parallelRx,[numel(parallelRx),1]); % Convert to serial 235 | 236 | % Uncoded demodulation of entire packet 237 | dataOut = qamdemod(qamRx,M,'OutputType','bit','UnitAveragePower',true);% Apply QAM demodulation 238 | codedData_out = randdeintrlv(dataOut,4831); % De-interleave data 239 | codedData_out(numel(codedData_in)+1:end) = []; % Remove pad bits 240 | errorStats_uncoded = errorRate(codedData_in,codedData_out,0); % Collect error statistics 241 | 242 | 243 | % Coded demodulation of entire packet 244 | powerDB = 10*log10(var(qamRx)); % Calculate Rx signal power 245 | noiseVar = 10.^(0.1*(powerDB-(EbNo(m) + 10*log10(codeRate*k) - 10*log10(sqrt(numDC))))); % Calculate the noise variance 246 | dataOut = qamdemod(qamRx,M,'OutputType', 'approxllr','UnitAveragePower',true,'NoiseVariance',noiseVar);% Apply QAM demodulation 247 | codedData_out1 = randdeintrlv(dataOut,4831); % De-interleave data 248 | codedData_out1(numel(codedData_in)+1:end) = []; % Remove pad bits 249 | 250 | % Decode individual code blocks 251 | dataBits_out = []; % Initialise matrix 252 | dataOut_buffer = codedData_out1; 253 | for q = 1:numCB 254 | dataBits_out = [dataBits_out;ldpcDecoder(dataOut_buffer(1:noCodedbits))]; % Decode data & add it to the data bits out matrix 255 | dataOut_buffer(1:noCodedbits) = []; % Delete decoded data from buffer 256 | end 257 | dataBits_out = double(dataBits_out); % Convert to a double compatible w/ errorStats 258 | errorStats_coded = errorRate1(dataBits_in,dataBits_out,0); % Collect error statistics 259 | 260 | end 261 | berOTFS(m,:) = errorStats_uncoded; % Save uncoded BER data 262 | berCOTFS(m,:) = errorStats_coded; % Save coded BER data 263 | errorStats_uncoded = errorRate(codedData_in,codedData_out,1); % Reset the error rate calculator 264 | errorStats_coded = errorRate1(dataBits_in,dataBits_out,1); % Reset the error rate calculator 265 | 266 | end 267 | 268 | end 269 | 270 | %-------------------------------------------------------------------------- 271 | % Figures 272 | %-------------------------------------------------------------------------- 273 | 274 | % Plot BER / EbNo curves 275 | plotGraphs(berOFDM, berCOFDM, berOTFS, berCOTFS, M, numSC, EbNo); 276 | 277 | --------------------------------------------------------------------------------