/* SigLib Frequency Modulation Example */

#include <stdio.h>
#include <siglib.h>
#include "GraphFunctions.h"

#define	SAMPLE_LENGTH		((SLArrayIndex_t)512)
#define	BAUD_RATE			((SLData_t)0.02)
#define	CARRIER_FREQ		((SLData_t)0.1)
#define	MOD_INDEX			((SLData_t)0.05)

#define IIR_FILTER_STAGES	3L		/* Number of 2nd-order filter stages */

#define	SINE_TABLE_SIZE		((SLArrayIndex_t)1024)	/* Look up table for fast sine calculation */


			/* IIR LPF, Fc = Fs * 0.1 */
				/* IIR filter coeffs, b(0), b(1), b(2), a(1), a(2) */
SLData_t pIIRFilterTaps[IIR_FILTER_STAGES * 5] = {
	 9.42380353047E-0002,  1.08526026540E-0001,  9.42380353047E-0002, -1.73648791886E+0000,  7.81845268784E-0001,
	 9.42380353047E-0002, -9.71701377691E-0002,  9.42380353047E-0002, -1.64442139918E+0000,  8.62782495425E-0001,
	 9.42380353047E-0002, -5.53439298689E-0002,  9.42380353047E-0002, -1.59154638820E+0000,  9.56063978767E-0001
	};

#define DEMOD_ENVELOPE_DECAY_FACTOR	((SLData_t)0.95)

SLData_t	pIIRFilterState[IIR_FILTER_STAGES * 2];
SLData_t	*pPNSequence, *pDisplayArray;
SLData_t	PnsPhase, PnsCurrentValue;
SLData_t	*pLookUpTable;							/* For fast sine lookup */
SLData_t	CarrierPhase;

void main (void);

