## Copyright (C) 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: gds_mainfreq(GDSSTRUCT)
## usage: gds_mainfreq(GDSSTRUCT, @FUNC)
## usage: [GDSSTRUCTOUT] = gds_mainfreq(GDSSTRUCT)
## usage: [GDSSTRUCTOUT] = gds_mainfreq(GDSSTRUCT, @FUNC)
## usage: [GDSSTRUCTOUT, FM] = gds_mainfreq(GDSSTRUCT)
## usage: [GDSSTRUCTOUT, FM] = gds_mainfreq(GDSSTRUCT, @FUNC)
##
## Calculate the main frequency component of the sampled signal in
## GDSSTRUCT, and construct a new GDS data structure with waveform data.
## The waveform data in that structure represents a signal with that
## main frequency only.
##
## GDSSTRUCT is a GDS data structure, for example, loaded with gds_csvread()
## from an oscilloscope .csv waveform sampling data file.
##
## FUNC is a handler to a function to be used for windowing the sampled data
## before calculating the discrete Fourier transform of it. This mitigates
## errors introduced due to the sampling interval usually not being aligned
## with the period of the signal.
##
## A provided FUNC function must accept one argument, the width of the
## window in sampling points.
##
## If FUNC is not provided then a Hanning window is used. See hanning().
##
## GDSSTRUCTOUT is a GDS data structure, containing the result.
##
## FM is the main frequency.
##
## If no return value is requested then the data is plotted instead.
##
## Example:
##
## > function [r] = boxwin(n)   # create a boxwindow function
## >> r = ones(n, 1);           # As opposite to hanning(), the ones() function
## >> endfunction               # can't be used directly as gds_mainfreq() arg.
## >
## > gs = gds_csvread("DS0018.CSV");         # read the data
## > gsout = gds_mainfreq(gs, @boxwin);      # calculate main frequency
## > gds_plot(gs, gsout);                    # plot original and result
##
## See also: barlett, blackman, chebwin, fft, gds_csvread, gds_plot,
## gds_spectrum, hamming, hanning, kaiser, ones
##

## Author: Thomas Weidenfeller
## Created: 2010-07-10
## Version: $Id: gds_mainfreq.m,v 1.5 2010/12/31 13:05:40 tw Exp $
## Keywords: Oscilloscope, GDS-2000, gds2000tools, fft

function [gsout, fmout] = gds_mainfreq (gs, func)
	if(nargin < 1 || nargin > 2 || !isstruct(gs))
		print_usage();
	elseif(nargin < 2)
		func = @hanning;	# TODO: Change to box?
	endif

	##
	## Determine sampling period
	##
	if(rows(gs.Sampling_Period) == 1)
		dt = gs.Sampling_Period;
	elseif(rows(gs.Horizontal_Scale) == 1)
		dt = gds_wd2val(gs.Horizontal_Scale, 1);
	else
		error("Neither Sampling_Period or Horizontal_Scale defined");
	endif

	##
	## Check if we have the data we should have
	##
	L = __gds_memory_length(gs);
	L_halfp1 = L / 2 + 1;

	##
	## Get AC component only, apply window, do fft.
	## (no scaling to Vertical Scale, no zero padding,
	## zero-frequency shifting, spectrum calculation).
	##
	dc = mean(gs.Waveform_Data);
	Y = fft((gs.Waveform_Data - dc) .* func(L));
	Yabs = abs(Y(1:L_halfp1));	# Get magnitude
	Yabs(1) = Yabs(1) / 2;		# DC component, should be zero
	Yabs(L_halfp1) = Yabs(L_halfp1) / 2;

	##
	## Get amplitude, frequency and phase of largest frequency component.
	##
	[maxYabs, nMax] = max(Yabs);
	a = maxYabs * 2 / L;
	f = (nMax - 1) / L;
	fm = f / dt;
	p = angle(Y(nMax));

	##
	## Construct result
	##
	gs.Waveform_Data = (a * cos(2 * pi * [0:L - 1] * f + p))';

	if(strcmp(gs.Horizontal_Units, "s"))
		unit = "Hz";
	else
		unit = [ "1 / " gs.Horizontal_Units ];
	endif
	gs.Source = [ gs.Source " - Main Freq. " num2str(fm) " " unit "; " func2str(func) " window" ];

	if(nargout > 0)
		gsout = gs;
		if(nargout > 1)
			fmout = fm;
		endif
	else
		gds_plot(gs);
	endif
endfunction

%!demo
%! ##gs = gds_csvread("DS0008.CSV"); ## read waveform from file
%! gs = __gds_demo_gs();      ## for now get a demo gds waveform data structure
%! gsout = gds_mainfreq(gs);  ## calculate main frequency
%! gds_plot(gs, gsout);       ## plot original and result
