----------------------------------------------
-- MSS copyright 2014
-- Filename: FAST_FREQUENCY_DETECTION.VHD
-- Authors: 
--		Alain Zarembowitch / MSS
-- Inheritance: n/a
-- Edit date: 3/5/16
-- Revision: 3
--
-- Description: 
-- simple low-pass filter (I&D), followed by complex square, followed by complex 2048-ppt FFT.
-- Maximum magnitude FFT output bin corresponds to 2*center frequency with the proper sign.
-- The low-pass filter bandwidth is controlled by NID = number of samples in the integrate and dump.
-- NID should be selected so that fs/2*NID > maximum center frequency to be detected
-- Trigonometry identities used:
-- sin(2alpha) = 2sin(alpha).cos(alpha)
-- cos(2alpha) = cos^2(alpha) - sin^2(alpha)
-- complex squaring of (a + ib) = (a^2-b^2) + i2ab
-- The complex squaring removes the data modulation, leaving only a pure carrier at 2*center frequency.
--
-- Rev 0b 9/30/14 AZ Vivado tools misunderstood the statement (something = 'X') as true
-- had to work around it.
--
-- Rev 1 11/5/14 AZ detect the two largest local maxima. Useful in assessing the modulated signal presence.
-- Added average FFT magnitude. Also useful in assessing signal presence.
--
-- Rev 2 2/11/15 Added ComScope monitoring
--
-- Rev 3 3/5/16 Made NID an input, for a more flexible selection of resolution/range
----------------------------------------------
library IEEE;
use IEEE.std_logic_1164.all;    
use IEEE.numeric_std.ALL;

entity FAST_FREQUENCY_DETECTION is
	generic (
		NID_MAX_LOG2: integer range 0 to 31:= 8;	
			-- extend accumulator precision = log2(maximum NID). must be consistent with NID
		SIMULATION: std_logic := '0'
			-- 1 during simulation. 
	);
    port (
	 	--// CLOCKS, RESET
		CLK: in std_logic;	
		SYNC_RESET: in std_logic;
		
		--// INPUTS
		DATA_I_IN: in std_logic_vector(17 downto 0);     
		DATA_Q_IN: in std_logic_vector(17 downto 0);   
			-- complex baseband input signed 
			-- read at the rising edge of CLK when SAMPLE_CLK_IN = '1'
		SAMPLE_CLK_IN: in std_logic;
			-- maximum: 1 samples/3 clk (because multiplier is time-shared)

		--// CONTROLS
		NID: in integer range 1 to 2**NID_MAX_LOG2; 
			-- Number of samples to be integrated (I&D = simple low-pass filter) 
			-- A coarse way to control the LPF bandwidth
			-- Trick: select a power of 2, as it makes it easier to scale back the FFT frequency units afterwards.
		NID_LOG2: in integer range 0 to 31;	
			-- extend accumulator precision = log2(NID)
		ENABLE: in std_logic;
		  -- trigger to start analyzing the signal

		--// OUTPUTS
		FFTM: out std_logic_vector(13 downto 0);
		FFTM2: out std_logic_vector(13 downto 0); -- second highest peak (useful in assessing signal presence)
		-- Note: beware of false peaks (when peak is close to FFTF=0, since frequency wraps around)
		FFTM_AVRG: out std_logic_vector(13 downto 0);
		  -- average FFT magnitude. Useful in assessing signal presence (when FFTM peak >> FFTM_AVRG)
		FFTF: out std_logic_vector(10 downto 0);
		FFTP: out std_logic_vector(10 downto 0);
		FFT_READY: out std_logic;
			-- measured magnitude, frequency and phase during the sync word
			-- frequency is expressed in steps of (input sampling rate /NID*2*2048)
			-- phase is expressed as 360deg/2**11
			-- magnitude is measured in a narrow frequency bin at the center of the modulation
			-- read when FFT_READY = '1'

		--// MONITORING
		SATURATION: out std_logic;

		-- COMSCOPE test points
        -- CS1: FFT output magnitude
		CS1: out std_logic_vector(7 downto 0); 
        CS1_CLK: out std_logic;
		TP: out std_logic_vector(10 downto 1)
			-- bit 1: FFT overflow

		);
 end entity;
  