void main (void)
{
	GraphObject *h2DGraph;							/* Declare graph object */

	SLData_t DifferentiatePrevious = SIGLIB_ZERO;	/* Previous value of differential */
	SLData_t EnvelopePrevious = SIGLIB_ZERO;		/* Previous value of envelope */

													/* Allocate memory */
	pPNSequence = SUF_VectorArrayAllocate (SAMPLE_LENGTH);
	pDisplayArray = SUF_VectorArrayAllocate (SAMPLE_LENGTH);
	pLookUpTable = SUF_VectorArrayAllocate (SINE_TABLE_SIZE);

	h2DGraph =										/* Initialize graph */
		Create2DGraph ("Frequency Modulation",		/* Graph title */
					   "Time / Frequency",			/* X-Axis label */
					   "Magnitude",					/* Y-Axis label */
					   SV_AUTO_SCALE,				/* Scaling mode */
					   SV_SIGNED,					/* Sign mode */
					   SV_GRAPH_LINE,				/* Graph type */
					   "localhost");				/* Graph server */
	if (h2DGraph == NULL)							/* Graph creation failed - e.g is server running ? */
	{
		printf ("\nGraph creation failure. Please check that the server is running\n");
		exit (1);
	}

	SIF_Iir (pIIRFilterState,						/* Pointer to filter state array */
			 IIR_FILTER_STAGES);					/* Number of second order stages */

													/* Initialize FM modulator */
	SIF_FrequencyModulate (&CarrierPhase,			/* Pointer to carrier phase */
						   pLookUpTable,			/* Pointer to LUT array */
						   SINE_TABLE_SIZE);		/* Table length */

	PnsPhase = SIGLIB_ZERO;							/* Initialize PNS generator */
	PnsCurrentValue = SIGLIB_ZERO;

													/* Generate the PN source */
	SDA_SignalGenerate (pPNSequence,				/* Pointer to destination array */
						SIGLIB_PN_SEQUENCE,			/* Signal type - Pseudo random number sequence */
						SIGLIB_TWO,					/* Signal magnitude range */
						SIGLIB_FILL,				/* Fill (overwrite) or add to existing array contents */
						BAUD_RATE,					/* Signal frequency */
						SIGLIB_MINUS_ONE,			/* Signal minimum level */
						SIGLIB_FOUR,				/* Number of discrete levels in PN sequence */
						SIGLIB_ZERO,				/* Signal end value - Unused */
						&PnsPhase,					/* PRN phase - used for next iteration */
						&PnsCurrentValue,			/* PRN current value - used for next iteration */
						SAMPLE_LENGTH);				/* Output array length */

	Display2DGraph (h2DGraph,						/* Graph handle */
				    "PN Sequence",					/* Title of the dataset */
				    pPNSequence,					/* Array of Double dataset */
				    SAMPLE_LENGTH,					/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_BLUE,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_NEW);					/* New graph */
	printf ("\nPN Sequence\n");

													/* Frequency modulate the PN signal */
	SDA_FrequencyModulate (pPNSequence,				/* Modulating signal source pointer */
						   pPNSequence,				/* Modulated signal destination pointer */
						   CARRIER_FREQ,			/* Carrier frequency */
						   MOD_INDEX,				/* Modulation index */
						   &CarrierPhase,			/* Pointer to carrier phase */
						   pLookUpTable,			/* Fast cosine look up table */
						   SINE_TABLE_SIZE,			/* Look up table size */
						   SAMPLE_LENGTH);			/* Array length */

	SDA_Polynomial (pPNSequence,					/* Pointer to source array */
					pDisplayArray,					/* Pointer to destination array */
					SIGLIB_MINUS_HALF,				/* x^0 coefficient */
					SIGLIB_QUARTER,					/* x^1 coefficient */
					0,								/* x^2 coefficient */
					0,								/* x^3 coefficient */
					0,								/* x^4 coefficient */
					0,								/* x^5 coefficient */
					SAMPLE_LENGTH);					/* Array length */

	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Modulated Sequence",			/* Title of the dataset */
				    pDisplayArray,					/* Array of Double dataset */
				    SAMPLE_LENGTH,					/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_RED,							/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("Modulated Sequence\n");

													/* Demodulate the FM signal */
	SDA_FrequencyDemodulate (pPNSequence,					/* Modulated signal source pointer */
							 pPNSequence,					/* Demodulated signal destination pointer */
							 &DifferentiatePrevious,		/* Previous value of differential */
							 &EnvelopePrevious,				/* Previous value of envelope */
							 DEMOD_ENVELOPE_DECAY_FACTOR,	/* Envelope decay factor */
							 SAMPLE_LENGTH);				/* Array length */


													/* Filter demodulated signals */
	SDA_Iir (pPNSequence,							/* Input array to be filtered */
			 pPNSequence,							/* Filtered output array */
			 pIIRFilterState,						/* Pointer to filter state array */
			 pIIRFilterTaps,						/* Pointer to filter coefficients array */
			 IIR_FILTER_STAGES,						/* Number of stages */
			 SAMPLE_LENGTH);						/* Array length */

	SDA_Polynomial (pPNSequence,					/* Pointer to source array */
					pDisplayArray,					/* Pointer to destination array */
					SIGLIB_MINUS_HALF,				/* x^0 coefficient */
					SIGLIB_ONE,						/* x^1 coefficient */
					0,								/* x^2 coefficient */
					0,								/* x^3 coefficient */
					0,								/* x^4 coefficient */
					0,								/* x^5 coefficient */
					SAMPLE_LENGTH);					/* Array length */

	Display2DGraph (h2DGraph,						/* Graph handle */
				    "Demodulated Sequence",			/* Title of the dataset */
				    pDisplayArray,					/* Array of Double dataset */
				    SAMPLE_LENGTH,					/* Number of data points */
					SV_GRAPH_LINE,					/* Graph type */
				    SV_GREEN,						/* Colour */
					SV_HIDE_MARKERS,				/* Marker enable / disable */
					SV_GRAPH_ADD);					/* New graph */
	printf ("Demodulated Sequence\n");
	
	SUF_MemoryFree (pPNSequence);					/* Free memory */
	SUF_MemoryFree (pDisplayArray);
	SUF_MemoryFree (pLookUpTable);

}		/* End of main() */

