├── Get_Trellis.m ├── README.md ├── RUN_ME.m ├── SOVA.m ├── SOVA_END.m └── ldiv2.m /Get_Trellis.m: -------------------------------------------------------------------------------- 1 | % Trellis for the Convolutional encoder with generator matrix given by 2 | % [1 (1+D^2)/(1+D+D^2)] 3 | function [Prev_State,Prev_Ip_trans,Outputs_prev,Prev_State_trans,Next_State,Outputs_next]= Get_Trellis() 4 | Outputs_prev = [1,4; 2,3; 1,4; 2,3]; % ex: row 1 corresponds to branch metrices that converge to state 1, similarly row 2,3,4 5 | Prev_State = [1,2; 4,3; 2,1; 3,4]; % row 1 corresponds to the previous states corresponding to inputs 0 and 1 6 | Prev_State_trans = [1,4,2,3;2,3,1,4]; % transpose of the P_State matrix 7 | Prev_Ip_trans = [1,1,1,1;2,2,2,2] ; % column 1 corresponds to previous input order. 8 | Next_State = [1,3; 3,1; 4,2; 2,4]; 9 | Outputs_next = [1,4; 1,4; 2,3; 2,3]; 10 | end 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Iterative decoding of turbo codes using the Soft Output Viterbi Algorithm (SOVA) 2 | 3 | References: 4 | 5 | See Section 5.5 in the book "Turbo Codes: Principles and Applications" by Branka Vucetic and Jinhong Yuan 6 | -------------------------------------------------------------------------------- /RUN_ME.m: -------------------------------------------------------------------------------- 1 | % Turbo coded QPSK OVER AWGN - overall rate is 1/2 2 | 3 | close all 4 | clear all 5 | clc 6 | SNR_dB = 3; % SNR PER BIT in dB 7 | FRAME_SIZE = 1024; 8 | NUM_BIT = 0.5*FRAME_SIZE; % NUMBER OF DATA BITS - OVERALL RATE IS 1/2 9 | NUM_FRAMES = 10^1; % NUMBER OF FRAMES SIMULATED 10 | 11 | % SNR PARAMETERS - OVERALL RATE IS 1/2 12 | SNR = 10^(0.1*SNR_dB); % SNR IN LINEAR SCALE 13 | NOISE_VAR_1D = 2*2/(2*SNR); % 1D AWGN NOISE VARIANCE 14 | NOISE_STD_DEV = sqrt(NOISE_VAR_1D); % NOISE STANDARD DEVIATION 15 | %-------------------------------------------------------------------------- 16 | % GENERATOR polynomial of the component encoders 17 | GEN_POLY = ldiv2([1 0 1],[1 1 1],NUM_BIT); % using long division method 18 | 19 | % Interleaver and deinterleaver mapping of the turbo code 20 | INTR_MAP = randperm(NUM_BIT); 21 | DEINTR_MAP = deintrlv((1:NUM_BIT),INTR_MAP); 22 | 23 | tic() 24 | C_BER = 0; % bit errors in each frame 25 | for FRAME_CNT = 1:NUM_FRAMES 26 | %---- TRANSMITTER ----------------------------------------- 27 | % SOURCE 28 | A = randi([0 1],1,NUM_BIT); 29 | 30 | % Turbo encoder 31 | % component encoder 1 32 | B1 = zeros(1,2*NUM_BIT); % encoder 1 output initialization 33 | B1(1:2:end) = A; % systematic bit 34 | temp1 = mod(conv(GEN_POLY,A),2); 35 | B1(2:2:end) = temp1(1:NUM_BIT); % parity bit 36 | % component encoder 2 37 | B2 = zeros(1,2*NUM_BIT); % encoder 2 output initialization 38 | B2(1:2:end) = A(INTR_MAP); % systematic bit 39 | temp2 = mod(conv(GEN_POLY,B2(1:2:end)),2); 40 | B2(2:2:end) = temp2(1:NUM_BIT); % parity bit 41 | 42 | % QPSK MAPPING 43 | % QPSK mapping (according to the set partitioning principles) 44 | MOD_SIG1 = 1-2*B1(1:2:end) + 1i*(1-2*B1(2:2:end)); 45 | MOD_SIG2 = 1-2*B2(1:2:end) + 1i*(1-2*B2(2:2:end)); 46 | MOD_SIG = [MOD_SIG1 MOD_SIG2]; 47 | 48 | %--------------- CHANNEL ----------------------------------------- 49 | % AWGN 50 | AWGN = normrnd(0,NOISE_STD_DEV,1,FRAME_SIZE)+1i*normrnd(0,NOISE_STD_DEV,1,FRAME_SIZE); 51 | 52 | % CHANNEL OUTPUT 53 | CHAN_OP = MOD_SIG + AWGN; 54 | %---------------- RECEIVER ------------------------------------------ 55 | %--------------------ITERATIVE TURBO DECODING ----------------------------- 56 | % Branch metrices for the SOVA 57 | QPSK_SYM = zeros(4,2*NUM_BIT); 58 | QPSK_SYM(1,:) = (1+1i)*ones(1,2*NUM_BIT); 59 | QPSK_SYM(2,:) = (1-1i)*ones(1,2*NUM_BIT); 60 | QPSK_SYM(3,:) = (-1+1i)*ones(1,2*NUM_BIT); 61 | QPSK_SYM(4,:) = (-1-1i)*ones(1,2*NUM_BIT); 62 | 63 | Dist = zeros(4,2*NUM_BIT); 64 | Dist(1,:)=abs(CHAN_OP-QPSK_SYM(1,:)).^2; 65 | Dist(2,:)=abs(CHAN_OP-QPSK_SYM(2,:)).^2; 66 | Dist(3,:)=abs(CHAN_OP-QPSK_SYM(3,:)).^2; 67 | Dist(4,:)=abs(CHAN_OP-QPSK_SYM(4,:)).^2; 68 | 69 | BRANCH_METRIC1 = Dist(:,1:NUM_BIT); % branch metrices for component decoder 1 70 | BRANCH_METRIC2 = Dist(:,NUM_BIT+1:end); % branch metrices for component decoder 2 71 | 72 | % a priori probabilities (LLR) - initialization 73 | APR_LLR = zeros(1,NUM_BIT); % for first iteration 74 | 75 | % iterative decoding 76 | SOFT_OUTPUT = SOVA(APR_LLR,NUM_BIT,BRANCH_METRIC1); 77 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %1 78 | 79 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 80 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %2 81 | 82 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 83 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %3 84 | 85 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 86 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %4 87 | 88 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 89 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %5 90 | 91 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 92 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %6 93 | 94 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 95 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %7 96 | 97 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 98 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %8 99 | 100 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 101 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %9 102 | 103 | SOFT_OUTPUT = SOVA(SOFT_OUTPUT(DEINTR_MAP),NUM_BIT,BRANCH_METRIC1); 104 | SOFT_OUTPUT = SOVA_END(SOFT_OUTPUT(INTR_MAP),NUM_BIT,BRANCH_METRIC2); %10 105 | 106 | % hard decision is taken on the a posteriori LLR 107 | SOFT_OUTPUT = SOFT_OUTPUT(DEINTR_MAP); 108 | DEC_A = SOFT_OUTPUT<0; 109 | % CALCULATING BIT ERRORS IN EACH FRAME 110 | C_BER = C_BER + nnz(A-DEC_A); 111 | end 112 | toc() 113 | % bit error rate 114 | BER = C_BER/(NUM_BIT*NUM_FRAMES) -------------------------------------------------------------------------------- /SOVA.m: -------------------------------------------------------------------------------- 1 | % Bidirectional Soft Output Viterbi Algorithm 2 | % Notation: if soft_output >0, then decoded bit is 0. 3 | % outputs extrinsic information 4 | % Written by Vineel Kumar Veludandi 5 | 6 | function[soft_output]=SOVA(apr_LLR,num_sym,branch_metric) 7 | C = log(exp(-apr_LLR/2)./(1+exp(-apr_LLR))); 8 | 9 | [Prev_State,Prev_Ip_trans,Outputs_prev,Prev_State_trans,Next_State,Outputs_next]= Get_Trellis(); 10 | num_states = 4; % number of states 11 | soft_output = zeros(1,num_sym); % soft output 12 | survivor_node = zeros(num_states,num_sym); % survivor nodes 13 | survivor_ip = zeros(num_states,num_sym); % survivor inputs 14 | F_path_metric = zeros(num_states,num_sym+1); % forward path metrics 15 | B_path_metric = zeros(num_states,num_sym+1); % backward path metrics 16 | index_temp = [0;1*2;2*2;3*2]; %for linear indexing. 17 | 18 | for sym_cnt= 1:num_sym 19 | [F_path_metric(:,sym_cnt+1),index] = min([F_path_metric(Prev_State(:,1),sym_cnt)+ branch_metric(Outputs_prev(:,1),sym_cnt)-(C(sym_cnt)+apr_LLR(sym_cnt)/2) ... 20 | F_path_metric(Prev_State(:,2),sym_cnt)+ branch_metric(Outputs_prev(:,2),sym_cnt)-((C(sym_cnt)-apr_LLR(sym_cnt)/2))],[],2); 21 | 22 | [B_path_metric(:,num_sym+1-sym_cnt),~] = min([B_path_metric(Next_State(:,1),num_sym+2-sym_cnt)+ branch_metric(Outputs_next(:,1),num_sym+1-sym_cnt)-(C(num_sym+1-sym_cnt)+apr_LLR(num_sym+1-sym_cnt)/2) ... 23 | B_path_metric(Next_State(:,2),num_sym+2-sym_cnt)+ branch_metric(Outputs_next(:,2),num_sym+1-sym_cnt)-(C(num_sym+1-sym_cnt)-apr_LLR(num_sym+1-sym_cnt)/2)],[],2); 24 | 25 | survivor_node(:,sym_cnt) = Prev_State_trans(index+index_temp); 26 | survivor_ip(:,sym_cnt) = Prev_Ip_trans(index+index_temp); 27 | 28 | end 29 | 30 | [ml_metric,trace_bf] = min(F_path_metric(:,num_sym+1)); 31 | 32 | for bk_cnt= num_sym:-1:1 33 | ip = survivor_ip(trace_bf,bk_cnt); 34 | com_ip = bitxor(ip-1,1)+1; % complementary input 35 | com_metric = min(F_path_metric(:,bk_cnt)+branch_metric(Outputs_next(:,com_ip),bk_cnt) + B_path_metric(Next_State(:,com_ip),bk_cnt+1) ); 36 | soft_output(bk_cnt) = ((-1)^(ip+1))*(com_metric-ml_metric); 37 | trace_bf = survivor_node(trace_bf,bk_cnt); 38 | end 39 | 40 | % normalizing (to avoid numerical instabilities) 41 | soft_output(soft_output>50) = 50; 42 | soft_output(soft_output<-50) = -50; 43 | 44 | 45 | end % for function 46 | -------------------------------------------------------------------------------- /SOVA_END.m: -------------------------------------------------------------------------------- 1 | % Bidirectional Soft Output Viterbi Algorithm 2 | % Notation: if soft_output >0, then decoded bit is 0. 3 | % outputs aposteriori probabilities 4 | % Written by Vineel Kumar Veludandi 5 | 6 | function[soft_output]=SOVA_END(apr_LLR,num_sym,branch_metric) 7 | C = log(exp(-apr_LLR/2)./(1+exp(-apr_LLR))); 8 | 9 | [Prev_State,Prev_Ip_trans,Outputs_prev,Prev_State_trans,Next_State,Outputs_next]= Get_Trellis(); 10 | num_states = 4; % number of states 11 | soft_output = zeros(1,num_sym); % soft output 12 | survivor_node = zeros(num_states,num_sym); % survivor nodes 13 | survivor_ip = zeros(num_states,num_sym); % survivor inputs 14 | F_path_metric = zeros(num_states,num_sym+1); % forward path metrics 15 | B_path_metric = zeros(num_states,num_sym+1); % backward path metrics 16 | index_temp = [0;1*2;2*2;3*2]; %for linear indexing. 17 | 18 | for sym_cnt= 1:num_sym 19 | [F_path_metric(:,sym_cnt+1),index] = min([F_path_metric(Prev_State(:,1),sym_cnt)+ branch_metric(Outputs_prev(:,1),sym_cnt)-(C(sym_cnt)+apr_LLR(sym_cnt)/2) ... 20 | F_path_metric(Prev_State(:,2),sym_cnt)+ branch_metric(Outputs_prev(:,2),sym_cnt)-(C(sym_cnt)-apr_LLR(sym_cnt)/2)],[],2); 21 | 22 | [B_path_metric(:,num_sym+1-sym_cnt),~] = min([B_path_metric(Next_State(:,1),num_sym+2-sym_cnt)+ branch_metric(Outputs_next(:,1),num_sym+1-sym_cnt)-(C(num_sym+1-sym_cnt)+apr_LLR(num_sym+1-sym_cnt)/2) ... 23 | B_path_metric(Next_State(:,2),num_sym+2-sym_cnt)+ branch_metric(Outputs_next(:,2),num_sym+1-sym_cnt)-(C(num_sym+1-sym_cnt)-apr_LLR(num_sym+1-sym_cnt)/2)],[],2); 24 | 25 | survivor_node(:,sym_cnt) = Prev_State_trans(index+index_temp); 26 | survivor_ip(:,sym_cnt) = Prev_Ip_trans(index+index_temp); 27 | end 28 | 29 | [ml_metric,trace_bf] = min(F_path_metric(:,num_sym+1)); 30 | 31 | for bk_cnt= num_sym:-1:1 32 | ip = survivor_ip(trace_bf,bk_cnt); 33 | com_ip = bitxor(ip-1,1)+1; % complementary input 34 | com_metric = min(F_path_metric(:,bk_cnt)+branch_metric(Outputs_next(:,com_ip),bk_cnt)-(C(bk_cnt)+((-1)^(com_ip-1))*apr_LLR(bk_cnt)/2) + B_path_metric(Next_State(:,com_ip),bk_cnt+1) ); 35 | soft_output(bk_cnt) = ((-1)^(ip+1))*(com_metric-ml_metric); 36 | trace_bf = survivor_node(trace_bf,bk_cnt); 37 | end 38 | 39 | % normalizing (to avoid numerical instabilities) 40 | soft_output(soft_output>50) = 50; 41 | soft_output(soft_output<-50) = -50; 42 | 43 | end % for function 44 | -------------------------------------------------------------------------------- /ldiv2.m: -------------------------------------------------------------------------------- 1 | % Long division of polynomials over GF(2) 2 | % Highest degree of numerator and denominator should be made equal through 3 | % zeros. 4 | % NP is numerator polynomial. For 1+D^2, put NP=[1 0 1] and for D^2 put NP=[0 0 1] 5 | % DP is denominator polynomial. 6 | % 'num_terms' is the 'num_terms' first coefficients of the long division of 7 | % NP by DP. 8 | % input and output are strictly row vectors 9 | % Same to the 'ldiv' function in SCILAB but in GF(2). 10 | % written by Vineel Kumar Veludandi 11 | 12 | function [quotient] = ldiv2(NP,DP,num_terms) 13 | quotient = zeros(1,num_terms); % quotient 14 | for coef_cnt = 1:num_terms 15 | quotient(coef_cnt) = NP(1); 16 | temp = bitxor(NP,DP*NP(1)); 17 | NP = [temp(2:end) 0]; 18 | end 19 | end --------------------------------------------------------------------------------