A short example MATLAB script for producing a M-OCK signal followed by a simplistic decoder. Assumes perfect synchronisation.

This is a short and (overly) simple example for producing a bandlimited M-OCK signal and subsequently demodulating the received signal. This example uses hardcoded m-sequences to demonstrate a K7 16-OCK signal. Perfect synchronisation is assumed in this example, although the paper referenced below does explore synchronisation structures as well as the associated receiver structures. For further information please read the associated paper dx.doi.org/10.1109/OCEANS-Genova.2015.7271500. If you should make use of this research/software then cite as below.

Cite:

B. Sherlock, C. C. Tsimenidis and J. A. Neasham, “Signal and receiver design for low-power acoustic communications using m-ary orthogonal code keying,” OCEANS 2015 – Genova, Genoa, 2015, pp. 1-10. doi: 10.1109/OCEANS-Genova.2015.7271500

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
% M-ary Orthogonal Code Keying (M-OCK) MATLAB Example
% Benjamin Sherlock 2016-05-02
% www.bensherlock.co.uk
%
% This is a short and (overly) simple example for producing a bandlimited
% M-OCK signal and subsequently demodulating the received signal.
% This example uses hardcoded m-sequences to demonstrate a K7 16-OCK
% signal. Perfect synchronisation is assumed in this example, although the
% paper referenced below does explore synchronisation structures as well as
% the associated receiver structures.
%
% For further information please read the associated paper below. If you
% should make use of this research/software then cite as below.
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
% Copyright (c) 2015 Benjamin Sherlock, Newcastle University, UK.
% All rights reserved.
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
% Cite:
%
% B. Sherlock, C. C. Tsimenidis and J. A. Neasham, "Signal and receiver
% design for low-power acoustic communications using m-ary orthogonal code
% keying," OCEANS 2015 - Genova, Genoa, 2015, pp. 1-10.
% doi: 10.1109/OCEANS-Genova.2015.7271500
%
%
% URL: http://dx.doi.org/10.1109/OCEANS-Genova.2015.7271500
%
% Abstract: Low-power, low received signal-to-noise-ratio (SNR) signals
% have potential for reducing the impact on marine life from acoustic
% communications. Here we explore the use of bandlimited pseudo-noise m-ary
% orthogonal code keying (MOCK) scheme using m-sequences. Analysis and
% simulation of receiver structure for synchronisation and data
% demodulation performance is carried out. Performance of M-OCK is compared
% with m-ary quadrature amplitude modulation with direct-sequence
% spread-spectrum (M-QAM DSSS). Real-world channel experiments are carried
% out with transmission power for the MOCK sequences limited to less than
% 1 W acoustic power (170.8 dB re 1 ?Pa at 1 m) and transmission range
% varied from 100 m to 10 km in the North Sea. Synchronisation at 10 km is
% achieved with effective received signal-to-noise-ratio of less than
% -9.96 dB, and data demodulation of 140.7 bit/s raw throughput with
% pre-coding bit-error-rate (BER) 0.5 × 10-1 (symbol-error-rate (SER) 0.1)
% and 46.9 bit/s raw throughput with pre-coding BER 0.9 × 10-3
% (SER 1.95 × 10-3). Error-free synchronisation and data demodulation is
% achieved at ranges up to 2 km, demonstrating data rates in excess of
% 140 bit/s.
%
% keywords: {acoustic receivers;bandlimited communication;demodulation;
% error statistics;orthogonal codes;precoding;pseudonoise codes;
% synchronisation;underwater acoustic communication;BER;M-OCK sequence;
% M-QAM DSSS;North sea;SER;SNR signal;acoustic power;bandlimited
% pseudonoise m-ary orthogonal code keying;data demodulation;error-free
% synchronisation;low-power acoustic communication;m-ary quadrature
% amplitude modulation with direct sequence spread-spectrum;marine life;
% precoding bit-error-rate;receiver design;signal-to-noise-ratio;
% symbol-error-rate;synchronisation;Band-pass filters;Binary phase shift
% keying;Correlation;Demodulation;Receivers;Signal to noise ratio;
% Synchronization;low-power;m-ary orthogonal code keying;m-ock;orthogonal
% signaling;underwater acoustic communications}
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

