/* SigLib BPSK Example Simulating : 400 bps '1' = cos (theta), '0' = - cos (theta) Carrier frequency = 1200 Hz. Sample rate = 9600 Hz. For a typical transmitter the modultor would be followed by a filter e.g a root raised cosine filter, which can be implemented using the SigLib SIF_RootRaisedCosineFilter function. */ #include #include #include "GraphFunctions.h" #include /* Define constants */ #define DISPLAY_GRAPHICS 0 /* Set to '1' to display graphics */ #define DISPLAY_FILTER_OUTPUT 0 /* Set to '1' to display the output of the demodulator filter */ #define TX_BIT_MODE_ENABLED 0 /* Set to '1' to process Tx bits, '0' for bytes */ #define DEBUG_LOG_FILE 0 /* Set to '1' to enable logging to debug.log */ #define SAMPLE_LENGTH ((SLArrayIndex_t)512) #define NUMBER_OF_LOOPS ((SLArrayIndex_t)8) #define SAMPLE_RATE 9600.0 #define BAUD_RATE 600.0 #define CARRIER_FREQ 1200.0 #define SYMBOL_LENGTH 16 /* Number of samples per symbol - SAMPLE_RATE / BAUD_RATE */ #define MAX_RX_STRING_LENGTH ((SLArrayIndex_t)80) /* Maximum length of an Rx string */ #define CARRIER_TABLE_FREQ ((SLData_t)100.0) /* Frequency of sine wave in table */ #define CARRIER_SINE_TABLE_SIZE ((SLArrayIndex_t) (SAMPLE_RATE / CARRIER_TABLE_FREQ)) /* Number of samples in each of cos and sine table */ /* Declare arrays and variables */ char TxString[] = "dHello World - abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; /* The 'd' at the start is a dummy character that is not received while the filters are initialized */ char RxString[MAX_RX_STRING_LENGTH]; char *TxStringPtr, *RxStringPtr; SLData_t *pData, *pCarrierTable; SLData_t TxCarrierPhase; SLData_t SampleCount; #define COSTAS_LP_LPF_LENGTH 17L /* Costas loop LP LPF FIR filter length */ #define VCO_MODULATION_INDEX ((SLData_t)0.005) /* Modulation index */ #define LOOP_FILTER_ALPHA ((SLData_t)0.9) /* Feedback coeff for one-pole loop filter */ #define VCO_SINE_TABLE_SIZE ((SLArrayIndex_t)1024) /* Look up table for fast sine calculation */ SLData_t *pCostasLpLPFCoeffs, *pCostasLpLPF1State, *pCostasLpLPF2State; /* Costas loop loop filter coefficient pointer */ SLArrayIndex_t CostasLpLPF1Index; /* Costas loop inphase LPF filter index */ SLArrayIndex_t CostasLpLPF2Index; /* Costas loop quadrature phase LPF filter index */ SLData_t CostasLpVCOPhase; /* Costas loop VCO phase */ SLData_t CostasLpState; /* Costas loop feedback state for next iteration */ SLData_t CostasLpLoopFilterState; /* Costas loop loop filter feedback coeff */ SLData_t *pVCOLookUpTable; /* VCO cosine look-up-table pointer */ SLArrayIndex_t RxSampleClock; /* Used to keep track of the samples and symbols */ SLData_t RxSampleSum; /* Used to keep decide which bit was Tx'd */ #if DISPLAY_FILTER_OUTPUT SLData_t *pFilterOutput; #endif void main(void) { GraphObject *h2DGraph; /* Declare graph object */ SLFixData_t i, j; SLFixData_t LoopCount; #if TX_BIT_MODE_ENABLED SLArrayIndex_t TxBitIndex; #endif SLArrayIndex_t DemodulatedBit; SLArrayIndex_t RxBitIndex = ((SLArrayIndex_t)7); /* Initialise bit count for correct synchronization */ #if DEBUG_LOG_FILE SUF_ClearDebugfprintf (); for (i = 0; i < 20; i++) { SUF_Debugfprintf ("TxString[%ld]", i); dpchar (TxString[i]); } #endif /* Allocate memory */ pData = SUF_VectorArrayAllocate (SAMPLE_LENGTH + 10); /* Not always returning the same number of samples from the modulator */ pCarrierTable = SUF_VectorArrayAllocate (CARRIER_SINE_TABLE_SIZE); pCostasLpLPFCoeffs = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH); pCostasLpLPF1State = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH); pCostasLpLPF2State = SUF_VectorArrayAllocate (COSTAS_LP_LPF_LENGTH); pVCOLookUpTable = SUF_CostasLoopVCOArrayAllocate (VCO_SINE_TABLE_SIZE); if ((pData == NULL) || (pCarrierTable == NULL) || (pCostasLpLPFCoeffs == NULL) || (pCostasLpLPF1State == NULL) || (pCostasLpLPF2State == NULL) || (pVCOLookUpTable == NULL)) { printf ("Memory allocation failure\n\n"); } #if DISPLAY_FILTER_OUTPUT pFilterOutput = SUF_VectorArrayAllocate (SAMPLE_LENGTH); /* Array for displaying output of LPF */ SDA_Clear (pFilterOutput, /* Pointer to destination array */ SAMPLE_LENGTH); /* Array length */ #endif TxStringPtr = TxString; RxStringPtr = RxString; #if (DISPLAY_FILTER_OUTPUT) || (DISPLAY_GRAPHICS) h2DGraph = /* Initialize graph */ Create2DGraph ("Binary Phase Shift Keying", /* Graph title */ "Time", /* 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); } #endif SIF_BpskModulate (pCarrierTable, /* Carrier table pointer */ (CARRIER_TABLE_FREQ / SAMPLE_RATE), /* Carrier frequency */ &SampleCount, /* Transmitter sample count - tracks samples */ CARRIER_SINE_TABLE_SIZE); /* Carrier sine table size */ SIF_BpskDemodulate (&CostasLpVCOPhase, /* VCO phase */ pVCOLookUpTable, /* VCO look up table */ VCO_SINE_TABLE_SIZE, /* VCO look up table size */ CARRIER_FREQ / SAMPLE_RATE, /* Carrier frequency */ pCostasLpLPF1State, /* Pointer to loop filter 1 state */ &CostasLpLPF1Index, /* Pointer to loop filter 1 index */ pCostasLpLPF2State, /* Pointer to loop filter 2 state */ &CostasLpLPF2Index, /* Pointer to loop filter 2 index */ pCostasLpLPFCoeffs, /* Pointer to loop filter coefficients */ COSTAS_LP_LPF_LENGTH, /* Loop filter length */ &CostasLpLoopFilterState, /* Pointer to loop filter state */ &CostasLpState, /* Pointer to delayed sample */ &RxSampleClock, /* Pointer to Rx sample clock */ &RxSampleSum); /* Pointer to Rx sample sum - used to decide which bit was Tx'd */ TxCarrierPhase = SIGLIB_ZERO; /* Initialise BPSK transmitter phase */ /* The phase of the transmitter can be rotated by changing this value */ /* Clear demodulated data input array - This is important because we are going to be ORing in the received bits */ for (i = 0; i < MAX_RX_STRING_LENGTH; i++) { RxString[i] = 0; } for (LoopCount = 0; LoopCount < NUMBER_OF_LOOPS; LoopCount++) { for (i = 0; i < SAMPLE_LENGTH; i += (SIGLIB_BYTE_LENGTH * SYMBOL_LENGTH)) { #if TX_BIT_MODE_ENABLED for (TxBitIndex = 0; TxBitIndex < SIGLIB_BYTE_LENGTH; TxBitIndex++) { SDA_BpskModulate ((*TxStringPtr >> TxBitIndex), /* Modulating bit */ pData + i + (TxBitIndex * SYMBOL_LENGTH), /* Destination array */ pCarrierTable, /* Carrier table pointer */ &TxCarrierPhase, /* Carrier phase pointer */ SYMBOL_LENGTH, /* Samples per symbol */ CARRIER_FREQ / CARRIER_TABLE_FREQ, /* Carrier table increment */ CARRIER_SINE_TABLE_SIZE); /* Carrier sine table size */ } TxStringPtr++; /* Increment string pointer */ #else SDA_BpskModulateByte (*TxStringPtr++, /* Modulating byte */ pData + i, /* Destination array */ pCarrierTable, /* Carrier table pointer */ &TxCarrierPhase, /* Carrier phase pointer */ SYMBOL_LENGTH, /* Samples per symbol */ CARRIER_FREQ / CARRIER_TABLE_FREQ, /* Carrier table increment */ CARRIER_SINE_TABLE_SIZE); /* Carrier sine table size */ #endif } #if DISPLAY_GRAPHICS Display2DGraph (h2DGraph, /* Graph handle */ "Modulated Signal", /* Title of the dataset */ pData, /* 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 ("\nModulated Signal\nPlease hit to continue . . ."); getchar (); #endif for (i = 0; i < SAMPLE_LENGTH; i += (SIGLIB_BYTE_LENGTH * SYMBOL_LENGTH)) { for (j = 0; j < SIGLIB_BYTE_LENGTH; j++) { #if DISPLAY_FILTER_OUTPUT DemodulatedBit = SDA_BpskDemodulateDebug (pData + i + (j * SYMBOL_LENGTH), /* Source array */ &CostasLpVCOPhase, /* VCO phase */ VCO_MODULATION_INDEX, /* VCO modulation index */ pVCOLookUpTable, /* VCO look up table */ VCO_SINE_TABLE_SIZE, /* VCO look up table size */ CARRIER_FREQ / SAMPLE_RATE, /* Carrier frequency */ pCostasLpLPF1State, /* Pointer to loop filter 1 state */ &CostasLpLPF1Index, /* Pointer to loop filter 1 index */ pCostasLpLPF2State, /* Pointer to loop filter 2 state */ &CostasLpLPF2Index, /* Pointer to loop filter 2 index */ pCostasLpLPFCoeffs, /* Pointer to loop filter coefficients */ COSTAS_LP_LPF_LENGTH, /* Loop filter length */ &CostasLpLoopFilterState, /* Pointer to loop filter state */ LOOP_FILTER_ALPHA, /* Loop filter coefficient */ &CostasLpState, /* Pointer to delayed sample */ &RxSampleClock, /* Pointer to receive sample clock */ &RxSampleSum, /* Pointer to Rx sample sum - used to decide which bit was Tx'd */ SYMBOL_LENGTH, /* Samples per symbol */ pFilterOutput); /* Pointer to filter output data */ Display2DGraph (h2DGraph, /* Graph handle */ "Filter Output", /* Title of the dataset */ pFilterOutput, /* 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 ("\nFilter Output\nPlease hit to continue . . ."); getchar (); #else DemodulatedBit = SDA_BpskDemodulate (pData + i + (j * SYMBOL_LENGTH), /* Source array */ &CostasLpVCOPhase, /* VCO phase */ VCO_MODULATION_INDEX, /* VCO modulation index */ pVCOLookUpTable, /* VCO look up table */ VCO_SINE_TABLE_SIZE, /* VCO look up table size */ CARRIER_FREQ / SAMPLE_RATE, /* Carrier frequency */ pCostasLpLPF1State, /* Pointer to loop filter 1 state */ &CostasLpLPF1Index, /* Pointer to loop filter 1 index */ pCostasLpLPF2State, /* Pointer to loop filter 2 state */ &CostasLpLPF2Index, /* Pointer to loop filter 2 index */ pCostasLpLPFCoeffs, /* Pointer to loop filter coefficients */ COSTAS_LP_LPF_LENGTH, /* Loop filter length */ &CostasLpLoopFilterState, /* Pointer to loop filter state */ LOOP_FILTER_ALPHA, /* Loop filter coefficient */ &CostasLpState, /* Pointer to delayed sample */ &RxSampleClock, /* Pointer to receive sample clock */ &RxSampleSum, /* Pointer to Rx sample sum - used to decide which bit was Tx'd */ SYMBOL_LENGTH); /* Samples per symbol */ #endif *RxStringPtr |= (((char)DemodulatedBit) << RxBitIndex); RxBitIndex++; if (RxBitIndex >= SIGLIB_BYTE_LENGTH) { RxBitIndex = SIGLIB_AI_ZERO; *RxStringPtr++; } } } } #if DEBUG_LOG_FILE for (i = 0; i < 20; i++) { SUF_Debugfprintf ("RxString[%ld]", i); dpchar (RxString[i]); } #endif *RxStringPtr = 0; /* Terminate string for printf */ /* Print received string - Note the first two characters received are not from the required string due to receiver filter initialization */ printf ("BPSK received string : %s\n", RxString+2); SUF_MemoryFree (pData); /* Free memory */ SUF_MemoryFree (pCarrierTable); SUF_MemoryFree (pCostasLpLPFCoeffs); SUF_MemoryFree (pCostasLpLPF1State); SUF_MemoryFree (pCostasLpLPF2State); SUF_MemoryFree (pVCOLookUpTable); }