architecture Behavioral of FAST_FREQUENCY_DETECTION is
-----------------------------------------------------------------
-- COMPONENTS
-----------------------------------------------------------------
	COMPONENT POLAR3
	PORT(
		CLK : IN std_logic;
		X_IN : IN std_logic_vector(11 downto 0);
		Y_IN : IN std_logic_vector(11 downto 0);
		SAMPLE_CLK_IN : IN std_logic;          
		PHASE_OUT : OUT std_logic_vector(10 downto 0);
		MAGNITUDE_OUT : OUT std_logic_vector(13 downto 0);
		SAMPLE_CLK_OUT : OUT std_logic
		);
	END COMPONENT;

	COMPONENT FFT_CONTROL2
	PORT(
		CLK : IN  std_logic;
		SYNC_RESET: in std_logic;
		DATA_I_IN : IN  std_logic_vector(17 downto 0);
		DATA_Q_IN : IN  std_logic_vector(17 downto 0);
		FFT_INDEX_IN : IN  std_logic_vector(10 downto 0);
		SAMPLE_CLK_IN : IN  std_logic;
		FWD_INVN : IN  std_logic;
		FFT_START : IN  std_logic;
		IO_ENABLED : OUT  std_logic;
		FFT_SCALE : IN  std_logic_vector(11 downto 0);
		FFT_BYPASS : IN  std_logic;
		DATA_I_OUT : OUT  std_logic_vector(17 downto 0);
		DATA_Q_OUT : OUT  std_logic_vector(17 downto 0);
		FFT_INDEX_OUT : IN  std_logic_vector(10 downto 0);
		SAMPLE_CLK_OUT : OUT  std_logic;
		SAMPLE_CLK_OUT_REQ : IN  std_logic;
		OVERFLOW : OUT  std_logic_vector(5 downto 0)
	  );
	END COMPONENT;

	component SIM2OUTFILE is
		 Generic (
			FILENAME: string
		 );
		 Port ( 
			--// CLK, RESET
			CLK: in std_logic;
				-- Reference clock
			DATA1: in std_logic_vector(11 downto 0);
			DATA2: in std_logic_vector(11 downto 0);
			DATA3: in std_logic_vector(11 downto 0);
			SAMPLE_CLK_IN: in std_logic
				-- DATA_IN is read at the rising edge of CLK when SAMPLE_CLK_IN = '1'

	);
	END COMPONENT;

-----------------------------------------------------------------
-- SIGNALS
-----------------------------------------------------------------
-- Suffix _D indicates a one CLK delayed version of the net with the same name
-- Suffix _x indicates an extended precision version of the net with the same name
-- Suffix _R indicates a reduced precision version of the net with the same name
-- Suffix _N indicates an inverted version of the net with the same name
-- Suffix _local indicates an exact version of the (output signal) net with the same name

--// INTEGRATE AND DUMP -------------------------------------
signal ID_CNTR: unsigned((NID_MAX_LOG2-1) downto 0) := (others => '0');
signal DATA_I_ACC: signed((NID_MAX_LOG2 + 18) downto 0) := (others => '0');
signal DATA_Q_ACC: signed((NID_MAX_LOG2 + 18) downto 0) := (others => '0');
signal DATA_I_ACC_SHIFT: signed((NID_MAX_LOG2 + 18) downto 0) := (others => '0');
signal DATA_Q_ACC_SHIFT: signed((NID_MAX_LOG2 + 18) downto 0) := (others => '0');
signal ACC_SHIFT_CNTR: unsigned(4 downto 0) := (others => '0');	-- because max(NID_MAX_LOG2) = 31
signal ACC_SHIFT_FLAG: std_logic := '0'; 
signal SAMPLE1_CLK: std_logic := '0'; 
signal DATA1_I: signed(17 downto 0) := (others => '0');
signal DATA1_Q: signed(17 downto 0) := (others => '0');

--// COMPLEX SQUARE -----------------------------------------
signal DATA1_I_D: signed(17 downto 0) := (others => '0');
signal DATA1_Q_D: signed(17 downto 0) := (others => '0');
signal SAMPLE1_CLK_D: std_logic := '0';
signal SAMPLE1_CLK_D2: std_logic := '0';
signal SAMPLE1_CLK_D3: std_logic := '0';
signal SAMPLE1_CLK_D4: std_logic := '0';
signal SAMPLE1_CLK_D5: std_logic := '0'; 
signal AMULT: signed(17 downto 0) := (others => '0');
signal BMULT: signed(17 downto 0) := (others => '0');
signal ABMULT: signed(35 downto 0) := (others => '0');
signal ABMULT_D: signed(35 downto 0) := (others => '0');
signal SAMPLE2_CLK: std_logic := '0'; 
signal DATA2_I: signed(17 downto 0) := (others => '0');
signal DATA2A_I: signed(17 downto 0) := (others => '0');
signal DATA2B_I: signed(17 downto 0) := (others => '0');
signal DATA2_Q: signed(17 downto 0) := (others => '0');