% Sample rate used throughout
Fs = 48e3;

% Bandpass Filter configuration
bandpass_f_low_hz = 8e3;
bandpass_f_high_hz = 12e3;
bandpass_order = 80;

bandpass_filter = fir1(bandpass_order, [ bandpass_f_low_hz/(Fs/2) bandpass_f_high_hz/(Fs/2) ]);

% M-OCK Configuration for K7 16-OCK
K = 7;
M = 16;

% The Hardcoded M-Sequence Code Bank for K7 16-OCK
code_length = (2^K)-1;
codebank = [
[1,1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,1,-1,1,-1,-1,-1,1,1,1,1,-1,-1,1,-1,-1,-1,1,-1,1,1,-1,-1,1,1,1,-1,1,-1,1,-1,-1,1,1,1,1,1,-1,1,-1,-1,-1,-1,1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,1,-1,1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,-1,-1,1,1,-1,-1,1,-1,1,-1,1,-1,1],
[1,1,1,1,-1,-1,-1,-1,1,1,1,-1,1,1,1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,-1,-1,-1,1,-1,1,1,1,-1,1,-1,1,1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,1,1,1,-1,1,1,-1,1,-1,-1,-1,-1,1,-1,1,-1,1,-1,1,1,1,1,1,-1,1,-1,-1,1,-1,1,-1,-1,-1,1,1,-1,1,1,1,-1,-1,-1,1,1,1],
[1,1,1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,-1,1,-1,1,1,1,1,-1,1,1,-1,1,1,1,-1,1,1,1,1,1,1,1,-1,-1,-1,-1,1,-1,1,-1,1,1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,-1,1,-1,1,-1,1,-1,-1,-1,-1,-1,1,1,-1,-1,1,-1,-1,-1,-1,1,1,1,-1,1,-1,1,1,1,-1,-1,1,1,1,-1,-1,-1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,-1,1],
[1,1,1,-1,-1,-1,1,1,1,-1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,-1,1,1,1,1,1,-1,1,-1,1,-1,1,-1,-1,-1,-1,1,-1,1,1,-1,1,1,1,1,-1,-1,1,1,1,-1,-1,1,-1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,-1,-1,1,1,-1,1,1,-1,1,-1,1,1,1,-1,1,-1,-1,-1,1,1,-1,-1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,1,1,1,-1,1,1,1,-1,-1,-1,-1,1,1,1,1],
[1,1,1,-1,1,-1,1,1,-1,1,-1,1,-1,-1,1,1,-1,1,1,-1,-1,1,1,1,-1,1,1,-1,1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,-1,-1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,1,1,1,-1,-1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,1,1,1,-1,-1,-1,1,-1,1,-1,1,-1,1,1,1,1,-1,-1,1,1,-1,-1,1,-1,1,-1,-1,-1,1,-1,-1,-1,1,1,-1,-1,-1,-1,1,1,1,1,-1,1,1],
[1,1,-1,-1,1,-1,-1,-1,1,1,-1,-1,-1,1,-1,1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,1,1,-1,1,1,1,1,1,1,1,-1,-1,1,1,-1,1,1,-1,1,-1,1,-1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,-1,-1,1,1,1,1,-1,-1,-1,1,1,1,-1,1,1,1,-1,1,-1,1,1,1,1,-1,1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,-1,-1,1],
[1,1,-1,-1,-1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,1,-1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,1,1,1,-1,-1,-1,1,-1,1,1,-1,1,-1,1,1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,-1,1,1,1,1,-1,1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,-1,-1,1,1,-1,-1,-1,1,1,1,-1,-1,1,-1,1,-1,1,-1,1,1,1,-1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,-1,1,1,1,1,1,-1,1,1,-1,1],
[1,1,-1,1,1,1,1,-1,-1,-1,-1,1,1,-1,-1,-1,1,-1,-1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,1,1,1,-1,1,-1,1,-1,1,-1,-1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,-1,1,1,1,-1,1,-1,-1,-1,-1,1,-1,-1,1,1,1,-1,-1,-1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,1,1,-1,1,1,-1,1,1,1,-1,-1,1,1,-1,1,1,-1,-1,1,-1,1,-1,1,1,-1,1,-1,1,1,1],
[1,1,-1,1,1,-1,1,-1,-1,1,1,1,1,-1,-1,-1,-1,1,-1,-1,1,1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,-1,1,1,1,-1,-1,1,1,-1,-1,1,-1,1,1,1,1,-1,1,-1,1,-1,-1,1,-1,1,-1,1,-1,1,1,1,-1,-1,-1,1,1,1,1,1,-1,1,1,1,1,1,1,1,-1,-1,1,-1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,-1,1,1,-1,1,1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,-1,1],
[1,-1,1,-1,1,-1,1,-1,-1,1,1,-1,-1,1,1,1,-1,1,1,1,-1,1,-1,-1,1,-1,1,1,-1,-1,-1,1,1,-1,1,1,1,1,-1,1,1,-1,1,-1,1,1,-1,1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,1,1,-1,-1,-1,-1,1,-1,1,1,1,1,1,-1,-1,1,-1,1,-1,1,1,1,-1,-1,1,1,-1,1,-1,-1,-1,1,-1,-1,1,1,1,1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,1,1],
[1,-1,1,-1,-1,1,-1,1,-1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,1,-1,-1,1,-1,1,1,1,1,1,1,1,-1,1,-1,1,1,-1,1,1,1,-1,1,1,1,1,-1,-1,-1,1,1,1,-1,1,-1,-1,-1,1,-1,1,-1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,1,-1,-1,1,1,1,1,1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,-1,1,1,-1,1,-1,1,-1,1,-1,-1,1,1,-1,1],
[1,-1,1,1,-1,-1,1,-1,1,-1,1,-1,1,1,-1,-1,-1,1,-1,-1,-1,-1,-1,1,-1,-1,1,1,1,1,1,-1,-1,1,1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,1,1,1,-1,-1,-1,-1,-1,-1,1,1,1,-1,1,-1,1,-1,-1,-1,1,-1,1,1,1,-1,-1,-1,1,1,1,1,-1,1,1,1,-1,1,1,-1,1,-1,1,1,1,1,1,1,1,-1,1,-1,-1,1,1,-1,-1,-1,-1,1,1,-1,1,-1,-1,-1,-1,1,-1,1,-1,-1,1,-1,1],
[1,-1,1,1,-1,1,1,1,1,1,-1,-1,1,1,1,1,1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,1,1,1,-1,1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,1,1,-1,-1,-1,1,-1,1,1,1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,1,-1,-1,-1,-1,1,1,-1,1,-1,1,1,-1,1,-1,-1,-1,1,1,1,1,-1,-1,-1,-1,-1,1,-1,-1,1,1,-1,1,1,-1,-1,-1,-1,1,-1,1,-1,-1,-1,-1,-1,-1,1,1],
[1,-1,-1,1,-1,1,-1,-1,1,1,-1,1,-1,-1,1,-1,1,1,1,1,-1,1,-1,1,1,1,-1,1,1,1,-1,-1,-1,1,1,1,1,-1,-1,1,1,-1,-1,1,-1,-1,1,-1,-1,-1,1,-1,1,-1,1,-1,1,1,-1,1,1,-1,-1,1,1,1,1,1,1,1,-1,1,1,-1,1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,1,1,1,1,1,-1,-1,-1,-1,-1,1,-1,1,1,-1,-1,-1,-1,1,-1,-1,-1,-1,1,1,1,-1,1,-1,-1,-1,1,1,-1,-1,-1,1,-1,-1,1,1],
[1,-1,-1,1,1,-1,1,1,-1,1,-1,-1,-1,1,1,1,1,1,-1,-1,-1,-1,1,1,1,-1,-1,-1,1,-1,1,-1,-1,1,1,-1,-1,-1,-1,-1,-1,1,1,-1,1,-1,1,1,1,-1,1,-1,-1,1,-1,1,-1,1,-1,1,1,-1,1,1,1,-1,-1,1,-1,-1,-1,-1,1,-1,-1,-1,1,-1,-1,1,-1,-1,1,1,1,1,-1,1,-1,1,-1,-1,-1,-1,-1,1,-1,1,1,1,1,-1,-1,1,1,1,-1,1,1,1,1,1,1,1,-1,1,1,-1,-1,1,-1,1,1,-1,-1,-1,1],
[1,-1,-1,-1,1,-1,-1,-1,-1,-1,-1,1,1,-1,-1,1,1,-1,1,1,-1,-1,-1,1,1,1,-1,-1,1,1,1,-1,1,-1,1,1,1,-1,-1,-1,-1,1,-1,-1,1,1,-1,-1,-1,-1,-1,1,-1,1,-1,1,-1,1,1,-1,1,-1,-1,1,-1,-1,1,-1,1,-1,-1,1,1,1,1,-1,-1,1,-1,-1,-1,1,1,-1,1,-1,1,-1,-1,-1,-1,1,1,1,1,1,1,1,-1,1,1,1,-1,1,1,-1,1,1,1,1,-1,1,-1,-1,-1,1,-1,1,1,-1,-1,1,-1,1,1,1,1]];

