๐Ÿ”’ Protected Content

This MATLAB tutorial is for ECOM 561 students only. Please enter the password to continue.

โŒ Incorrect password. Please try again.

๐Ÿ’ป MATLAB Tutorial

ECOM 561 - Information Theory and Coding | Spring 2026

๐Ÿš€ Introduction & Setup

This tutorial provides MATLAB implementations for key concepts in Information Theory and Coding. These examples will help you understand theoretical concepts through practical implementation and prepare you for course assignments and projects.

๐Ÿ“‹ Course Learning Outcome

CLO-6: Evaluate the performance of selected coding algorithms on some error-correction and coding techniques using MATLAB.

Required Toolboxes

Check Installed Toolboxes
% Check if Communications Toolbox is installed
v = ver;
hasCommToolbox = any(strcmp({v.Name}, 'Communications Toolbox'));
if hasCommToolbox
    disp('โœ“ Communications Toolbox is installed')
else
    disp('โœ— Communications Toolbox not found - some functions may not work')
end

% Alternative: Use built-in functions for most examples in this tutorial

Basic Setup Template

Script Header Template
%% ECOM 561 - Information Theory and Coding
%  Assignment/Project: [Title]
%  Student Name: [Your Name]
%  Student ID: [Your ID]
%  Date: [Date]
%  Description: [Brief description of what this code does]

clear all;    % Clear all variables
close all;    % Close all figures
clc;          % Clear command window

%% Main Code Starts Here
% Your implementation goes here

๐Ÿ’ก Tip: Using Sections

Use %% to create sections in your code. Press Ctrl+Enter to run the current section only. This is very useful for testing parts of your code!

๐Ÿ“Š Entropy & Information Measures CLO-1

๐Ÿ“ Theory Review

Self-Information: I(x) = -logโ‚‚(P(x)) bits

Entropy: H(X) = -ฮฃ P(xแตข) logโ‚‚(P(xแตข)) bits

Joint Entropy: H(X,Y) = -ฮฃแตข ฮฃโฑผ P(xแตข,yโฑผ) logโ‚‚(P(xแตข,yโฑผ))

Mutual Information: I(X;Y) = H(X) + H(Y) - H(X,Y)

Self-Information Calculator

self_information.m
function I = self_information(p)
% SELF_INFORMATION Calculate self-information of an event
%   I = self_information(p) returns the self-information in bits
%   Input: p - probability of the event (0 < p <= 1)
%   Output: I - self-information in bits

    if p <= 0 || p > 1
        error('Probability must be in range (0, 1]');
    end
    
    I = -log2(p);
end

%% Example Usage
% Event with probability 0.5 (fair coin flip)
p = 0.5;
I = self_information(p);
fprintf('Self-information for P=%.2f: %.4f bits\n', p, I);

% Multiple events
probs = [0.9, 0.5, 0.1, 0.01];
for i = 1:length(probs)
    I = self_information(probs(i));
    fprintf('P = %.2f โ†’ I = %.4f bits\n', probs(i), I);
end

Entropy Calculator

calculate_entropy.m
function H = calculate_entropy(P)
% CALCULATE_ENTROPY Calculate entropy of a discrete source
%   H = calculate_entropy(P) returns entropy in bits
%   Input: P - probability distribution (must sum to 1)
%   Output: H - entropy in bits

    % Validate input
    if abs(sum(P) - 1) > 1e-10
        error('Probabilities must sum to 1. Sum = %.6f', sum(P));
    end
    
    if any(P < 0)
        error('Probabilities cannot be negative');
    end
    
    % Calculate entropy (handle P=0 case)
    H = 0;
    for i = 1:length(P)
        if P(i) > 0
            H = H - P(i) * log2(P(i));
        end
    end
end

%% Example: Binary Source Entropy
p = 0:0.01:1;
H_binary = zeros(size(p));

for i = 1:length(p)
    if p(i) == 0 || p(i) == 1
        H_binary(i) = 0;
    else
        H_binary(i) = calculate_entropy([p(i), 1-p(i)]);
    end
end