----// FFT -----------------------------------------
signal SAMPLE4_CLK: std_logic := '0'; 
signal DATA4_I: signed(17 downto 0) := (others => '0');
signal DATA4_Q: signed(17 downto 0) := (others => '0');
signal FFT_STATE: integer range 0 to 5 := 0;
signal FFT_IO_ENABLED: std_logic := '0';
signal FFT_START: std_logic := '0';
signal FFT_INDEX_IN : unsigned(10 downto 0) := (others => '0');
signal FFT_INDEX_OUT : unsigned(10 downto 0) := (others => '0');
signal FFT_SCALE: std_logic_vector(11 downto 0) := (others => '0');
signal DATA5_I: std_logic_vector(17 downto 0) := (others => '0');
signal DATA5_Q: std_logic_vector(17 downto 0) := (others => '0');
signal SAMPLE5_CLK: std_logic := '0';
signal SAMPLE5_CLK_REQ: std_logic := '0';
signal FFT_OVERFLOW: std_logic_vector(5 downto 0) := (others => '0');

--// CENTER FREQUENCY MEASUREMENT -----------------------------------------
signal SAMPLEMP5_CLK: std_logic := '0';
signal SAMPLEMP5_CLK_D: std_logic := '0';
signal DATA5P_slv: std_logic_vector(10 downto 0) := (others => '0');
signal DATA5M_slv: std_logic_vector(13 downto 0) := (others => '0');
signal DATA5P: unsigned(10 downto 0) := (others => '0');
signal DATA5M: unsigned(13 downto 0) := (others => '0');
signal FFTM_LOCAL_MAX: unsigned(13 downto 0) := (others => '0');
signal FFTP_MAX: unsigned(10 downto 0) := (others => '0');
signal FFTF_LOCAL_MAX: unsigned(10 downto 0) := (others => '0');
signal FFTF_LOCAL_MAX1: unsigned(10 downto 0) := (others => '0');
signal FFTF_LOCAL_MAX2: unsigned(10 downto 0) := (others => '0');
signal FFT_INDEX: unsigned(10 downto 0) := (others => '0');
signal FFT_OUTPUT_ENABLE: std_logic := '0';

-- average, peak magnitude
signal FFTM_LOCAL_MAX1: unsigned(13 downto 0) := (others => '0');
signal FFTM_LOCAL_MAX2: unsigned(13 downto 0) := (others => '0');
signal FFTM_LOCAL_MAX_STATE: std_logic := '0';
signal FFTM_ACC: unsigned(24 downto 0) := (others => '0');

-----------------------------------------------------------------
-- IMPLEMENTATION
-----------------------------------------------------------------
begin 

--// INTEGRATE AND DUMP -------------------------------------
-- NID samples
ID_001:  process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			ID_CNTR <= (others => '1');	
		elsif(SAMPLE_CLK_IN = '1') then
			if(ID_CNTR = NID-1) then
				ID_CNTR <= (others => '0');	
			else
				ID_CNTR <= ID_CNTR + 1;
			end if;
		end if;
	end if;
end process;