% Randomly generate the data to be transmitted
% - nibbles as in this case (16-OCK) each symbol carries one nibble
data_symbol_count = 8;
original_data = randi([0 15], 1, data_symbol_count);

% Generate the payload symbols
original_pn = zeros(1, length(original_data * code_length));
for i = 1:data_symbol_count
% Copy the appropriate symbol from the code bank into the pn buffer.
original_pn(1, ((i-1)*code_length)+1:(i*code_length)) = codebank(original_data(1, i)+1, :);
end

% Bandlimit the packet to suit the transmit transducer's operating range
filtered_pn = conv(bandpass_filter, original_pn);

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
% Transmit the signal through the channel.
% Add your own channel effects here.
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
%
received_pn = filtered_pn;
%
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

% Receive the signal (assume perfect synchronisation)
% See the paper for examples of synchronisation structures based on PN
% sequences along with the associated receiver structures for successful
% synchronsation of low-received-SNR signals.

% Demodulate each symbol by correlating with all codes in the bank then
% selecting the code that produces the greatest magnitude result.

% Lowpass filter used to produce the envelope of the cross correlation
lowpass_order = 12;
lowpass_filter = fir1(lowpass_order, (bandpass_f_high_hz - bandpass_f_low_hz)/(Fs/2) );

% Window to search within for the peak xcorr result for each symbol
window_size = 6;