% Plot binary entropy function
figure('Position', [100, 100, 800, 500]);
plot(p, H_binary, 'b-', 'LineWidth', 2);
xlabel('Probability p', 'FontSize', 12);
ylabel('H(p) [bits]', 'FontSize', 12);
title('Binary Entropy Function', 'FontSize', 14);
grid on;
xlim([0 1]);
ylim([0 1.1]);

% Mark maximum entropy point
hold on;
plot(0.5, 1, 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
text(0.52, 1, 'Maximum at p=0.5', 'FontSize', 11);
hold off;

Joint and Conditional Entropy

joint_conditional_entropy.m
function [H_XY, H_X, H_Y, H_X_given_Y, H_Y_given_X, I_XY] = joint_conditional_entropy(P_XY)
% JOINT_CONDITIONAL_ENTROPY Calculate all entropy measures
%   Input: P_XY - joint probability matrix P(X,Y)
%   Output: Various entropy measures

    % Marginal distributions
    P_X = sum(P_XY, 2);     % Sum over Y (columns)
    P_Y = sum(P_XY, 1);     % Sum over X (rows)
    
    % Individual entropies
    H_X = calculate_entropy(P_X);
    H_Y = calculate_entropy(P_Y);
    
    % Joint entropy H(X,Y)
    H_XY = 0;
    [m, n] = size(P_XY);
    for i = 1:m
        for j = 1:n
            if P_XY(i,j) > 0
                H_XY = H_XY - P_XY(i,j) * log2(P_XY(i,j));
            end
        end
    end
    
    % Conditional entropies
    H_X_given_Y = H_XY - H_Y;  % H(X|Y) = H(X,Y) - H(Y)
    H_Y_given_X = H_XY - H_X;  % H(Y|X) = H(X,Y) - H(X)
    
    % Mutual information
    I_XY = H_X + H_Y - H_XY;   % I(X;Y) = H(X) + H(Y) - H(X,Y)
end

%% Example: Binary Symmetric Channel Analysis
p = 0.1;  % Crossover probability

% Assume uniform input: P(X=0) = P(X=1) = 0.5
P_XY = [0.5*(1-p), 0.5*p;      % P(X=0,Y=0), P(X=0,Y=1)
        0.5*p,     0.5*(1-p)];  % P(X=1,Y=0), P(X=1,Y=1)

[H_XY, H_X, H_Y, H_X_given_Y, H_Y_given_X, I_XY] = joint_conditional_entropy(P_XY);

fprintf('===== Binary Symmetric Channel Analysis (p=%.2f) =====\n', p);
fprintf('H(X) = %.4f bits\n', H_X);
fprintf('H(Y) = %.4f bits\n', H_Y);
fprintf('H(X,Y) = %.4f bits\n', H_XY);
fprintf('H(X|Y) = %.4f bits\n', H_X_given_Y);
fprintf('I(X;Y) = %.4f bits\n', I_XY);

โœ… Key Relationships to Remember

  • Chain Rule: H(X,Y) = H(X) + H(Y|X) = H(Y) + H(X|Y)
  • Conditioning Reduces Entropy: H(X|Y) โ‰ค H(X)
  • Mutual Information: I(X;Y) = H(X) - H(X|Y) โ‰ฅ 0
  • Maximum Entropy: Uniform distribution maximizes entropy

๐Ÿ“ฆ Source Coding Fundamentals CLO-2

๐Ÿ“ Source Coding Theorem

For a discrete memoryless source with entropy H(X), the average codeword length L satisfies:

H(X) โ‰ค L < H(X) + 1

The minimum average length approaches H(X) for optimal prefix-free codes.

Kraft Inequality Checker

kraft_inequality.m
function [K, is_valid] = kraft_inequality(lengths, r)
% KRAFT_INEQUALITY Check if codeword lengths satisfy Kraft inequality
%   Input: lengths - vector of codeword lengths
%          r - radix/alphabet size (default: 2 for binary)
%   Output: K - Kraft sum
%           is_valid - true if K <= 1 (prefix-free code exists)

    if nargin < 2
        r = 2;  % Binary by default
    end
    
    K = sum(r.^(-lengths));
    is_valid = K <= 1;
    
    fprintf('===== Kraft Inequality Check =====\n');
    fprintf('Codeword lengths: [%s]\n', num2str(lengths));
    fprintf('Kraft sum K = %.4f\n', K);
    
    if is_valid
        fprintf('โœ“ K โ‰ค 1: A prefix-free code EXISTS\n');
    else
        fprintf('โœ— K > 1: NO prefix-free code exists\n');
    end
end

%% Examples
fprintf('Example 1: Valid code\n');
kraft_inequality([1, 2, 3, 3], 2);

fprintf('\nExample 2: Invalid lengths\n');
kraft_inequality([1, 1, 2, 2], 2);

๐ŸŒณ Huffman Coding CLO-2

๐Ÿ“ Huffman Algorithm

Huffman coding produces an optimal prefix-free code:

  1. Sort symbols by probability (ascending)
  2. Combine two lowest probability symbols
  3. Repeat until single node remains
  4. Assign bits by traversing tree (0=left, 1=right)

Huffman Coding Implementation

huffman_encode.m
function [codes, lengths, L_avg] = huffman_encode(symbols, P)
% HUFFMAN_ENCODE Generate Huffman codes for given symbols
%   Input: symbols - cell array of symbol names
%          P - probability distribution
%   Output: codes - cell array of binary code strings
%           lengths - codeword lengths
%           L_avg - average codeword length

    n = length(P);
    
    % Initialize nodes
    nodes = cell(1, n);
    for i = 1:n
        nodes{i}.prob = P(i);
        nodes{i}.symbols = {i};
        nodes{i}.code = '';
    end
    
    % Build Huffman tree
    while length(nodes) > 1
        % Sort by probability
        probs = cellfun(@(x) x.prob, nodes);
        [~, idx] = sort(probs);
        nodes = nodes(idx);
        
        % Combine two smallest nodes
        new_node.prob = nodes{1}.prob + nodes{2}.prob;
        new_node.left = nodes{1};
        new_node.right = nodes{2};
        new_node.symbols = [nodes{1}.symbols, nodes{2}.symbols];
        
        % Remove combined nodes and add new node
        nodes = nodes(3:end);
        nodes{end+1} = new_node;
    end
    
    % Generate codes by traversing tree
    codes = cell(1, n);
    lengths = zeros(1, n);
    
    function traverse(node, code)
        if isfield(node, 'left')
            traverse(node.left, [code '0']);
            traverse(node.right, [code '1']);
        else
            idx = node.symbols{1};
            codes{idx} = code;
            lengths(idx) = length(code);
        end
    end
    
    traverse(nodes{1}, '');
    
    % Calculate average length
    L_avg = sum(P .* lengths);
    
    % Display results
    H = calculate_entropy(P);
    fprintf('===== Huffman Coding Results =====\n');
    fprintf('Symbol | Prob   | Length | Code\n');
    fprintf('-------|--------|--------|----------\n');
    for i = 1:n
        fprintf('  %s    | %.4f |   %d    | %s\n', symbols{i}, P(i), lengths(i), codes{i});
    end
    fprintf('\nEntropy H(X) = %.4f bits\n', H);
    fprintf('Average Length L = %.4f bits\n', L_avg);
    fprintf('Efficiency = %.2f%%\n', H/L_avg*100);
end

%% Example
symbols = {'A', 'B', 'C', 'D', 'E'};
P = [0.4, 0.2, 0.2, 0.1, 0.1];
[codes, lengths, L_avg] = huffman_encode(symbols, P);

๐Ÿ”„ Lempel-Ziv Coding CLO-2

๐Ÿ“ LZ78 Algorithm

Dictionary-based compression that builds a codebook dynamically:

  1. Start with empty dictionary
  2. Read input until finding longest match in dictionary
  3. Output (index, next_symbol) pair
  4. Add new phrase to dictionary

LZ78 Encoder

lz78_encode.m
function [output, dictionary] = lz78_encode(input)
% LZ78_ENCODE Encode a string using LZ78 algorithm
%   Input: input - string to encode
%   Output: output - cell array of (index, symbol) pairs
%           dictionary - final dictionary

    dictionary = {''};  % Start with empty string
    output = {};
    i = 1;
    
    fprintf('===== LZ78 Encoding Process =====\n');
    
    while i <= length(input)
        % Find longest match in dictionary
        match_idx = 0;
        match_len = 0;
        
        for j = 1:length(dictionary)
            dict_entry = dictionary{j};
            entry_len = length(dict_entry);
            
            if i + entry_len - 1 <= length(input)
                if strcmp(input(i:i+entry_len-1), dict_entry) && entry_len > match_len
                    match_idx = j - 1;
                    match_len = entry_len;
                end
            end
        end
        
        % Get next symbol after match
        next_pos = i + match_len;
        if next_pos <= length(input)
            next_symbol = input(next_pos);
        else
            next_symbol = '';
        end
        
        % Output pair
        output{end+1} = {match_idx, next_symbol};
        
        % Add new phrase to dictionary
        if ~isempty(next_symbol)
            new_phrase = [dictionary{match_idx+1}, next_symbol];
            dictionary{end+1} = new_phrase;
        end
        
        i = next_pos + 1;
    end
    
    fprintf('Final Dictionary: {%s}\n', strjoin(dictionary(2:end), ', '));
end

%% Example
input_string = 'AABABAABAB';
fprintf('Input: %s\n\n', input_string);
[encoded, dict] = lz78_encode(input_string);

๐Ÿ“ก Channel Capacity CLO-3

๐Ÿ“ Shannon's Channel Capacity

Binary Symmetric Channel (BSC):

C = 1 - H(p) = 1 + p logโ‚‚(p) + (1-p) logโ‚‚(1-p)

AWGN Channel:

C = W logโ‚‚(1 + SNR) bits/second

Binary Symmetric Channel Capacity

bsc_capacity.m
function C = bsc_capacity(p)
% BSC_CAPACITY Calculate capacity of Binary Symmetric Channel
%   Input: p - crossover probability (error probability)
%   Output: C - channel capacity in bits per channel use

    if p == 0 || p == 1
        C = 1;  % Perfect channel
    else
        H_p = -p*log2(p) - (1-p)*log2(1-p);  % Binary entropy
        C = 1 - H_p;
    end
end

%% Plot BSC Capacity vs Error Probability
p = 0:0.001:0.5;
C = zeros(size(p));

for i = 1:length(p)
    C(i) = bsc_capacity(p(i));
end

figure('Position', [100, 100, 800, 500]);
plot(p, C, 'b-', 'LineWidth', 2);
xlabel('Crossover Probability p', 'FontSize', 12);
ylabel('Channel Capacity C (bits/use)', 'FontSize', 12);
title('Binary Symmetric Channel Capacity', 'FontSize', 14);
grid on;
xlim([0 0.5]);
ylim([0 1]);

AWGN Channel Capacity

awgn_capacity.m
function C = awgn_capacity(SNR_dB, W)
% AWGN_CAPACITY Calculate capacity of AWGN channel
%   Input: SNR_dB - Signal-to-noise ratio in dB
%          W - Bandwidth in Hz (default: 1 for normalized)
%   Output: C - Channel capacity in bits/second

    if nargin < 2
        W = 1;
    end
    
    SNR_linear = 10^(SNR_dB/10);
    C = W * log2(1 + SNR_linear);
end

%% Plot AWGN Capacity vs SNR
SNR_dB = -10:0.5:30;
C = zeros(size(SNR_dB));

for i = 1:length(SNR_dB)
    C(i) = awgn_capacity(SNR_dB(i), 1);
end

figure('Position', [100, 100, 800, 500]);
plot(SNR_dB, C, 'b-', 'LineWidth', 2);
xlabel('SNR (dB)', 'FontSize', 12);
ylabel('Channel Capacity C (bits/s/Hz)', 'FontSize', 12);
title('AWGN Channel Capacity (Shannon Limit)', 'FontSize', 14);
grid on;

๐Ÿ”ฒ Linear Block Codes CLO-4

๐Ÿ“ Linear Block Code Basics

An (n, k) linear block code encodes k information bits into n coded bits.

Generator Matrix G: c = m ร— G

Parity-Check Matrix H: c ร— HT = 0 for valid codewords

Syndrome: s = r ร— HT (non-zero indicates errors)

Hamming (7,4) Code Implementation

hamming_74.m
%% Hamming (7,4) Code - Complete Implementation
% Parameters: n=7 (codeword length), k=4 (message length), d_min=3

clear all; close all; clc;

%% Generator Matrix (Systematic Form: G = [I_k | P])
G = [1 0 0 0 1 1 0;
     0 1 0 0 1 0 1;
     0 0 1 0 0 1 1;
     0 0 0 1 1 1 1];

% Parity-check matrix H = [P' | I_(n-k)]
H = [1 1 0 1 1 0 0;
     1 0 1 1 0 1 0;
     0 1 1 1 0 0 1];

fprintf('===== Hamming (7,4) Code =====\n\n');
fprintf('Generator Matrix G:\n');
disp(G);
fprintf('Parity-Check Matrix H:\n');
disp(H);

%% Verify G and H relationship: G * H' = 0
GHt = mod(G * H', 2);
fprintf('Verification G ร— H^T (should be all zeros):\n');
disp(GHt);

%% Generate all codewords
fprintf('\n===== All 16 Codewords =====\n');
fprintf('Message | Codeword    | Weight\n');
fprintf('--------|-------------|-------\n');

all_messages = dec2bin(0:15, 4) - '0';
all_codewords = mod(all_messages * G, 2);

for i = 1:16
    msg = num2str(all_messages(i,:), '%d');
    cw = num2str(all_codewords(i,:), '%d');
    wt = sum(all_codewords(i,:));
    fprintf(' %s   | %s   |   %d\n', msg, cw, wt);
end

% Minimum distance
weights = sum(all_codewords, 2);
d_min = min(weights(weights > 0));
fprintf('\nMinimum distance d_min = %d\n', d_min);
fprintf('Error correction capability: %d error\n', floor((d_min-1)/2));

Encoding and Syndrome Decoding

hamming_codec.m
function codeword = hamming_encode(message, G)
% HAMMING_ENCODE Encode message using generator matrix
    codeword = mod(message * G, 2);
end

function [syndrome, error_pos] = hamming_syndrome(received, H)
% HAMMING_SYNDROME Calculate syndrome and find error position
    syndrome = mod(received * H', 2);
    
    if all(syndrome == 0)
        error_pos = 0;  % No error
    else
        error_pos = bi2de(syndrome, 'left-msb');
    end
end

function corrected = hamming_correct(received, H)
% HAMMING_CORRECT Correct single-bit error
    [syndrome, error_pos] = hamming_syndrome(received, H);
    corrected = received;
    
    if error_pos > 0
        corrected(error_pos) = mod(corrected(error_pos) + 1, 2);
        fprintf('Error detected at position %d, corrected.\n', error_pos);
    elseif error_pos == 0
        fprintf('No error detected.\n');
    end
end

%% Example: Encode, Add Error, Decode
G = [1 0 0 0 1 1 0;
     0 1 0 0 1 0 1;
     0 0 1 0 0 1 1;
     0 0 0 1 1 1 1];

H = [1 1 0 1 1 0 0;
     1 0 1 1 0 1 0;
     0 1 1 1 0 0 1];

message = [1 0 1 1];
fprintf('Original message: %s\n', num2str(message, '%d'));

codeword = hamming_encode(message, G);
fprintf('Encoded codeword: %s\n', num2str(codeword, '%d'));

% Introduce single-bit error
error_position = 3;
received = codeword;
received(error_position) = mod(received(error_position) + 1, 2);
fprintf('\nReceived with error at position %d: %s\n', error_position, num2str(received, '%d'));

corrected = hamming_correct(received, H);
fprintf('Corrected codeword: %s\n', num2str(corrected, '%d'));
fprintf('Matches original: %s\n', string(isequal(corrected, codeword)));

โ™ป๏ธ Cyclic Codes CLO-4

๐Ÿ“ Cyclic Code Properties

A cyclic code is a linear block code where any cyclic shift of a codeword is also a codeword.

Generator Polynomial g(x): Divides xn + 1

CRC Implementation

crc_example.m
function [codeword, fcs] = crc_encode(data, generator)
% CRC_ENCODE Generate CRC codeword
    r = length(generator) - 1;
    augmented = [data, zeros(1, r)];
    
    temp = augmented;
    for i = 1:(length(data))
        if temp(i) == 1
            temp(i:i+r) = xor(temp(i:i+r), generator);
        end
    end
    
    fcs = temp(end-r+1:end);
    codeword = [data, fcs];
end

function is_valid = crc_check(received, generator)
% CRC_CHECK Verify received codeword
    r = length(generator) - 1;
    
    temp = received;
    for i = 1:(length(received) - r)
        if temp(i) == 1
            temp(i:i+r) = xor(temp(i:i+r), generator);
        end
    end
    
    remainder = temp(end-r+1:end);
    is_valid = all(remainder == 0);
end

%% Example: CRC-4
data = [1 1 0 1 0 1 1];
generator = [1 0 0 1 1];  % x^4 + x + 1

fprintf('===== CRC Example =====\n');
fprintf('Data: %s\n', num2str(data, '%d'));

[codeword, fcs] = crc_encode(data, generator);
fprintf('FCS (CRC): %s\n', num2str(fcs, '%d'));
fprintf('Transmitted: %s\n', num2str(codeword, '%d'));

is_valid = crc_check(codeword, generator);
fprintf('Verification (no error): %s\n', string(is_valid));

๐Ÿ”— Convolutional Codes CLO-5

๐Ÿ“ Convolutional Code Parameters

Rate: R = k/n (k input bits, n output bits)

Constraint Length: K (memory + 1)

Generator Polynomials: Define connections to output

Rate 1/2 Convolutional Encoder

conv_encoder.m
function [output, states] = conv_encode(input, g1, g2, K)
% CONV_ENCODE Rate 1/2 convolutional encoder
%   Input: input - binary input sequence
%          g1, g2 - generator polynomials
%          K - constraint length
%   Output: output - encoded sequence (2ร— length of input)

    memory = K - 1;
    state = zeros(1, memory);
    
    n_bits = length(input);
    output = zeros(1, 2*n_bits);
    states = zeros(n_bits, memory);
    
    for i = 1:n_bits
        in_bit = input(i);
        reg = [in_bit, state];
        
        out1 = mod(sum(reg .* g1), 2);
        out2 = mod(sum(reg .* g2), 2);
        
        output(2*i-1) = out1;
        output(2*i) = out2;
        states(i, :) = state;
        state = [in_bit, state(1:end-1)];
    end
end

%% Example: Standard rate 1/2, K=3 encoder
K = 3;
g1 = [1 1 1];  % Connections for output 1 (octal 7)
g2 = [1 0 1];  % Connections for output 2 (octal 5)

fprintf('===== Rate 1/2, K=3 Convolutional Encoder =====\n');
fprintf('Generator 1: [%s] (octal 7)\n', num2str(g1, '%d '));
fprintf('Generator 2: [%s] (octal 5)\n', num2str(g2, '%d '));

input = [1 0 1 1 0];
fprintf('\nInput sequence: %s\n', num2str(input, '%d'));

[output, states] = conv_encode(input, g1, g2, K);
fprintf('Output sequence: %s\n', num2str(output, '%d'));
fprintf('\nCode rate: 1/2\n');

State Transition Table

state_table.m
function print_state_table(g1, g2, K)
% PRINT_STATE_TABLE Generate and display state transition table

    memory = K - 1;
    num_states = 2^memory;
    
    fprintf('===== State Transition Table =====\n');
    fprintf('Current State | Input | Next State | Output\n');
    fprintf('--------------|-------|------------|-------\n');
    
    for s = 0:num_states-1
        state = de2bi(s, memory, 'left-msb');
        
        for in_bit = 0:1
            reg = [in_bit, state];
            
            out1 = mod(sum(reg .* g1), 2);
            out2 = mod(sum(reg .* g2), 2);
            
            next_state = [in_bit, state(1:end-1)];
            next_dec = bi2de(next_state, 'left-msb');
            
            fprintf('     %s      |   %d   |     %s     |   %d%d\n', ...
                dec2bin(s, memory), in_bit, dec2bin(next_dec, memory), out1, out2);
        end
    end
end

%% Generate table
K = 3;
g1 = [1 1 1];
g2 = [1 0 1];
print_state_table(g1, g2, K);

๐ŸŽฏ Viterbi Algorithm CLO-5

๐Ÿ“ Viterbi Decoding

Maximum likelihood sequence decoding algorithm:

  1. Initialize: Set initial path metrics
  2. Branch Metrics: Calculate Hamming distance to received bits
  3. Add-Compare-Select: Keep best path to each state
  4. Traceback: Find path with minimum metric

Viterbi Decoder Implementation

viterbi_decode.m
function [decoded, path_metric] = viterbi_decode(received, g1, g2, K)
% VITERBI_DECODE Decode convolutional code using Viterbi algorithm

    memory = K - 1;
    num_states = 2^memory;
    n_branches = length(received) / 2;
    
    path_metrics = inf(num_states, 1);
    path_metrics(1) = 0;  % Start at state 00
    
    survivors = zeros(num_states, n_branches);
    
    for t = 1:n_branches
        r1 = received(2*t - 1);
        r2 = received(2*t);
        
        new_metrics = inf(num_states, 1);
        
        for curr_state = 0:num_states-1
            if path_metrics(curr_state + 1) == inf
                continue;
            end
            
            state_bits = de2bi(curr_state, memory, 'left-msb');
            
            for in_bit = 0:1
                reg = [in_bit, state_bits];
                
                exp1 = mod(sum(reg .* g1), 2);
                exp2 = mod(sum(reg .* g2), 2);
                
                branch_metric = (r1 ~= exp1) + (r2 ~= exp2);
                
                next_state_bits = [in_bit, state_bits(1:end-1)];
                next_state = bi2de(next_state_bits, 'left-msb');
                
                total_metric = path_metrics(curr_state + 1) + branch_metric;
                
                if total_metric < new_metrics(next_state + 1)
                    new_metrics(next_state + 1) = total_metric;
                    survivors(next_state + 1, t) = curr_state * 2 + in_bit;
                end
            end
        end
        
        path_metrics = new_metrics;
    end
    
    % Traceback
    [path_metric, final_state] = min(path_metrics);
    final_state = final_state - 1;
    
    decoded = zeros(1, n_branches);
    current_state = final_state;
    
    for t = n_branches:-1:1
        survivor_info = survivors(current_state + 1, t);
        prev_state = floor(survivor_info / 2);
        input_bit = mod(survivor_info, 2);
        
        decoded(t) = input_bit;
        current_state = prev_state;
    end
end

%% Test Viterbi decoder
K = 3;
g1 = [1 1 1];
g2 = [1 0 1];

message = [1 0 1 1 0 0];
fprintf('===== Viterbi Decoder Test =====\n');
fprintf('Original message: %s\n', num2str(message, '%d'));

[encoded, ~] = conv_encode(message, g1, g2, K);
fprintf('Encoded: %s\n', num2str(encoded, '%d'));

% Add error
received = encoded;
received(5) = mod(received(5) + 1, 2);
fprintf('Received (with error): %s\n', num2str(received, '%d'));

[decoded, metric] = viterbi_decode(received, g1, g2, K);
fprintf('Decoded: %s\n', num2str(decoded, '%d'));
fprintf('Path metric: %d\n', metric);
fprintf('Decoding successful: %s\n', string(isequal(decoded, message)));

๐Ÿ“ˆ BER Performance Simulation CLO-6

Complete BER Simulation

ber_simulation.m
function ber_simulation()
% BER_SIMULATION Compare coded vs uncoded BER performance

    K = 3;
    g1 = [1 1 1];
    g2 = [1 0 1];
    
    num_bits = 10000;
    EbN0_dB = 0:0.5:10;
    num_trials = 5;
    
    ber_uncoded = zeros(size(EbN0_dB));
    ber_coded = zeros(size(EbN0_dB));
    
    fprintf('===== BER Simulation =====\n');
    
    for idx = 1:length(EbN0_dB)
        errors_uncoded = 0;
        errors_coded = 0;
        total_bits = 0;
        
        for trial = 1:num_trials
            bits = randi([0, 1], 1, num_bits);
            bits_tail = [bits, zeros(1, K-1)];
            
            [coded, ~] = conv_encode(bits_tail, g1, g2, K);
            
            tx_uncoded = 2*bits - 1;
            tx_coded = 2*coded - 1;
            
            EbN0_linear = 10^(EbN0_dB(idx)/10);
            
            noise_var_uncoded = 1 / (2 * EbN0_linear);
            rx_uncoded = tx_uncoded + sqrt(noise_var_uncoded) * randn(size(tx_uncoded));
            
            noise_var_coded = 1 / (2 * EbN0_linear * 0.5);
            rx_coded = tx_coded + sqrt(noise_var_coded) * randn(size(tx_coded));
            
            decoded_uncoded = rx_uncoded < 0;
            received_hard = rx_coded < 0;
            
            [decoded_coded, ~] = viterbi_decode(double(received_hard), g1, g2, K);
            
            errors_uncoded = errors_uncoded + sum(bits ~= decoded_uncoded);
            errors_coded = errors_coded + sum(bits ~= decoded_coded(1:num_bits));
            total_bits = total_bits + num_bits;
        end
        
        ber_uncoded(idx) = errors_uncoded / total_bits;
        ber_coded(idx) = errors_coded / total_bits;
        
        fprintf('Eb/N0 = %4.1f dB: BER_coded = %.2e\n', EbN0_dB(idx), ber_coded(idx));
    end
    
    figure('Position', [100, 100, 800, 600]);
    semilogy(EbN0_dB, ber_uncoded, 'bo-', 'LineWidth', 1.5, 'DisplayName', 'Uncoded BPSK');
    hold on;
    semilogy(EbN0_dB, ber_coded, 'rs-', 'LineWidth', 1.5, 'DisplayName', 'Conv Code R=1/2, K=3');
    
    xlabel('E_b/N_0 (dB)', 'FontSize', 12);
    ylabel('Bit Error Rate (BER)', 'FontSize', 12);
    title('BER Performance: Coded vs Uncoded BPSK', 'FontSize', 14);
    legend('Location', 'southwest');
    grid on;
    hold off;
end

ber_simulation();

โš ๏ธ Simulation Tips

  • Use enough bits for statistical significance (โ‰ฅ10,000)
  • Run multiple trials and average results
  • Account for code rate when calculating noise variance

๐Ÿ’ก Tips & Best Practices

MATLAB Shortcuts

ShortcutAction
Ctrl + CStop running code
Ctrl + EnterRun current section
F5Run script
F9Run selected code
Ctrl + RComment lines
Ctrl + TUncomment lines

Useful Functions Reference

Binary Operations

  • de2bi(), bi2de()
  • dec2bin(), bin2dec()
  • mod(x, 2)
  • xor(), bitxor()

Matrix Operations

  • eye(), zeros(), ones()
  • transpose(), '
  • reshape(), repmat()
  • sum(), prod()

Communications

  • gfdeconv() - GF(2) division
  • convenc() - Conv encoding
  • vitdec() - Viterbi decoder
  • biterr() - Count bit errors

Plotting

  • semilogy() - Log y-axis
  • subplot() - Multiple plots
  • legend(), title()
  • grid on, hold on

โœ… Assignment Submission Checklist

  • โœ“ Header with name, ID, assignment number
  • โœ“ Code runs without errors from start to finish
  • โœ“ All variables properly defined
  • โœ“ Comments explain complex operations
  • โœ“ Figures have titles, labels, and legends
  • โœ“ Results displayed with fprintf()
  • โœ“ Code properly indented and readable

๐Ÿ“š Additional Resources

Need Help?

Contact Dr. Al Bataineh during office hours (Tuesday/Thursday 11:00 AM - 12:00 PM)

Email: [email protected] | Office: F1-1175

โ† Back to ECOM 561 Course Page