ID_002: process(CLK) 
begin
	if rising_edge(CLK) then
		if(SAMPLE_CLK_IN = '1') and ((SIMULATION = '0') or (DATA_I_IN(17) /= 'X')) then	-- prevent propagation of undefined during simulation
			if(ID_CNTR = 0) then
				-- reset accumulated values
				DATA_I_ACC <=  resize(signed(DATA_I_IN),DATA_I_ACC'length);
				DATA_Q_ACC <=  resize(signed(DATA_Q_IN),DATA_Q_ACC'length);
			else
				-- accumulate 
				-- extend precision by NID_MAX_LOG2 bits to avoid any overflow.
				DATA_I_ACC <=  DATA_I_ACC + resize(signed(DATA_I_IN),DATA_I_ACC'length);
				DATA_Q_ACC <=  DATA_Q_ACC + resize(signed(DATA_Q_IN),DATA_Q_ACC'length);
			end if;
		end if;
	end if;
end process;

-- shift acc to a 18-bit value with similar order of magnitude as DATA_IN
ID_003: process(CLK) 
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			SAMPLE1_CLK <= '0';
		elsif(SAMPLE_CLK_IN = '1') and ((SIMULATION = '0') or (DATA_I_IN(17) /= 'X')) and (ID_CNTR = 0) then	-- prevent propagation of undefined during simulation
			-- dump integrated total
			DATA_I_ACC_SHIFT <= DATA_I_ACC;
			DATA_Q_ACC_SHIFT <= DATA_Q_ACC;
			ACC_SHIFT_CNTR <= to_unsigned(NID_LOG2, ACC_SHIFT_CNTR'length);
			ACC_SHIFT_FLAG <= '1';
			SAMPLE1_CLK <= '0';
		elsif(ACC_SHIFT_CNTR /= 0) then
			-- shift right NID_LOG2 bits
			ACC_SHIFT_CNTR <= ACC_SHIFT_CNTR - 1;
			DATA_I_ACC_SHIFT(DATA_I_ACC_SHIFT'left-1 downto 0) <= DATA_I_ACC_SHIFT(DATA_I_ACC_SHIFT'left downto 1);
			DATA_Q_ACC_SHIFT(DATA_I_ACC_SHIFT'left-1 downto 0) <= DATA_Q_ACC_SHIFT(DATA_I_ACC_SHIFT'left downto 1);
		else
			if(ACC_SHIFT_FLAG = '1') then
				ACC_SHIFT_FLAG <= '0';
				SAMPLE1_CLK <= '1';
				DATA1_I <= DATA_I_ACC_SHIFT(17 downto 0);
				DATA1_Q <= DATA_Q_ACC_SHIFT(17 downto 0);
			else
				SAMPLE1_CLK <= '0';
			end if;
		end if;
	end if;
end process;


--// COMPLEX SQUARE -----------------------------------------
RECLOCK_MULT_INPUT_001: process(CLK)
begin
	if rising_edge(CLK) then
		SAMPLE1_CLK_D <= SAMPLE1_CLK;
		SAMPLE1_CLK_D2 <= SAMPLE1_CLK_D;
		SAMPLE1_CLK_D3 <= SAMPLE1_CLK_D2;
		
		if(SAMPLE1_CLK = '1') then
			DATA1_I_D <= DATA1_I;
			DATA1_Q_D <= DATA1_Q;
		end if;
		-- time-share multiplier
		if(SAMPLE1_CLK_D = '1') then
			AMULT <= DATA1_I_D;
			BMULT <= DATA1_I_D;
		elsif(SAMPLE1_CLK_D2 = '1') then
			--AMULT <= DATA1_I_D;
			BMULT <= DATA1_Q_D;
		elsif(SAMPLE1_CLK_D3 = '1') then
			AMULT <= DATA1_Q_D;
			--BMULT <= DATA1_Q_D;
		end if;
	end if;
end process;

ABMULT <= AMULT * BMULT;

-- demux multipler output
RECLOCK_MULT_OUTPUT_001: process(CLK)
begin
	if rising_edge(CLK) then
		ABMULT_D(35 downto 17) <= ABMULT(35 downto 17);

		SAMPLE1_CLK_D4 <= SAMPLE1_CLK_D3;
		SAMPLE1_CLK_D5 <= SAMPLE1_CLK_D4;
		SAMPLE2_CLK <= SAMPLE1_CLK_D5;
		
		if(SAMPLE1_CLK_D3 = '1') then
			DATA2A_I <= ABMULT_D(35 downto 18);	-- i^2
		end if;
		if(SAMPLE1_CLK_D4 = '1') then
			DATA2_Q <= ABMULT_D(34 downto 17);	-- 2iq
		end if;
		if(SAMPLE1_CLK_D5 = '1') then
			DATA2B_I <= ABMULT_D(35 downto 18);	-- i^2 - q^2
		end if;
	end if;
end process;
DATA2_I <= DATA2A_I - DATA2B_I;
		
----// FFT -----------------------------------------
-- FFT state machine
FFT_STATE_GEN_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
			FFT_STATE <= 0;	-- back to idle
		elsif(FFT_STATE = 0) and (FFT_IO_ENABLED = '1') and (ENABLE = '1') then
			-- FFT engine is ready 
			FFT_STATE <= 1;
			FFT_INDEX_IN <= (others => '0');
		elsif(FFT_STATE = 1) and (SAMPLE2_CLK = '1')  then
			-- enter complex square
			if((not FFT_INDEX_IN) = 0) then
                -- this completes the FFT input (all 2048 input samples in)
                -- start the FFT
                FFT_START <= '1';
                FFT_STATE <= 3;
            else
			     FFT_INDEX_IN <= FFT_INDEX_IN + 1;
            end if;
-- no zero padding here			
--			if(FFT_INDEX_IN(8) = '1') then
--				-- Collected 256 FFT input samples. Can't wait for all 2048. Pad FFT input with zeros
--				FFT_STATE <= 2;
--			end if;
--		elsif(FFT_STATE = 2) and ((not FFT_INDEX_IN) = 0) then
--			-- this completes the FFT input (all 2048 input samples in)
--			-- start the FFT
--			FFT_START <= '1';
--			FFT_STATE <= 3;
--		elsif(FFT_STATE = 2)  then
--			FFT_INDEX_IN <= FFT_INDEX_IN + 1;
		elsif(FFT_STATE = 3)  then
			FFT_START <= '0';
			FFT_STATE <= 4;
		elsif(FFT_STATE = 4) and (FFT_IO_ENABLED = '1') then
			-- start reading FFT output
			FFT_INDEX_OUT <= (others => '0');
			SAMPLE5_CLK_REQ <= '1';
			FFT_STATE <= 5;
		elsif(FFT_STATE = 5) and ((not FFT_INDEX_OUT) = 0) then
			-- FFT output complete
			FFT_STATE <= 0;	-- back to idle
			SAMPLE5_CLK_REQ <= '0';
		elsif(FFT_STATE = 5) then
			FFT_INDEX_OUT <= FFT_INDEX_OUT + 1;
		end if;
	end if;
end process;

DATA4_I <= DATA2_I when (FFT_STATE = 1) else (others => '0') ;
DATA4_Q <= DATA2_Q when (FFT_STATE = 1) else (others => '0') ;
SAMPLE4_CLK <= SAMPLE2_CLK when (FFT_STATE = 1) else	
					'1' when (FFT_STATE = 2) else 	-- pad FFT input with zeroes
					'0';
FFT_SCALE <= "101010101010";  -- Heuristic

				
FFT_CONTROL2_001: FFT_CONTROL2 PORT MAP (
	 CLK => CLK,
	 SYNC_RESET => SYNC_RESET,
	 DATA_I_IN => std_logic_vector(DATA4_I),
	 DATA_Q_IN => std_logic_vector(DATA4_Q),
	 FFT_INDEX_IN => std_logic_vector(FFT_INDEX_IN),
	 SAMPLE_CLK_IN => SAMPLE4_CLK,
	 FWD_INVN => '0',
	 FFT_START => FFT_START,
	 IO_ENABLED => FFT_IO_ENABLED,
	 FFT_SCALE => FFT_SCALE,
	 FFT_BYPASS => '0',
	 DATA_I_OUT => DATA5_I,
	 DATA_Q_OUT => DATA5_Q,
	 FFT_INDEX_OUT => std_logic_vector(FFT_INDEX_OUT),
	 SAMPLE_CLK_OUT => SAMPLE5_CLK,
	 SAMPLE_CLK_OUT_REQ => SAMPLE5_CLK_REQ,
	 OVERFLOW => FFT_OVERFLOW
  );


--// CENTER FREQUENCY MEASUREMENT -----------------------------------------

-- Note: this lookup table is used exclusively for FFT output 
-- Latency: 5 CLK
POLAR3_002a: POLAR3 PORT MAP(
	CLK => CLK,
	X_IN => DATA5_I(17 downto 6),   
	Y_IN => DATA5_Q(17 downto 6),
	SAMPLE_CLK_IN => SAMPLE5_CLK,		
	PHASE_OUT => DATA5P_slv,			-- phase
	MAGNITUDE_OUT => DATA5M_slv,	-- sqrt(X_IN(13:0)^2 + Y_IN(13:0)^2)
	SAMPLE_CLK_OUT => SAMPLEMP5_CLK
);
DATA5M <= unsigned(DATA5M_slv);
DATA5P <= unsigned(DATA5P_slv);

-- block FFT output ENABLE goes low during FFT computation
-- enable FFT output after 1st SOF detection and continuous SOF lock until FFT is complete
--FFT_OUTPUT_VALID_GEN: process(CLK)
--begin
--	if rising_edge(CLK) then
--		if(SYNC_RESET = '1') then
--			FFT_OUTPUT_ENABLE <= '0';
--		elsif(ENABLE = '0') then
--			-- ENABLE went to zero. Ignore the output of any FFT started before hand.
--			FFT_OUTPUT_ENABLE <= '0';
--		elsif(SAMPLEMP5_CLK = '1') and (SAMPLEMP5_CLK_D = '0') then
--			-- first FFT input sample
			FFT_OUTPUT_ENABLE <= '1';
--		end if;
--	end if;
--end process;


-- find out maximum magnitude, associated frequency (index) and phase
FFT_MAX_001: process(CLK)
begin
	if rising_edge(CLK) then
		SAMPLEMP5_CLK_D <= SAMPLEMP5_CLK;
		
		if(SYNC_RESET = '1') then
			FFTM_LOCAL_MAX_STATE <= '0';
			FFTM_LOCAL_MAX <= (others => '0');
			FFTM_LOCAL_MAX1 <= (others => '0');
            FFTM_LOCAL_MAX2 <= (others => '0');
			FFTF_LOCAL_MAX1 <= (others => '0');
            FFTF_LOCAL_MAX2 <= (others => '0');
			FFT_INDEX <= (others => '0');
			FFTM <= (others => '0');
			FFTM2 <= (others => '0');
			FFTF <= (others => '0');
			FFTP <= (others => '0');
			FFT_READY <= '0';
		elsif(SAMPLEMP5_CLK = '0') then
			if(SAMPLEMP5_CLK_D = '1') and (FFT_OUTPUT_ENABLE = '1') then
				-- FFT output is complete. Send results to the output
				FFT_READY <= '1';
                 -- end => confirm local max
                 -- is this local max the largest or 2nd largest max?
                 if(FFTM_LOCAL_MAX > FFTM_LOCAL_MAX1) then
                     -- new largest max
                     FFTM <= std_logic_vector(FFTM_LOCAL_MAX);
                     FFTM2 <= std_logic_vector(FFTM_LOCAL_MAX1);
 				     FFTF <= std_logic_vector(FFTF_LOCAL_MAX);
                     FFTP <= std_logic_vector(FFTP_MAX);
                 elsif(FFTM_LOCAL_MAX > FFTM_LOCAL_MAX2) then
                     -- new second largest peak
                     FFTM <= std_logic_vector(FFTM_LOCAL_MAX1);
                     FFTM2 <= std_logic_vector(FFTM_LOCAL_MAX);
 				     FFTF <= std_logic_vector(FFTF_LOCAL_MAX1);
                     FFTP <= std_logic_vector(FFTP_MAX);
                 else
                     FFTM <= std_logic_vector(FFTM_LOCAL_MAX1);
                     FFTM2 <= std_logic_vector(FFTM_LOCAL_MAX2);
 				     FFTF <= std_logic_vector(FFTF_LOCAL_MAX1);
                     FFTP <= std_logic_vector(FFTP_MAX);
                end if;
			else
				FFT_READY <= '0';
				-- reset FFT max magnitude
			    FFTM_LOCAL_MAX_STATE <= '0';
				FFTM_LOCAL_MAX <= (others => '0');
			    FFTM_LOCAL_MAX1 <= (others => '0');
                FFTM_LOCAL_MAX2 <= (others => '0');
			    FFTF_LOCAL_MAX1 <= (others => '0');
                FFTF_LOCAL_MAX2 <= (others => '0');
				FFT_INDEX <= (others => '0');	
			end if;
		else
			-- processing FFT magnitude/phase from POLAR3
			FFT_INDEX <= FFT_INDEX + 1;
			if(DATA5M > FFTM_LOCAL_MAX) then 
				-- found new FFT magnitude local maximum (unconfirmed until DATA5M drops to below half of the local max)
				FFTM_LOCAL_MAX_STATE <= '1';  -- wait for local peak confirmation (when FFTM is a new low < FFTM_LOCAL_MAX/2)
				FFTM_LOCAL_MAX <= DATA5M;	-- magnitude
				FFTP_MAX <= DATA5P;	-- phase
				FFTF_LOCAL_MAX <= FFT_INDEX;	-- frequency index
			elsif(FFTM_LOCAL_MAX_STATE = '1') and (DATA5M < FFTM_LOCAL_MAX(13 downto 1)) then
			     -- local max confirmed
			     FFTM_LOCAL_MAX_STATE <= '0';
		         FFTM_LOCAL_MAX <= (others => '0'); -- reset local max search
			     -- is this local max the largest or 2nd largest max?
			     if(FFTM_LOCAL_MAX > FFTM_LOCAL_MAX1) then
			         -- new largest max
			         FFTM_LOCAL_MAX1 <= FFTM_LOCAL_MAX;
                     FFTM_LOCAL_MAX2 <= FFTM_LOCAL_MAX1;
			         FFTF_LOCAL_MAX1 <= FFTF_LOCAL_MAX;
                     FFTF_LOCAL_MAX2 <= FFTF_LOCAL_MAX1;
			     elsif(FFTM_LOCAL_MAX > FFTM_LOCAL_MAX2) then
			         -- second largest
			         FFTM_LOCAL_MAX2 <= FFTM_LOCAL_MAX;
			         FFTF_LOCAL_MAX2 <= FFTF_LOCAL_MAX;
			     end if;     
			end if;
		end if;
	end if;
end process;

-- average FFT magnitude. Useful in assessing signal presence (when FFTM peak >> FFTM_AVRG)
FFT_AVRG_001: process(CLK)
begin
	if rising_edge(CLK) then
		if(SYNC_RESET = '1') then
		    FFTM_ACC <= (others => '0');  -- clear accumulator
		elsif(SAMPLEMP5_CLK = '0') then
			if(SAMPLEMP5_CLK_D = '1') and (FFT_OUTPUT_ENABLE = '1') then
			    FFTM_AVRG <= std_logic_vector(FFTM_ACC(24 downto 11)); -- to output (divide accumulator by 2048 samples)
                FFTM_ACC <= (others => '0'); -- clear accumulator
 			end if;
		else
		  FFTM_ACC <= FFTM_ACC + resize(DATA5M,FFTM_ACC'length);
        end if;
    end if;
end process;

-----------------------------------------------------------------------------
------// TEST POINTS, MONITORING
------------------------------------------------------------------------------
SATURATION <= '1' when (unsigned(FFT_OVERFLOW) /= 0) else '0';
--
-- ComScope trace
CS1 <= DATA5M_slv(8 downto 1);
CS1_CLK <= SAMPLEMP5_CLK;

--// simulation. send to a tab-delimited text file for subsequent (Matlab) plot.
SIM2OUTFILE_X: if(SIMULATION = '1') generate

--	Inst_SIM2OUTFILE1: SIM2OUTFILE 
--	generic map(
--		FILENAME => "ffd1.txt"
--	)
--	PORT MAP(
--		CLK => CLK,
--		DATA1 => std_logic_vector(DATA1_I(17 downto 6)),		
--		DATA2 => std_logic_vector(DATA1_Q(17 downto 6)),	
--		DATA3 => x"000",
--		SAMPLE_CLK_IN => SAMPLE1_CLK
--	);


--	Inst_SIM2OUTFILE2: SIM2OUTFILE 
--	generic map(
--		FILENAME => "ffd2.txt"
--	)
--	PORT MAP(
--		CLK => CLK,
--		DATA1 => std_logic_vector(DATA2_I(17 downto 6)),		
--		DATA2 => std_logic_vector(DATA2_Q(17 downto 6)),	
--		DATA3 => x"000",
--		SAMPLE_CLK_IN => SAMPLE2_CLK
--	);

	Inst_SIM2OUTFILE5: SIM2OUTFILE 
	generic map(
		FILENAME => "ffd5.txt"
	)
	PORT MAP(
		CLK => CLK,
		DATA1 => DATA5M_slv(13 downto 2),
		DATA2 => std_logic_vector(FFTM_LOCAL_MAX(13 downto 2)),	
		DATA3 => std_logic_vector(FFTM_LOCAL_MAX1(13 downto 2)),
		SAMPLE_CLK_IN => SAMPLEMP5_CLK
	);
end generate;

end Behavioral;
