ble/physicalLayer/fskdemod.m

180 lines
5.4 KiB
Matlab

function z = fskdemod(y,M,freq_sep,nSamp,varargin)
%FSKDEMOD Frequency shift keying demodulation
% Z = FSKDEMOD(Y,M,FREQ_SEP,NSAMP) noncoherently demodulates the complex
% envelope Y of a signal using the frequency shift keying method. M is the
% alphabet size and must be an integer power of 2. FREQ_SEP is the frequency
% separation, and must be positive. NSAMP is the required samples per symbol
% and must be an integer greater than 1. For two dimensional signals, the
% function treats each column of data as one channel.
%
% Z = FSKDEMOD(Y,M,FREQ_SEP,NSAMP,Fs) specifies the sampling frequency (Hz).
% The default sampling frequency is 1.
%
% Z = FSKDEMOD(Y,M,FREQ_SEP,NSAMP,Fs,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 FSKMOD, PSKDEMOD, QAMDEMOD, PAMDEMOD, OQPSKDEMOD.
% Copyright 1996-2012 The MathWorks, Inc.
% Error checks -----------------------------------------------------------------
if (nargin < 4)
error(message('comm:fskdemod:numarg1'));
end
if (nargin > 6)
error(message('comm:fskdemod:numarg2'));
end
% Check that M is a positive integer
if (~isreal(M) || ~isscalar(M) || M<2 || (ceil(M)~=M) || ~isnumeric(M))
error(message('comm:fskdemod:Mreal'));
end
% Check that M is of the form 2^K
if(~isnumeric(M) || ceil(log2(M)) ~= log2(M))
error(message('comm:fskdemod:Mpow2'));
end
% Check that the FREQ_SEP is greater than 0
if( ~isnumeric(freq_sep) || ~isscalar(freq_sep) || freq_sep<=0 )
error(message('comm:fskdemod:freqSep'));
end
% Check that NSAMP is an integer greater than 1
if((~isnumeric(nSamp) || (ceil(nSamp) ~= nSamp)) || (nSamp <= 1))
error(message('comm:fskdemod: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:fskdemod:FsReal'));
end
else
Fs = 1;
end
% Check that the maximum transmitted frequency does not exceed Fs/2
maxFreq = ((M-1)/2) * freq_sep;
if (maxFreq > Fs/2)
error(message('comm:fskdemod:maxFreq'));
end
% Check SYMBOL_ORDER
if(nargin==4 || nargin==5 )
Symbol_Ordering = 'bin'; %default
else
Symbol_Ordering = varargin{2};
if (~ischar(Symbol_Ordering)) || (~strcmpi(Symbol_Ordering,'GRAY')) && (~strcmpi(Symbol_Ordering,'BIN'))
error(message('comm:fskdemod:SymbolOrder'));
end
end
% End of error checks ----------------------------------------------------------
% Assure that Y, if one dimensional, has the correct orientation
wid = size(y,1);
if(wid ==1)
y = y(:);
end
[nRows, nChan] = size(y);
% Preallocate memory
z = zeros(nRows/nSamp, nChan);
% Define the frequencies used for the demodulator.
freqs = (-(M-1)/2 : (M-1)/2) * freq_sep;
% Use the frequencies to generate M complex tones which will be multiplied with
% each received FSK symbol. The tones run down the columns of the "tones"
% matrix.
t = (0 : 1/Fs : nSamp/Fs - 1/Fs)';
phase = 2*pi*t*freqs;
tones = exp(-1i*phase);
% For each FSK channel, multiply the complex received signal with the M complex
% tones. Then perform an integrate and dump over each symbol period, find the
% magnitude, and choose the transmitted symbol corresponding to the maximum
% magnitude.
for iChan = 1 : nChan % loop for each FSK channel
for iSym = 1 : nRows/nSamp
% Load the samples for the current symbol
yTemp = y( (iSym-1)*nSamp+1 : iSym*nSamp, iChan);
% Replicate the received FSK signal to multiply with the M tones
yTemp = yTemp(:, ones(M,1));
% Multiply against the M tones
yTemp = yTemp .* tones;
% Perform the integrate and dump, then get the magnitude. Use a
% subfunction for the integrate and dump, to omit the error checking.
yMag = abs(intanddump(yTemp, nSamp));
% Choose the maximum and assign an integer value to it. Subtract 1 from the
% output of MAX because the integer outputs are zero-based, not one-based.
[~, maxIdx] = max(yMag, [], 2);
z(iSym,iChan) = maxIdx - 1;
end
end
% Restore the output signal to the original orientation
if(wid == 1)
z = z';
end
% Gray decode if necessary
if (strcmpi(Symbol_Ordering,'GRAY'))
[~,gray_map] = gray2bin(z,'fsk',M); % Gray decode
% --- Assure that X, if one dimensional, has the correct orientation --- %
if(size(z,1) == 1)
temp = zeros(size(z));
temp(:) = gray_map(z+1);
z(:) = temp(:);
else
z = gray_map(z+1);
end
end
% EOF -- fskdemod.m
% ------------------------------------------------------------------------------
function y = intanddump(x, Nsamp)
%INTANDDUMP Integrate and dump.
% Y = INTANDDUMP(X, NSAMP) integrates the signal X for 1 symbol period, then
% outputs one value into Y. NSAMP is the number of samples per symbol.
% For two-dimensional signals, the function treats each column as 1
% channel.
%
% --- Assure that X, if one dimensional, has the correct orientation --- %
wid = size(x,1);
if(wid ==1)
x = x(:);
end
[xRow, xCol] = size(x);
x = mean(reshape(x, Nsamp, xRow*xCol/Nsamp), 1);
y = reshape(x, xRow/Nsamp, xCol);
% --- restore the output signal to the original orientation --- %
if(wid == 1)
y = y.';
end
% EOF --- intanddump.m