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