% Preallocate buffers for speed
received_data = zeros(1, data_symbol_count);
xcorred = zeros(1, (code_length+length(received_pn)-1));
xcorr_enveloped = zeros(1, (code_length+lowpass_order+length(received_pn)-1));

% For each symbol in the signal
for i = 1:data_symbol_count
% Window centre takes into account the offsets caused by convolution
% with bandpass and lowpass filters as well as the code.
window_centre_index = (bandpass_order/2) + (lowpass_order/2) + (i*code_length);

% Store the maximum in the search
max_xcorr_magnitude = 0;
max_xcorr_code_id = -1;

% For each code in the codebank
for code_id = 0:M-1
% Cross Correlate (Multiply and Accumulate)
xcorred(1,:) = conv( fliplr( codebank(code_id+1, :)), received_pn(1,:) );

    % Envelope
    % 1. Square and x2
    xcorred(1,:) = xcorred .* xcorred;
    xcorred(1,:) = xcorred * 2;

    % 2. Lowpass Filter
    xcorr_enveloped(1,:) = conv(lowpass_filter, xcorred);

    % 3. Squareroot
    xcorr_enveloped(1,:) = sqrt( abs(xcorr_enveloped) );

    % Now take the peak within the expected window
    xcorr_magnitude = max( xcorr_enveloped(1, window_centre_index-(window_size/2):window_centre_index+(window_size/2) ) );

    % Compare magnitude to find and store maximum
    if( xcorr_magnitude > max_xcorr_magnitude )
      max_xcorr_magnitude = xcorr_magnitude;
      max_xcorr_code_id = code_id;
    end
end
received_data(1, i) = max_xcorr_code_id;
end

% Compare the transmitted data against the received data.
fprintf('Compare the transmitted and received data\n');
for i = 1:data_symbol_count
fprintf('%d: Tx=%d \tRx=%d \n', i, original_data(i), received_data(i));
end

%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
% M-ary Orthogonal Code Keying (M-OCK) MATLAB Example
% Benjamin Sherlock 2016-05-02
% www.bensherlock.co.uk
%~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~