193 lines
6.1 KiB
Matlab
193 lines
6.1 KiB
Matlab
|
function y = fskmod(x,M,freq_sep,nSamp,varargin)
|
||
|
%FSKMOD Frequency shift keying modulation
|
||
|
% Y = FSKMOD(X,M,FREQ_SEP,NSAMP) outputs the complex envelope of the
|
||
|
% modulation of the message signal X using frequency shift keying modulation. M
|
||
|
% is the alphabet size and must be an integer power of two. The message
|
||
|
% signal must consist of integers between 0 and M-1. FREQ_SEP is the desired
|
||
|
% separation between successive frequencies, in Hz. NSAMP denotes the number
|
||
|
% of samples per symbol and must be an integer greater than 1. For two
|
||
|
% dimensional signals, the function treats each column as one channel.
|
||
|
%
|
||
|
% Y = FSKMOD(X,M,FREQ_SEP,NSAMP,FS) specifies the sampling frequency (Hz).
|
||
|
% The default sampling frequency is 1.
|
||
|
%
|
||
|
% Y = FSKMOD(X,M,FREQ_SEP,NSAMP,FS,PHASE_CONT) specifies the phase continuity
|
||
|
% across FSK symbols. PHASE_CONT can be either 'cont' for continuous phase,
|
||
|
% or 'discont' for discontinuous phase. The default is 'cont'.
|
||
|
%
|
||
|
% Y = FSKMOD(X,M,FREQ_SEP,NSAMP,Fs,PHASE_CONT,SYMBOL_ORDER) specifies how the
|
||
|
% function assigns binary words to corresponding integers. If SYMBOL_ORDER is
|
||
|
% set to 'bin' (default), then the function uses a natural binary-coded
|
||
|
% ordering. If SYMBOL_ORDER is set to 'gray', then the function uses a
|
||
|
% Gray-coded ordering.
|
||
|
%
|
||
|
% See also FSKDEMOD, PSKMOD, QAMMOD, PAMMOD, OQPSKMOD.
|
||
|
|
||
|
% Copyright 1996-2012 The MathWorks, Inc.
|
||
|
|
||
|
|
||
|
% Error checks -----------------------------------------------------------------
|
||
|
if (nargin < 4)
|
||
|
error(message('comm:fskmod:numarg1'));
|
||
|
end
|
||
|
|
||
|
if (nargin > 7)
|
||
|
error(message('comm:fskmod:numarg2'));
|
||
|
end
|
||
|
|
||
|
% Check X
|
||
|
if (~isreal(x) || any(any(ceil(x) ~= x)) || ~isnumeric(x))
|
||
|
error(message('comm:fskmod:xreal1'));
|
||
|
end
|
||
|
|
||
|
% Check that M is a positive integer
|
||
|
if (~isreal(M) || ~isscalar(M) || M<2 || (ceil(M)~=M) || ~isnumeric(M))
|
||
|
error(message('comm:fskmod:Mreal'));
|
||
|
end
|
||
|
|
||
|
% Check that M is of the form 2^K
|
||
|
if(~isnumeric(M) || ceil(log2(M)) ~= log2(M))
|
||
|
error(message('comm:fskmod:Mpow2'));
|
||
|
end
|
||
|
|
||
|
%Check that all X are integers within [0,M-1]
|
||
|
if ((min(min(x)) < 0) || (max(max(x)) > (M-1)))
|
||
|
error(message('comm:fskmod:xreal2'));
|
||
|
end
|
||
|
|
||
|
% Check that the FREQ_SEP is greater than 0
|
||
|
if( ~isnumeric(freq_sep) || ~isscalar(freq_sep) || freq_sep<=0 )
|
||
|
error(message('comm:fskmod:freqSep'));
|
||
|
end
|
||
|
|
||
|
% Check that NSAMP is an integer greater than 1
|
||
|
if((~isnumeric(nSamp) || (ceil(nSamp) ~= nSamp)) || (nSamp <= 1))
|
||
|
error(message('comm:fskmod:nSampPos'));
|
||
|
end
|
||
|
|
||
|
% Check Fs
|
||
|
if (nargin >= 5)
|
||
|
Fs = varargin{1};
|
||
|
if (isempty(Fs))
|
||
|
Fs = 1;
|
||
|
elseif (~isreal(Fs) || ~isscalar(Fs) || ~isnumeric(Fs) || Fs<=0)
|
||
|
error(message('comm:fskmod:FsReal'));
|
||
|
end
|
||
|
else
|
||
|
Fs = 1;
|
||
|
end
|
||
|
samptime = 1/Fs;
|
||
|
|
||
|
% Check that the maximum transmitted frequency does not exceed Fs/2
|
||
|
maxFreq = ((M-1)/2) * freq_sep;
|
||
|
if (maxFreq > Fs/2)
|
||
|
error(message('comm:fskmod:maxFreq'));
|
||
|
end
|
||
|
|
||
|
% Check if the phase is continuous or discontinuous
|
||
|
if (nargin >= 6)
|
||
|
phase_type = varargin{2};
|
||
|
%check the phase_type string
|
||
|
if ~( strcmpi(phase_type,'cont') || strcmpi(phase_type,'discont') )
|
||
|
error(message('comm:fskmod:phaseCont'));
|
||
|
end
|
||
|
|
||
|
else
|
||
|
phase_type = 'cont';
|
||
|
end
|
||
|
|
||
|
if (strcmpi(phase_type, 'cont'))
|
||
|
phase_cont = 1;
|
||
|
else
|
||
|
phase_cont = 0;
|
||
|
end
|
||
|
|
||
|
% Check SYMBOL_ORDER
|
||
|
if(nargin >= 4 && nargin <= 6 )
|
||
|
Symbol_Ordering = 'bin'; % default
|
||
|
else
|
||
|
Symbol_Ordering = varargin{3};
|
||
|
if (~ischar(Symbol_Ordering)) || (~strcmpi(Symbol_Ordering,'GRAY')) && (~strcmpi(Symbol_Ordering,'BIN'))
|
||
|
error(message('comm:fskmod:SymbolOrder'));
|
||
|
end
|
||
|
end
|
||
|
|
||
|
% End of error checks ----------------------------------------------------------
|
||
|
|
||
|
|
||
|
% Assure that X, if one dimensional, has the correct orientation
|
||
|
wid = size(x,1);
|
||
|
if (wid == 1)
|
||
|
x = x(:);
|
||
|
end
|
||
|
|
||
|
% Gray encode if necessary
|
||
|
if (strcmpi(Symbol_Ordering,'GRAY'))
|
||
|
[~,gray_map] = bin2gray(x,'fsk',M); % Gray encode
|
||
|
[~,index]=ismember(x,gray_map);
|
||
|
x=index-1;
|
||
|
end
|
||
|
|
||
|
% Obtain the total number of channels
|
||
|
[nRows, nChan] = size(x);
|
||
|
|
||
|
% Initialize the phase increments and the oscillator phase for modulator with
|
||
|
% discontinuous phase.
|
||
|
phaseIncr = (0:nSamp-1)' * (-(M-1):2:(M-1)) * 2*pi * freq_sep/2 * samptime;
|
||
|
% phIncrSym is the incremental phase over one symbol, across all M tones.
|
||
|
phIncrSym = phaseIncr(end,:);
|
||
|
% phIncrSamp is the incremental phase over one sample, across all M tones.
|
||
|
phIncrSamp = phaseIncr(2,:); % recall that phaseIncr(1,:) = 0
|
||
|
OscPhase = zeros(nChan, M);
|
||
|
|
||
|
% phase = nSamp*# of symbols x # of channels
|
||
|
Phase = zeros(nSamp*nRows, nChan);
|
||
|
|
||
|
% Special case for discontinuous-phase FSK: can use a table look-up for speed
|
||
|
if ( (~phase_cont) && ...
|
||
|
( floor(nSamp*freq_sep/2 * samptime) == nSamp*freq_sep/2 * samptime ) )
|
||
|
exp_phaseIncr = exp(1i*phaseIncr);
|
||
|
y = reshape(exp_phaseIncr(:,x+1),nRows*nSamp,nChan);
|
||
|
else
|
||
|
for iChan = 1:nChan
|
||
|
prevPhase = 0;
|
||
|
for iSym = 1:nRows
|
||
|
% Get the initial phase for the current symbol
|
||
|
if (phase_cont)
|
||
|
ph1 = prevPhase;
|
||
|
else
|
||
|
ph1 = OscPhase(iChan, x(iSym,iChan)+1);
|
||
|
end
|
||
|
|
||
|
% Compute the phase of the current symbol by summing the initial phase
|
||
|
% with the per-symbol phase trajectory associated with the given M-ary
|
||
|
% data element.
|
||
|
Phase(nSamp*(iSym-1)+1:nSamp*iSym,iChan) = ...
|
||
|
ph1*ones(nSamp,1) + phaseIncr(:,x(iSym,iChan)+1);
|
||
|
|
||
|
% Update the oscillator for a modulator with discontinuous phase.
|
||
|
% Calculate the phase modulo 2*pi so that the phase doesn't grow too
|
||
|
% large.
|
||
|
if (~phase_cont)
|
||
|
OscPhase(iChan,:) = ...
|
||
|
rem(OscPhase(iChan,:) + phIncrSym + phIncrSamp, 2*pi);
|
||
|
end
|
||
|
|
||
|
% If in continuous mode, the starting phase for the next symbol is the
|
||
|
% ending phase of the current symbol plus the phase increment over one
|
||
|
% sample.
|
||
|
prevPhase = Phase(nSamp*iSym,iChan) + phIncrSamp(x(iSym,iChan)+1);
|
||
|
end
|
||
|
end
|
||
|
y = exp(1i*Phase);
|
||
|
end
|
||
|
|
||
|
% Restore the output signal to the original orientation
|
||
|
if(wid == 1)
|
||
|
y = y.';
|
||
|
end
|
||
|
|
||
|
% EOF --- fskmod.m
|
||
|
|
||
|
|