Code covered by the BSD License  

Highlights from
A Numerical Tour of Signal Processing

from A Numerical Tour of Signal Processing by Gabriel Peyre
A set of Matlab experiments that illustrates advanced computational signal and image processing.

perform_arith_fixed(x, h, n)
function y = perform_arith_fixed(x, h, n)

% perform_arith_fixed - arithmetic coding
% 
% Coding:
%   y = perform_arith_fixed(x, h, n);
% Decoding:
%   x = perform_arith_fixed(y, h);
%
%   Copyright (c) 2008 Gabriel Peyre

if nargin==2
    dir=1;
elseif nargin==3
    dir=-1;
else
    error('Wrong number of arumgnets');
end

h = round(h*100000); 

if dir==1
    y = arithenco(x,h);
else
    y = arithdeco(x, h, n);
end



function code = arithenco(seq, counts)
%ARITHENCO Encode a sequence of symbols using arithmetic coding.
%   CODE = ARITHENCO(SEQ, COUNTS) generates binary arithmetic code 
%   corresponding to the sequence of symbols specified in the vector SEQ. 
%   The vector COUNTS contains the symbol counts (the number of times each
%   symbol of the source's alphabet occurs in a test data set) and represents
%   the source's statistics.
%
%   Example: 
%     Consider a source whose alphabet is {x, y, z}. A 177-symbol test data 
%     set from the source contains 29 x's, 48 y's and 100 z's. To encode the 
%     sequence yzxzz, use these commands:
%
%       seq = [2 3 1 3 3];
%       counts = [29 48 100];
%       code = arithenco(seq, counts) 
%                   
%   See also ARITHDECO.

%   Copyright 1996-2002 The MathWorks, Inc.
%   $Revision: 1.3 $ $Date: 2002/06/17 12:22:10 $

%   References:
%         [1] Sayood, K., Introduction to Data Compression, 
%         Morgan Kaufmann, 2000, Chapter 4, Section 4.4.3.
         

% Check the incoming orientation and adjust if necessary
[row_s, col_s] = size(seq);
if (row_s > 1),
    seq = seq.';
end

[row_c, col_c] = size(counts);
if (row_c > 1),
    counts = counts.';
end

% Compute the cumulative counts vector from the counts 
cum_counts = [0, cumsum(counts)];

% Compute the Word Length required.
total_count = cum_counts(end);
N = ceil(log2(total_count)) + 2;

% Initialize the lower and upper bounds.
dec_low = 0;
dec_up = 2^N-1;
E3_count = 0;

% Obtain an over estimate for the length of CODE and initialize CODE
code_len = length(seq) * ( ceil(log2(length(counts))) + 2 ) + N;
code = zeros(1, code_len);
code_index = 1;

% Loop for each symbol in SEQ
for k = 1:length(seq)

    symbol = seq(k);
    % Compute the new lower bound
    dec_low_new = dec_low + floor( (dec_up-dec_low+1)*cum_counts(symbol+1-1)/total_count );

    % Compute the new upper bound
    dec_up = dec_low + floor( (dec_up-dec_low+1)*cum_counts(symbol+1)/total_count )-1;

    % Update the lower bound
    dec_low = dec_low_new;
    
    % Check for E1, E2 or E3 conditions and keep looping as long as they occur.
    while( isequal(bitget(dec_low, N), bitget(dec_up, N)) || ...
        (isequal(bitget(dec_low, N-1), 1) && isequal(bitget(dec_up, N-1), 0) ) ),
        
        % If it is an E1 or E2 condition,
        if isequal(bitget(dec_low, N), bitget(dec_up, N)),

            % Get the MSB
            b = bitget(dec_low, N);
            code(code_index) = b;
            code_index = code_index + 1;
        
            % Left shifts
            dec_low = bitshift(dec_low, 1) + 0;
            dec_up = bitshift(dec_up, 1) + 1;
            
            % Check if E3_count is non-zero and transmit appropriate bits
            if (E3_count > 0),
                % Have to transmit complement of b, E3_count times.
                code(code_index:code_index+E3_count-1) = bitcmp(b, 1).*ones(1, E3_count);
                code_index = code_index + E3_count;
                E3_count = 0;
            end

            % Reduce to N for next loop
            dec_low = bitset(dec_low, N+1, 0);
            dec_up  = bitset(dec_up, N+1, 0);
            
        % Else if it is an E3 condition    
        elseif ( (isequal(bitget(dec_low, N-1), 1) && ...
            isequal(bitget(dec_up, N-1), 0) ) ),
            
            % Left shifts
            dec_low = bitshift(dec_low, 1) + 0;
            dec_up  = bitshift(dec_up, 1) + 1;

            % Reduce to N for next loop
            dec_low = bitset(dec_low, N+1, 0);
            dec_up  = bitset(dec_up, N+1, 0);
            
            % Complement the new MSB of dec_low and dec_up
            dec_low = bitxor(dec_low, 2^(N-1) );
            dec_up  = bitxor(dec_up, 2^(N-1) );
            
            % Increment E3_count to keep track of number of times E3 condition is hit.
            E3_count = E3_count+1;
        end
    end
end
 
% Terminate encoding
bin_low = de2bi(dec_low, N, 'left-msb');
if E3_count==0,
    % Just transmit the final value of the lower bound bin_low       
    code(code_index:code_index + N - 1) = bin_low;
    code_index = code_index + N;
else
   % Transmit the MSB of bin_low. 
   b = bin_low(1);
   code(code_index) = b;
   code_index = code_index + 1;
   
   % Then transmit complement of b (MSB of bin_low), E3_count times. 
   code(code_index:code_index+E3_count-1) = bitcmp(b, 1).*ones(1, E3_count);
   code_index = code_index + E3_count;

   % Then transmit the remaining bits of bin_low
   code(code_index:code_index+N-2) = bin_low(2:N);
   code_index = code_index + N - 1;
end          

% Output only the filled values
code = code(1:code_index-1);

% Set the same output orientation as seq
if (row_s > 1)
    code = code.';
end

%----------------------------------------------------------
function eStr = errorchk(seq, counts)
% Function for validating the input parameters. 

eStr.ecode = 0;
eStr.emsg = '';

% Check to make sure a vector has been entered as input and not a matrix
if (length(find(size(seq)==1)) ~= 1)
    eStr.emsg = ['The symbol sequence parameter must be a vector of positive ',...
                 'finite integers.'];
    eStr.ecode = 1; return;    
end

% Check to make sure a character array is not specified for SEQ
if ischar(seq)
    eStr.emsg = ['The symbol sequence parameter must be a vector of positive ',...
                 'finite integers.'];
    eStr.ecode = 1; return;    
end

% Check to make sure that finite positive integer values (non-complex) are 
% entered for SEQ
if ~all(seq > 0) || ~all(isfinite(seq)) || ~isequal(seq, round(seq)) || ...
    ~isreal(seq)
    eStr.emsg = ['The symbol sequence parameter must be a vector of positive ',...
                 'finite integers.'];
    eStr.ecode = 1; return;    
end

if length(find(size(counts)==1)) ~= 1
    eStr.emsg = ['The symbol counts parameter must be a vector of positive ',...
                 'finite integers.'];
    eStr.ecode = 1; return;    
end

% Check to make sure that finite positive integer values (non-complex) are
% entered for COUNTS
if ~all(counts > 0) || ~all(isfinite(counts)) || ~isequal(counts, round(counts)) || ...
     ~isreal(counts)
    eStr.emsg = ['The symbol counts parameter must be a vector of positive ',...
                 'finite integers.'];
    eStr.ecode = 1; return;    
end

% Check to ensure that the maximum value in the SEQ vector is less than or equal
% to the length of the counts vector COUNTS.
if max(seq) > length(counts)
    eStr.emsg = ['The symbol sequence parameter can take values only between',...
                 ' 1 and the length of the symbol counts parameter.'];
    eStr.ecode = 1; return;    
end

% [EOF]



function dseq = arithdeco(code, counts, len)
%ARITHDECO Decode binary code using arithmetic decoding.
%   DSEQ = ARITHDECO(CODE, COUNTS, LEN) decodes the binary arithmetic code
%   in the vector CODE (generated using ARITHENCO) to the corresponding
%   sequence of symbols. The vector COUNTS contains the symbol counts (the
%   number of times each symbol of the source's alphabet occurs in a test
%   data set) and represents the source's statistics. LEN is the number of
%   symbols to be decoded. 
%   
%   Example: 
%     Consider a source whose alphabet is {x, y, z}. A 177-symbol test data 
%     set from the source contains 29 x's, 48 y's and 100 z's. To encode the 
%     sequence yzxzz, use these commands:
%
%       seq = [2 3 1 3 3];
%       counts = [29 48 100];
%       code = arithenco(seq, counts)   
%            
%     To decode this code (and recover the sequence of  
%     symbols it represents) use this command:
%            
%       dseq = arithdeco(code, counts, 5)
%            
%   See also ARITHENCO.

%   Copyright 1996-2002 The MathWorks, Inc.
%   $Revision: 1.2 $ $Date: 2002/04/14 20:12:32 $

%   References:
%         [1] Sayood, K., Introduction to Data Compression, 
%         Morgan Kaufmann, 2000, Chapter 4, Section 4.4.3.


% Check the incoming orientation and adjust if necessary
[row_cd, col_cd] = size(code);
if (row_cd > 1),
    code = code.';
end

[row_c, col_c] = size(counts);
if (row_c > 1),
    counts = counts.';
end

% Compute the cumulative counts vector from the counts vector
cum_counts = [0, cumsum(counts)];

% Compute the Word Length (N) required.
total_count = cum_counts(end);
N = ceil(log2(total_count)) + 2;

% Initialize the lower and upper bounds.
dec_low = 0;
dec_up = 2^N-1;

% Read the first N number of bits into a temporary tag bin_tag
bin_tag = code(1:N);
dec_tag = bi2de(bin_tag, 'left-msb');

% Initialize DSEQ
dseq = zeros(1,len);
dseq_index = 1;

k=N;
ptr = 0;

% This loop runs untill all the symbols are decoded into DSEQ
while (dseq_index <= len)
    
    % Compute dec_tag_new
    dec_tag_new =floor( ((dec_tag-dec_low+1)*total_count-1)/(dec_up-dec_low+1) );
    
    % Decode a symbol based on dec_tag_new
    ptr = pick(cum_counts, dec_tag_new);
    
    % Update DSEQ by adding the decoded symbol
    dseq(dseq_index) = ptr;
    dseq_index = dseq_index + 1;
    
    % Compute the new lower bound
    dec_low_new = dec_low + floor( (dec_up-dec_low+1)*cum_counts(ptr-1+1)/total_count );
    
    % Compute the new upper bound
    dec_up = dec_low + floor( (dec_up-dec_low+1)*cum_counts(ptr+1)/total_count )-1;
    
    % Update the lower bound
    dec_low = dec_low_new;
    
    % Check for E1, E2 or E3 conditions and keep looping as long as they occur.
     while ( isequal(bitget(dec_low, N), bitget(dec_up, N)) | ...
        ( isequal(bitget(dec_low, N-1), 1) & isequal(bitget(dec_up, N-1), 0) ) ),
        
        % Break out if we have finished working with all the bits in CODE
        if ( k==length(code) ), break, end;
        k = k + 1;

        % If it is an E1 or E2 condition, do
        if isequal(bitget(dec_low, N), bitget(dec_up, N)),

            % Left shifts and update
            dec_low = bitshift(dec_low, 1) + 0;
            dec_up  = bitshift(dec_up,  1) + 1;

            % Left shift and read in code
            dec_tag = bitshift(dec_tag, 1) + code(k);

            % Reduce to N for next loop
            dec_low = bitset(dec_low, N+1, 0);
            dec_up  = bitset(dec_up,  N+1, 0);
            dec_tag = bitset(dec_tag, N+1, 0);
        
        % Else if it is an E3 condition        
        elseif ( isequal(bitget(dec_low, N-1), 1) & ...
            isequal(bitget(dec_up, N-1), 0) ),

            % Left shifts and update
            dec_low = bitshift(dec_low, 1) + 0;
            dec_up  = bitshift(dec_up,  1) + 1;

            % Left shift and read in code
            dec_tag = bitshift(dec_tag, 1) + code(k);
            
            % Reduce to N for next loop
            dec_low = bitset(dec_low, N+1, 0);
            dec_up  = bitset(dec_up,  N+1, 0);
            dec_tag = bitset(dec_tag, N+1, 0);
            
            % Complement the new MSB of dec_low, dec_up and dec_tag
            dec_low = bitxor(dec_low, 2^(N-1) );
            dec_up  = bitxor(dec_up,  2^(N-1) );
            dec_tag = bitxor(dec_tag, 2^(N-1) );

        end
    end % end while
end % end while length(dseq)

% Set the same output orientation as code
if (row_cd > 1)
    dseq = dseq.';
end
%-------------------------------------------------------------
function [ptr] = pick(cum_counts, value);
% This internal function is used to find where value is positioned

% Check for this case and quickly exit
if value == cum_counts(end)
    ptr = length(cum_counts)-1;
    return
end

c = find(cum_counts <= value);
ptr = c(end);

% EOF


function b = de2bi(varargin) 
%DE2BI Convert decimal numbers to binary numbers. 
%   B = DE2BI(D) converts a nonnegative integer decimal vector D to a binary 
%   matrix B. Each row of the binary matrix B corresponds to one element of D. 
%   The default orientation of the of the binary output is Right-MSB; the first 
%   element in B represents the lowest bit. 
% 
%   In addition to the vector input, three optional parameters can be given: 
% 
%   B = DE2BI(...,N) uses N to define how many digits (columns) are output. 
% 
%   B = DE2BI(...,N,P) uses P to define which base to convert the decimal 
%   elements to. 
% 
%   B = DE2BI(...,FLAG) uses FLAG to determine the output orientation.  FLAG 
%   has two possible values, 'right-msb' and 'left-msb'.  Giving a 'right-msb' 
%   FLAG does not change the function's default behavior.  Giving a 'left-msb' 
%   FLAG flips the output orientation to display the MSB to the left. 
% 
%   Examples: 
%    D = [12; 5]; 
% 
%    B = de2bi(D)                   B = de2bi(D,5) 
%   B =                             B = 
%        0     0     1     1             0     0     1     1     0 
%        1     0     1     0             1     0     1     0     0 
% 
%    T = de2bi(D,[],3)              B = de2bi(D,5,'left-msb') 
%   T =                             B = 
%        0     1     1                   0     1     1     0     0 
%        2     1     0                   0     0     1     0     1 
% 
%   See also BI2DE. 
 
%   Copyright 1996-2001 The MathWorks, Inc. 
%   $Revision: 1.16 $  $Date: 2001/04/23 15:32:11 $ 
 
% Typical error checking. 
error(nargchk(1,4,nargin)); 
 
% --- Placeholder for the signature string. 
sigStr = ''; 
flag = ''; 
p = []; 
n = []; 
 
% --- Identify string and numeric arguments 
for i=1:nargin 
   if(i>1) 
      sigStr(size(sigStr,2)+1) = '/'; 
   end; 
   % --- Assign the string and numeric flags 
   if(ischar(varargin{i})) 
      sigStr(size(sigStr,2)+1) = 's'; 
   elseif(isnumeric(varargin{i})) 
      sigStr(size(sigStr,2)+1) = 'n'; 
   else 
      error('Only string and numeric arguments are accepted.'); 
   end; 
end; 
 
% --- Identify parameter signitures and assign values to variables 
switch sigStr 
   % --- de2bi(d) 
   case 'n' 
      d		= varargin{1}; 
 
	% --- de2bi(d, n) 
	case 'n/n' 
      d		= varargin{1}; 
      n		= varargin{2}; 
 
	% --- de2bi(d, flag) 
	case 'n/s' 
      d		= varargin{1}; 
      flag	= varargin{2}; 
 
	% --- de2bi(d, n, flag) 
	case 'n/n/s' 
      d		= varargin{1}; 
      n		= varargin{2}; 
      flag	= varargin{3}; 
 
	% --- de2bi(d, flag, n) 
	case 'n/s/n' 
      d		= varargin{1}; 
      flag	= varargin{2}; 
      n		= varargin{3}; 
 
	% --- de2bi(d, n, p) 
	case 'n/n/n' 
      d		= varargin{1}; 
      n		= varargin{2}; 
      p  	= varargin{3}; 
 
	% --- de2bi(d, n, p, flag) 
	case 'n/n/n/s' 
      d		= varargin{1}; 
      n		= varargin{2}; 
      p  	= varargin{3}; 
      flag	= varargin{4}; 
 
	% --- de2bi(d, n, flag, p) 
	case 'n/n/s/n' 
      d		= varargin{1}; 
      n		= varargin{2}; 
      flag	= varargin{3}; 
      p  	= varargin{4}; 
 
	% --- de2bi(d, flag, n, p) 
	case 'n/s/n/n' 
      d		= varargin{1}; 
      flag	= varargin{2}; 
      n		= varargin{3}; 
      p  	= varargin{4}; 
 
   % --- If the parameter list does not match one of these signatures. 
   otherwise 
      error('Syntax error.'); 
end; 
 
if isempty(d) 
   error('Required parameter empty.'); 
end 
 
d = d(:); 
len_d = length(d); 
 
if max(max(d < 0)) | max(max(~isfinite(d))) | (~isreal(d)) | (max(max(floor(d) ~= d))) 
   error('Input must contain only finite real positive integers.'); 
end 
 
% Assign the base to convert to. 
if isempty(p) 
    p = 2; 
elseif max(size(p) ~= 1) 
   error('Destination base must be scalar.'); 
elseif (~isfinite(p)) | (~isreal(p)) | (floor(p) ~= p) 
   error('Destination base must be a finite real integer.'); 
elseif p < 2 
   error('Cannot convert to a base of less than two.'); 
end; 
 
% Determine minimum length required. 
tmp = max(d); 
if tmp ~= 0 				% Want base-p log of tmp. 
   ntmp = floor( log(tmp) / log(p) ) + 1; 
else 							% Since you can't take log(0). 
   ntmp = 1; 
end 
 
% This takes care of any round off error that occurs for really big inputs. 
if ~( (p^ntmp) > tmp ) 
   ntmp = ntmp + 1; 
end 
 
% Assign number of columns in output matrix. 
if isempty(n) 
   n = ntmp; 
elseif max(size(n) ~= 1) 
   error('Specified number of columns must be scalar.'); 
elseif (~isfinite(n)) | (~isreal(n)) | (floor(n) ~= n) 
   error('Specified number of columns must be a finite real integer.'); 
elseif n < ntmp 
   error('Specified number of columns in output matrix is too small.'); 
end 
 
% Check if the string flag is valid. 
if isempty(flag) 
   flag = 'right-msb'; 
elseif ~(strcmp(flag, 'right-msb') | strcmp(flag, 'left-msb')) 
   error('Invalid string flag.'); 
end 
 
% Initial value. 
b = zeros(len_d, n); 
 
% Perform conversion. 
for i = 1 : len_d                   % Cycle through each element of the input vector/matrix. 
    j = 1; 
    tmp = d(i); 
    while (j <= n) & (tmp > 0)      % Cycle through each digit. 
        b(i, j) = rem(tmp, p);      % Determine current digit. 
        tmp = floor(tmp/p); 
        j = j + 1; 
    end; 
end; 
 
% If a flag is specified to flip the output such that the MSB is to the left. 
if strcmp(flag, 'left-msb') 
 
   b2 = b; 
   b = b2(:,n:-1:1); 
 
end 
 
% [EOF] de2bi.m 

function d = bi2de(b, varargin) 
%BI2DE Convert binary vectors to decimal numbers. 
%   D = BI2DE(B) converts a binary vector B to a decimal value D. When B is a 
%   matrix, the conversion is performed row-wise and the output D is a column 
%   vector of decimal values. The default orientation of the binary input 
%   is Right-MSB; the first element in B represents the least significant bit. 
% 
%   In addition to the input matrix, two optional parameters can be given: 
% 
%   D = BI2DE(...,P) converts a base P vector to a decimal value. 
% 
%   D = BI2DE(...,FLAG) uses FLAG to determine the input orientation.  FLAG has 
%   two possible values, 'right-msb' and 'left-msb'.  Giving a 'right-msb' FLAG 
%   does not change the function's default behavior.  Giving a 'left-msb' 
%   FLAG flips the input orientation such that the MSB is on the left. 
% 
%   Examples: 
%    B = [0 0 1 1; 1 0 1 0]; 
%    T = [0 1 1; 2 1 0]; 
% 
%    D = bi2de(B)       D = bi2de(B,'left-msb')       D = bi2de(T,3) 
%   D =                 D =                            D = 
%       12                   3                             12 
%        5                  10                              5 
% 
%   See also DE2BI. 
 
%   Copyright 1996-2004 The MathWorks, Inc. 
%   $Revision: 1.15.4.1 $  $Date: 2004/08/10 01:32:22 $ 
 
 
% Typical error checking. 
error(nargchk(1,3,nargin)); 
 
% --- Placeholder for the signature string. 
sigStr = ''; 
flag = ''; 
p = []; 
 
% Check the type of the input B 
if ~(isnumeric(b) || islogical(b)) 
    error('The binary input must be numeric or logical.'); 
end 
b = double(b);  % To allow logicals to work 
 
% --- Identify string and numeric arguments 
for i=1:length(varargin) 
   if(i>1) 
      sigStr(size(sigStr,2)+1) = '/'; 
   end 
   % --- Assign the string and numeric flags 
   if(ischar(varargin{i})) 
      sigStr(size(sigStr,2)+1) = 's'; 
   elseif(isnumeric(varargin{i})) 
      sigStr(size(sigStr,2)+1) = 'n'; 
   else 
      error('Optional parameters must be string or numeric.'); 
   end 
end 
 
% --- Identify parameter signitures and assign values to variables 
switch sigStr 
     
    % --- bi2de(d) 
    case '' 
         
	% --- bi2de(d, p) 
	case 'n' 
      p		= varargin{1}; 
 
	% --- bi2de(d, flag) 
	case 's' 
      flag	= varargin{1}; 
 
	% --- bi2de(d, p, flag) 
	case 'n/s' 
      p		= varargin{1}; 
      flag	= varargin{2}; 
 
	% --- bi2de(d, flag, p) 
	case 's/n' 
      flag	= varargin{1}; 
      p		= varargin{2}; 
 
   % --- If the parameter list does not match one of these signatures. 
   otherwise 
      error('Syntax error.'); 
end 
 
if isempty(b) 
   error('Required parameter empty.'); 
end 
 
if max(max(b < 0)) || max(max(~isfinite(b))) || (~isreal(b)) || ... 
     (max(max(floor(b) ~= b))) 
    error('Input must contain only finite real positive integers.'); 
end 
 
% Set up the base to convert from. 
if isempty(p) 
    p = 2; 
elseif max(size(p)) > 1 
   error('Source base must be a scalar.'); 
elseif (floor(p) ~= p) || (~isfinite(p)) || (~isreal(p)) 
   error('Source base must be a finite real integer.'); 
elseif p < 2 
   error('Source base must be greater than or equal to two.'); 
end 
 
if max(max(b)) > (p-1) 
   error('The elements of the matrix are larger than the base can represent.'); 
end 
 
n = size(b,2); 
 
% If a flag is specified to flip the input such that the MSB is to the left. 
if isempty(flag) 
   flag = 'right-msb'; 
elseif ~(strcmp(flag, 'right-msb') || strcmp(flag, 'left-msb')) 
   error('Invalid string flag.'); 
end 
 
if strcmp(flag, 'left-msb') 
 
   b2 = b; 
   b = b2(:,n:-1:1); 
 
end 
 
%%% The conversion 
max_length = 1024; 
pow2vector = p.^(0:1:(size(b,2)-1)); 
size_B = min(max_length,size(b,2)); 
d = b(:,1:size_B)*pow2vector(:,1:size_B).'; 
 
% handle the infs... 
idx = find(max(b(:,max_length+1:size(b,2)).') == 1); 
d(idx) = inf; 
 
% [EOF] 

Contact us at files@mathworks.com