image thumbnail

A Few Modulations

by

 

ASK, BPSK, FSK and QPSK modulations done by hand.

ask_mod

Contents

function modulated = ask_mod( msg, varargin )

A function to perform Amplitude Shift Keying

     Using good form and properly vectorized code, we generate the ASK
     sequence of the msg passed from user-land.  Plots are generated to
     show the result generated from the original bits.
     modulated = ASK_MOD( msg )  "msg" can be a row vector if you only want to modulate one
     message, or you can create a matrix... with the rows comprising the messages.  The
     result will be either a vector or a matrix of modulated signal.
     modulated = ASK_MOD( msg, samples_per_symbol ) The user can set the number of samples
     per symbol in the final modulated carrier.
     modulated = ASK_MOD( msg, samples_per_symbol, do_plot ) If the user wants to turn off
     the plotting, just set the third argument to anything.
     Example :
     >> msg = [1 0 0 0 1 1 1 0 1];
     >> ask_mod( msg );
     ** Poof... magic plots **
     Example #2 :
     >> msg = [[1 0 0 0 1 1 1 0 1]; [0 1 0 0 1 0 1 0 1]];
     >> ask_mod( msg );
     ** Poof... more magic plots **

SEE ALSO : BPSK_MOD, FSK_MOD, QPSK_MOD

    % Some input checking : Only allow 0's and 1's.
    if ~isempty(find( msg ~= 0 & msg ~= 1, 1 ))
        error( 'Only values between 0 and 1 are supported for modulation in ASK.' );
    end

    % Check the shape of what the user gave us.  I decided to make this work on matrices of
    % bits.  So each row will be a message.
    [m,n] = size(msg);

    % We're going to oversample a bit so we can see good resolution on the
    % sine wave we will be generating for the carrier wave.
    samples_per_symbol = 100;
    if nargin >= 2
        % Allow the user to override the samples per symbol
        samples_per_symbol = varargin{1};
    end

    % Let the user turn off verbose prints/plots
    doplot = 1;
    if nargin >= 3
        doplot = 0;
    end
Error using ask_mod (line 30)
Not enough input arguments.

Variable Declarations

    %Hz   Frequency of the carrier signal
    f = 200;

    % Generate our time vector for the sine wave generation.  We're
    % creating one period, so from 0->2*pi in steps of
    % 2*pi/samples_per_bit.  i.e. 0->2*pi in 100 steps, evenly divided.
    t=0:2*pi/(samples_per_symbol-1):2*pi;

    modulated = zeros( m, samples_per_symbol*n );

The actual work is done in the following 6 lines

This is a little bit of MATLAB magic. 'repmat' stands for replicate matrix. So, now 't' consists of cycles of 0->2*pi. There are as many cycles from 0->2*pi as we have bits in the original msg.

Alternatively, you could do this the n00b way and make a for loop like this...

