No BSD License  

Highlights from
Samplify Sampled Data Compression

image thumbnail
from Samplify Sampled Data Compression by Al Wegener
Samplify compresses samples used by A/D and D/A converters

samplify(x, opt)
function [y, opt] = samplify(x, opt)
%samplify Compress signal. 
%   [y, opt] = samplify(x,opt) compresses a vector of samples using the
%   settings given in the Samplify configuration structure opt. The input 
%   signal x to be samplified *must* be a one-dimensional vector (either 
%   1xN or Nx1), and can either be a normal MATLAB floating point array or
%   of integer type 'int8', 'uint8', 'int16', or 'uint16'.
%
%   The following fields in the configuration struct opt are pertinent to 
%   the operation of this Samplify For MATLAB function:
%
%   1) opt.Display: determines the verbosity of the samplify function,
%                   either 'off' or 'on'
%   2) opt.Mode: 'lossless', 'fixedRate', 'fixedDynRange', 'NoiseTrak'
%                (see user's manual for complete description of these modes)
%   3) opt.CompressionParameter: scalar, whose value is interpreted based 
%                                on the contents of #2.
%   This parameter is completely ignored in lossless mode. In fixedRate it
%   signifies the desired compression ratio (i.e. opt.CompressionMode = 2.0
%   implies 2:1 compression between the samplified data and the
%   uncompressed, original data). In fixed dynamic range ('fixedDynRange')
%   mode the units of this field are dB, while in NoiseTrak mode the units
%   are bits.
%   4) opt.InputDataType: One of 'int8', 'uint8', 'int16', 'uint16',
%   'float', or 'double'. This field gives the data type for how the sample 
%   values of x should be interpreted. It is not mandatory to specify this, 
%   and if not provided, it is inferred from the data type of x. That is, if
%   x if of type UINT8, then that is the same as if opt.InputDataType='int8'.
%
%   This function also modifies opt because depending on the value of 
%   opt.Mode, certain information potentially needed by DESAMPLIFY is
%   returned back to the user inside of opt. In particular, the # of 
%   samples in x is stored here, as well the Samplify block sizes and
%   noise-floor estimates (where appropriate). If floating-point
%   compression is being used (i.e. opt.InputDataType='float',
%   opt.InputDataType='double', _or_ x's data type is single/double precision
%   _and_ opt.InputDataType is not explicitly specified), then opt will
%   contain per-bock scale factors.
%
%   Examples
%   --------
%       % losslessly compress a signal vector sig
%       [c,opt] = samplify(sig, samplifyOptions('Mode','lossless'));
%
%       % Verbose mode, 2:1 fixed-rate compression of 16-bit signed vector sig
%       opt = samplifyOptions('Mode','fixedRate','CompressionParameter',2.0,'InputDataType','int16');
%       [c,opt] = samplify(sig, opt);
%
%   See also SAMPLIFYOPTIONS, DESAMPLIFY

%   Copyright 2005 Samplify Systems LLC
%   Revision: 1.0 (2005/11/23)

sanity_check_x(x);
sanity_check_options(opt);

if isfield(opt, 'Display')
    if strcmpi(opt.Display, 'on')
        display_options(opt);
    end
end

xprime = handle_data_type(x, opt);
%if isfloat(xprime) MATLAB R12 doesn't have isfloat()
if isa(xprime,'float')
    % sanity check, remember that floating-point and lossless compression 
    % isn't possible!
    if strcmpi(opt.Mode, 'lossless')
        error('Lossless mode not supported with floating-point input.');
    end
    % then we need to normalize the input to samplify such that the input
    % vector fits nicely into a signed 16-bit array
    [xprime, opt] = handle_floating_point_array(xprime, opt);
end
cparam = opt.CompressionParameter;
if strcmpi(opt.Mode, 'lossless')
    [y, opt.orig_nsamps, opt.InputDataType, opt.block_sizes, opt.nf_est] = samplify_mex(1, xprime, 0);
elseif strcmpi(opt.Mode, 'fixedRate')
    cparam = opt.CompressionParameter;
    [y, opt.orig_nsamps, opt.InputDataType, opt.block_sizes, opt.nf_est, opt.dr] = samplify_mex(1, xprime, 1, cparam);
