## Copyright (C) 2009, 2010 Thomas Weidenfeller
## 
## This file is part of gds2000tools/gds-octave.
## 
## gds2000tools/gds-octave is free software: you can redistribute it
## and/or modify it under the terms of the GNU General Public License
## version 3 as published by the Free Software Foundation.
## 
## gds2000tools/gds-octave is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with gds2000tools/gds-octave.  If not,
## see <http://www.gnu.org/licenses/>.
##

## usage: [GDSSTRUCT_FM] = gds_fm(GDSSTRUCT)
## usage: [GDSSTRUCT_FM] = gds_fm(GDSSTRUCT, FFILT)
## usage: gds_fm(GDSSTRUCT)
## usage: gds_fm(GDSSTRUCT, FFILT)
##
## Simple FM demodulator.
##
## Create a waveform GDSSTRUCT_FM, which contains the frequency
## demodulation of the signal in GDSSTRUCT.
##
## NOTE: The function does not use octave's fmdemod(), because fmdemod()
## requires knowledge of the carrier frequency in advance. However, this
## simple algorithm creates limited results.
##
## Since the demodulator doesn't extract the unknown carrier frequency
## before attempting demodulation, we get a DC offset and a good chunk
## of residual carrier and phase wrapping.
##
## DC offset is removed by subtracting the mean.
##
## Residual carrier is partly removed with a fixed low-pass filter with a
## corner frequency of FFILT. If FFILT is not provided a corner frequency of
## 44800 Hz is used.
##
## Example:
##
## gs = gds_csvread("DS0002.CSV");
## fm = gds_fm(gs);
## subplot (2,1,1);
## gds_plot(gs);
## subplot (2,1,2);
## gds_plot(fm);
##
## See also: gds_plot(), gds_am()
##

## Author: Thomas Weidenfeller
## Created: 2010-12-28
## Version: $Id: gds_fm.m,v 1.4 2010/12/31 02:28:33 tw Exp $
## Keywords: Oscilloscope, GDS-2000, gds2000tools, FM, demodulator

function [gsfm] = gds_fm(gs, f_filt)
	if(nargin < 2 || !isstruct(gs))
		f_filt = 44800;
		if(nargin < 1)
			print_usage();
		endif
	endif

	## Primitive demodulator. FM -> AM -> demod
	s = abs(hilbert(abs(diff(gs.Waveform_Data))));

	##
	## Determine sampling period
	##
	dt = __gds_sampling_period(gs);

	L = __gds_memory_length(gs);

	## Filter residual carrier
	Wc = 2 * f_filt * dt;
	if(Wc > 1)
		## Too low sampling frequency. 
		## Just guess something
		Wc = 0.5;
		f_filt = Wc / 2 / dt;
	endif
	[b, a]= butter(5, Wc);
	s = filter(b, a, s);

	## Remove DC component
	s = s .- mean(s);
	
	## NOTE: Because of the diff() operator in the demodulator we
	## have one sample less
	gs.Waveform_Data = s;
	gs.Memory_Length = L - 1;
	gs.Trigger_Level = 0;
	gs.Source = [gs.Source " - FM Demod. (" num2str(f_filt) " Hz LP)" ];
	## TODO: Need to correctly scale amplitude
	gs.Vertical_Units = "Amplitude";

	if(nargout < 1)
		gds_plot(gs);
	else
		gsfm = gs;
	endif

endfunction