temp( = []; % Make a matrix with scope outside the for loop. for n = 1:length(msg) temp = [temp t]; <---- This is matrix concatenation... end t = temp;

But one piece of advice : You should avoid for loops like the plague in MATLAB. There is almost always a "vectorized" way to accomplish the same task in MATLAB, and for loops are slow in m-code, while vectorization is blazing fast. Also, the for loop grows an array dynamically which also incurs memory allocation penalties which is slow and not good practice. In fact, MATLAB's lint tool has now started warning about that. n00bish. But repmat is pro.

    t = repmat( t, 1, n );

    % Now we need to oversample our msg.  This is for convenience in the
    % multiply later.  i.e. we want our 10011101 to look like...
    % 1111111 0000000 000000 1111111 11... etc.  We want as many
    % replications of the bits as we're oversampling... so samples_per_bit.
    % However, we've replicated the vector as follows...
    % 1 0 0 1 1 1 0 1
    % 1 0 0 1 1 1 0 1
    % . . . . . . . .
    % <samples_per_bit times>
    % . . . . . . . .
    % 1 0 0 1 1 1 0 1
    %
    % This is mainly because there's (amazingly) not a good/easy way to do
    % it in MATLAB.  (Rectpulse in the comms toolbox will do it for you, but
    % assuming you don't have that, there's this.)
    for k = 1:m
        temp = repmat( msg(k, :), samples_per_symbol, 1);

        % So it takes two steps to perform our oversample of the data.
        % This function reshapes that matrix of data by running
        % down the columns and placing the data into a single long vector, thus
        % accomplishing the goal of replicating the bits samples_per_bit times.
        %
        % The +1 at the end is to map the signal from 0,1 (which would create
        % OOK) to 1, 2 which creates ASK.  Take it out to see the difference.
        msg_upsampled = reshape( temp, samples_per_symbol*n, 1) + 1;

        % The following would also have worked, but it's even harder to explain
        % how it's doing the same thing...
        %
        % msg = msg(ones(1,samples_per_bit), :);
        % msg = msg(:) + 1;
        %
        % Alternatively, if you have the comms toolbox :
        %
        % msg = rectpulse( msg, samples_per_bit );

        % Now we generate our carrier sine wave.  Frequency * 0->2*pi over and
        % over again.  It makes a sin wave.  :)  The ' at the end transposes
        % the result from a row vector to a column vector so we can easily
        % multiply in the next step.
        carrier = sin(f * t )';

        % This is the actual carrier modulation step.  Here we do a point by point
        % multiply ".*"  This multiplies modulated(1) = msg(1) * carrier(1) and
        % modulated(2) = msg(2) * carrier(2) ... modulated(n) = msg(n) * carrier(n).
        % The "*" operator does dot products and matrix multiplies, and in this
        % case, we want the point by point multiply instead.
        %
        % Regarding the normal * operator, you'll end up having endless
        % headaches with it as it strictly adheres to the rules of linear
        % algebra.  So, for example, strictly speaking, if we were to try to
        % dot product (*) the following vectors, it would fail since they're
        % both column vectors.  For dot product to work, one would have to be a
        % column vector, and one a row vector... and they'd also have to be the
        % same length.  You can also use the * operator on matrices, but again,
        % you must strictly adhere to linear algebra rules.  For example, a 3x2
        % matrix may be multiplied by a 2x3 matrix only.  For example...
        %
        % >> a = ones(2,3)
        % a =
        %      1     1     1
        %      1     1     1
        % >> b = ones(3,2)
        % b =
        %      1     1
        %      1     1
        %      1     1
        % >> a*b
        % ans =
        %      3     3
        %      3     3
        %
        modulated(k, :) = msg_upsampled .* carrier;
    end

Plot the results in a pretty little display... with titles!

    if doplot == 1
        % Plot the results
        figure;                     % Create a new plot figure
        for k = 1:m
            subplot( 2,1,1 );           % Create a subplot frame inside the figure with
                                        % 2 horizontal plots
            plot( modulated(k,:) );     % plot the modulated data
            % Set the axes limits for the y axis... cause I HATE how MATLAB does
            % this by default.
            ylim( [(min(modulated(k,:)) - 0.5) (max(modulated(k,:) + 0.5))] );
            str = sprintf( 'ASK Modulated Message : %d of %d', k, m );
            title( str );               % Give it a title.
            subplot(2,1,2);             % Move to the next frame in the subplot
            msg(k,:) = msg(k,:) - 1;
            plot( msg(k,:) );           % Plot our msg, remembering to subtract 1 to make
                                        % it 0->1 bits instead of 1->2

            % Set the ylimit so you can see the top of the msg bits... otherwise
            % they're unviewable.
            ylim( [(min(msg(k,:)) - 0.5) (max(msg(k,:)) + 0.5)] );
            str = sprintf( 'Original Message Bits : Message %d of %d', k, m );
            title( str ); % Give it a title.

            if k ~= m
                fprintf( 'Press space bar or enter to move on to the next plot\n' );
                pause;
            end
        end
    end
end

Contact us