elseif strcmpi(opt.Mode, 'fixedDynRange')
    [y, opt.orig_nsamps, opt.InputDataType, opt.block_sizes, opt.nf_est, opt.dr] = samplify_mex(1, xprime, 2, cparam);
elseif strcmpi(opt.Mode, 'NoiseTrak')
    [y, opt.orig_nsamps, opt.InputDataType, opt.block_sizes, opt.nf_est, opt.dr] = samplify_mex(1, xprime, 3, cparam); 
else
    error(['Unknown mode ' opt.Mode]);
end

function sanity_check_x(x)
%
% SANITY_CHECK_X
%

if ~isnumeric(x)
    error('Input samples have to be a numeric array.');
end

if ndims(x) > 2
    error('Input samples must be a 1xN or Nx1 vector.');
else
    if length(x) < 192
        error('Input vector too small.');
    else
        [M N] = size(x);
        if 1~=M & 1~=N
           error('Input samples must be a 1xN or Nx1 vector.');
        end
    end
end

function sanity_check_options(options)
%
% SANITY_CHECK_OPTIONS
%

if ~isstruct(options)
    error('Malformed samplify options structure.');
end

% leverage samplifyOptions.m, which already does all 
% the error checking for us

% first build up the parameter value string
% 'PARAM1',VALUE1,'PARAM2',VALUE2,...
names = fieldnames(options);
params_vals = [];
for ifield = 1:length(names)
    value = sprintf('options.%s', names{ifield});
    if ~isempty(eval(value))
        % User could theoretically pass in a samplify options struct
        % containing come of the samplify.m generated fields, like
        % options.block_sizes, options.nf_est, and so on. By verifying that
        % if it's a numeric element it's length MUST be one we effectively
        % filter out alot (not all) of these.
        if isnumeric(eval(value))
            if 1 == eval(sprintf('length(%s)', value))
                params_vals = strcat(params_vals, sprintf(',%c%s%c,%f', 39, names{ifield}, 39, eval(value)));
            end
        elseif ischar(eval(value))
            params_vals = strcat(params_vals, sprintf(',%c%s%c,%c%s%c', 39, names{ifield}, 39, 39, eval(value), 39));
        else
            error('parameter values must be either scalar or string.');
        end
    end
end

% this will bomb out with an error in the event of a mal-formed
% samplify options structure
optdummy = eval(sprintf('samplifyOptions(%s)', params_vals(2:end)));

% one can invoke samplifyOptions without specifying all of the
% options - however here I absolutely must have all of them!
if ~isfield(options,'Mode')
    error('Samplify requires a mode (lossless, fixedRate, fixedDynRange, NoiseTrak) specification.');
end
if isempty(options.Mode)
    error('Samplify requires a mode (lossless, fixedRate, fixedDynRange, NoiseTrak) specification.');
end

if ~strcmpi(options.Mode, 'lossless')
   % require compression parameter arg
   if ~isfield(options, 'CompressionParameter')
       error('Missing compression parameter field.');
   end
   if isempty(options.CompressionParameter)
       error('Missing compression parameter field.'); 
   end
end

function display_options(options)
%
% DISPLAY_OPTIONS
%

disp('Samplify options are:');

disp(['  Mode is ' options.Mode]);

if strcmpi(options.Mode, 'fixedRate')
    disp(sprintf('  Compression ratio is %.3f', options.CompressionParameter));
elseif strcmpi(options.Mode, 'fixedDynRange')
    disp(['  Dynamic range is ' options.CompressionParameter ' dB']);
elseif strcmpi(options.Mode, 'NoiseTrak')
    disp(['  Noise-floor is ' options.CompressionParameter]);
end

if isfield(options, 'InputDataType') & ~isempty(options.InputDataType)
    disp(['  Data type hint is ' options.InputDataType]);
end

function [xprime, opt] = handle_floating_point_array(xprime, opt)
%
% HANDLE_FLOATING_POINT_ARRAY
%

[nwin, nblocks, istart, iend] = block_info(length(xprime));
for ii=1:nblocks
    idx = [istart(ii):iend(ii)];
    m = max( abs(xprime(idx)) );
    opt.FloatingPointNormalization(ii) = m;
    if 0 ~= m
        xprime(idx) = (32767/m) .* xprime(idx);
    end
end
xprime = int16(xprime);

Contact us at files@mathworks.com