Developing a multi-thread Simulation of GPS system You’ll only need to add the threads – all functions (except correlation( )) provided M. Smith Electrical Engineering, University of Calgary Smithmr @ ucalgary.ca 9/21/2018
Tackled today Why bother with a GPS example of a multi-tasking DSP problem? Prototype of working product Explanation of the provided functions Tests are provided so you can test out your assembly code versions of the correlation functions. Lab. 4 and Take home quiz 4 How are they interlinked? 9/21/2018
Why bother? Learn the basics of programming DSP within real time operation system constraints Interesting Basic concepts to understand GPS functionality Ability to easily visualize work load Basic C++ correlation (provided by me) (Lab. 4) FFT correlation (provided by Analog as part of C++ library (THQ4) Assembly FIR algorithm modified for correlation (Lab. 4 using Lab 3 code provided by you) Use of CLU XCORR instruction (THQ4 -- Hints from Analog, myself and Trevor) Research side Allows me to test out the E-TDD tool set in RTOS environment on embedded system, and gain personal familiarity with problems of doing so. 9/21/2018
GPS Positioning Concepts (1) For now make 2 assumptions: We know the distance to each satellite We know where each satellite is Require 3 satellites for a 3-D position in this “ideal” scenario Requires 4 satellites to account for local receiver clock drift. 9/21/2018
GPS Signal Structure Each satellite transmits 2 carrier frequencies referred to as L1 (1575 MHz) and L2 (1227 MHz) Each carrier frequency is BPSK modulated with a unique PRN (pseudo random number) code The PRN code on L1 is called CA code (coarse acquisition), The PRN code on L2 is called P code (precise) CA code takes 1 ms for full PRN transmission at 1MHz chip (bit) rate. P code takes 1.5 s for full PRN transmission at ~10MHz chip rate Also modulated on each carrier is 50 Hz data that includes the current position of the satellite 9/21/2018
Determining Time Use the PRN code to determine time (1) Use the PRN code to determine time Use time to determine distance to the satellite distance = speed of light * time 9/21/2018
Algorithms to Find PRN Phase Time-domain Cross correlation: 1/N ∑ x1 (n) * x2(n) Coding equivalent to FIR filter, but need to filter N sets of data, each shifted by one data point Correlation of perfectly matching signals gives a maximum value Correlation of 2 random data sequences tends to 0 PRN code from different satellites are designed to correlate to 0. Frequency domain correlation: 1/N F-1[X1(k)X2(k)] where F-1 is the inverse Discrete Fourier Transform and the X’s are the Discrete Fourier Transforms of two sequences D 9/21/2018
Lab. 4 – Parts 1, 2 and 3 – done as pre-laboratory tasks – about 1 hour Part 1 -- Create an Initialization Thread Use VDK::Sleep(200) sleep as a work load Part 2 – Launch (create) Satellite Receiver Tasks as free running tasks Use VDK::Sleep(X) as a work load ClearReceiverThread X = 100 ReceiveSatellite1 X = 10 ReceiveSatellite2 X = 20 ReceiveSatellite3 X = 30 Part 3 – Add semaphores to get satellite tasks running in proper time sequences 9/21/2018
Lab. 4 – Continued – details to be added Part 4 -- Add Satellite Receiver Tasks Payloads Download payload code from the web – code provided Part 5 – Generate E-TTD tests for correlation function designed using your existing FIR filter code Part 6 – Add analysis and reporting threads Part 7 – adjust task priorities to make realistic and working Demo and code hand-in with minor write-up 9/21/2018
Lab. 4 – Adding payloads to the threads Thread set to receive signals from satellites Simulation – Clear receiveBuffer. Add satelliteX’s PRN signal stream to receiveBuffer based on satellite location and speed. Functions and their tests provided Thread set to analyze received signal Correlate information in receiveBuffer with satelliteX PRN stream to see if signal from satellite is present or not. Analysis functions and their tests provided Correlation function tests provided Thread set to report on satellite status ErrorX means that signal to satellite signal X was lost 9/21/2018
Final result – VDK Thread Picture Satellite thread generates signal into receiveBuffer Analysis thread – long execution time – each tick = 0.05 ms 9/21/2018
Satellite signal “received” into receiveBuffer Clear Add Add Add Start buffer Sat1 Sat2 Sat3 Analysis 9/21/2018
Analysis errors can occur Errors occur – here one satellite is active but algorithm gets confused. Length of PRN too small Choice of PRN poor – rand( ) poor? 9/21/2018
Satellite moving in and out of range 9/21/2018
InitializationThread::Run() VDK::CreateThread(kReceiverControlThread); VDK::CreateThread(kAnalysisThread); VDK::CreateThread(kError1); VDK::CreateThread(kError2); VDK::CreateThread(kError3); VDK::CreateThread(kReportThread); VDK::CreateThread(kReceiverBufferClear); VDK::CreateThread(kReceive1Satellite); VDK::CreateThread(kReceive2Satellite); VDK::CreateThread(kReceive3Satellite); while (1) { VDK::PostSemaphore(kCaptureSignalSTART); VDK::Sleep(1500); if (VDK::GetUptime( ) > 20000) exit(0); } You can cut-and-paste this code from the slide PROVIDED your thread names are the same as mine Order of creation changes the way things look in VDK HISTORY window 9/21/2018
void ReceiverControlThread::Run() // You’ll need to add #include “Satellite.h” // Generate a PRN sequence Warning -- big problems with the rand( ) generator const int prn_length = TEST_PRN_LENGTH; InitializeSatelliteData(prn_length); SetSatelliteVelocity(2, 60); SetSatelliteLocation(2, 0); while (1) { VDK::PendSemaphore(kCaptureSignalSTART, 0); VDK::PostSemaphore(kReceiverBufferClearSTART); VDK::PendSemaphore(kReceiverBufferClearDONE, 0); VDK::PostSemaphore(kReceiver1SatelliteSTART); VDK::PendSemaphore(kReceiver1SatelliteDONE, 0); VDK::PostSemaphore(kReceiver2SatelliteSTART); VDK::PendSemaphore(kReceiver2SatelliteDONE, 0); VDK::PostSemaphore(kReceiver3SatelliteSTART); VDK::PendSemaphore(kReceiver3SatelliteDONE, 0); VDK::PostSemaphore(kAnalysisSTART); VDK::PendSemaphore(kAnalysisDONE, 0); VDK::PostSemaphore(kCaptureSignalDONE); } 9/21/2018
ReceiverBufferClear::Run() #include "Satellite.h" // ReceiverBufferClear Run Function (ReceiverBufferClear's main{}) void ReceiverBufferClear::Run() { while (1) // TODO - Put the thread's "main" body HERE VDK::PendSemaphore(kReceiverBufferClearSTART, 0); ClearReceiveBuffer( ); VDK::PostSemaphore(kReceiverBufferClearDONE); // Use a "break" instruction to exit the "while (1)" loop } // TODO - Put the thread's exit from "main" HERE // A thread is automatically Destroyed when it exits its run function 9/21/2018
Adding satellite data void Receive2Satellite::Run() { // Data not added from this satellite while (1) { VDK::PendSemaphore(kReceiver2SatelliteSTART, 0); // TransferSatelliteDataToReceiveBuffer(1); VDK::PostSemaphore(kReceiver2SatelliteDONE); } void Receive3Satellite::Run() { // Data added VDK::PendSemaphore(kReceiver3SatelliteSTART, 0); TransferSatelliteDataToReceiveBuffer(2); VDK::PostSemaphore(kReceiver3SatelliteDONE); 9/21/2018
AnalysisThread::Run() void AnalysisThread::Run() { bool valid_results; while (1) { // TODO - Put the thread's "main" body HERE VDK::PendSemaphore(kAnalysisSTART, 0); AnalyseReceiveBuffer( ); valid_results = ValidateResults( ); if (!valid_results) { VDK::PostSemaphore(kReportSTART); VDK::PendSemaphore(kReportDONE, 0); } VDK::PostSemaphore(kAnalysisDONE); 9/21/2018
void ReportThread::Run( ) while (1) { VDK::PendSemaphore(kReportSTART, 0); if ((satelliteActive[0] != MYsatelliteActive[0]) || (satelliteLocation[0] != MYsatelliteLocation[0])) VDK::PostSemaphore(kSatellite0LOST); if ((satelliteActive[1] != MYsatelliteActive[1]) || (satelliteLocation[1] != MYsatelliteLocation[1])) if ((satelliteActive[2] != MYsatelliteActive[2]) || (satelliteLocation[2] != MYsatelliteLocation[2])) VDK::PostSemaphore(kSatellite1LOST); VDK::PostSemaphore(kSatellite2LOST); VDK::PostSemaphore(kReportDONE); } Just spotted a BUG 9/21/2018
What you’ll need to modify void CorrelateAlongReceiverBuffer(int *satellitePRN, int array_size, int *correlation_result){ for (int i = 0; i < RECEIVE_BUFFER_LENGTH; i++) correlation_result[i] = 0; for (int result_index = 0; result_index < RECEIVE_BUFFER_LENGTH - array_size; result_index++) { int sum = 0; for (int sum_index = 0; sum_index < array_size; sum_index++) sum = sum + satellitePRN[sum_index] * receiveBuffer[sum_index + result_index]; correlation_result[result_index] = sum; } 9/21/2018
Provided “Satellite.h” #ifdef DECLARE_SATELLITE_VARIABLES #define EXTERN #else #define EXTERN extern #endif #define RECEIVE_BUFFER_LENGTH 256 EXTERN int receiveBuffer[RECEIVE_BUFFER_LENGTH]; void ClearReceiveBuffer(void); #define NUM_SATELLITES 3 #define MAX_PRN_LENGTH 128 #define TEST_PRN_LENGTH 128 // Generate a pseudo-random number sequence // Warning -- big problems with the rand( ) generator // when generating random bits -- (rand ( ) >> X ) % 2 #define SATELLITE_SEED 0x12397 EXTERN pm int satellitePRN[NUM_SATELLITES][MAX_PRN_LENGTH]; EXTERN pm bool satelliteActive[NUM_SATELLITES]; EXTERN pm int satelliteLocation[NUM_SATELLITES]; EXTERN pm int satelliteNextLocation[NUM_SATELLITES]; EXTERN pm int satelliteVelocity[NUM_SATELLITES]; EXTERN pm int MYsatelliteLocation[NUM_SATELLITES]; EXTERN pm bool MYsatelliteActive[NUM_SATELLITES]; EXTERN pm int MYsatelliteNextLocation[NUM_SATELLITES]; EXTERN pm int MYsatelliteVelocity[NUM_SATELLITES]; 9/21/2018
Provided “Satellite.h” void TransferSatelliteDataToReceiveBuffer(int which_satellite); bool InitializeSatelliteData(int prn_length); void SetSatelliteVelocity(int which_satellite, int which_speed); void SetSatelliteLocation(int which_satellite, int which_distance); int GetSatelliteVelocity(int which_satellite); int GetSatelliteLocation(int which_satellite); bool InitializeMYSatelliteData(void); void SetMYSatelliteVelocity(int which_satellite, int which_speed); void SetMYSatelliteLocation(int which_satellite, int which_distance); int GetMYSatelliteVelocity(int which_satellite); int GetMYSatelliteLocation(int which_satellite); void CrossCorrelate(int *first, int *second, int *correlation_result, int array_size); void CorrelateAlongReceiverBuffer(int *satellitePRN, int array_size, int *correlation_result); int MaximumLocation(int *correlation_result, int array_size); int MaximumValue(int *correlation_result, int array_size); bool ValidateResults(void); void AnalyseReceiveBuffer(void); int CalculateCorrelationRange(void); int CalculateCorrelationAverage(void) 9/21/2018
Provided Tests Examples TEST(CrossCorrelationTest, DEVELOPER_TEST) { TEST_LEVEL(9); int first[ARRAY_SIZE] = {1, 0, 0, 0, 0, 0, 0, 0}; int second[ARRAY_SIZE] = {0, 1, 0, 0, 0, 0, 0, 0}; int third[ARRAY_SIZE] = {0, 0, 1, 0, 0, 0, 0, 0}; int correlation_result[ARRAY_SIZE]; int maximum_location; CrossCorrelate(first, first, correlation_result, ARRAY_SIZE); maximum_location = MaximumLocation(correlation_result, ARRAY_SIZE); CHECK_EQUAL(maximum_location, 0); CrossCorrelate(first, second, correlation_result, ARRAY_SIZE); CHECK_EQUAL(maximum_location, 1); etc. …….. } 9/21/2018
Tackled today Why bother with a GPS example of a multi-tasking DSP problem? Prototype of working product Explanation of the provided functions Tests are provided so you can test out your assembly code versions of the correlation functions. Lab. 4 and Take home quiz 4 How are they interlinked? 9/21/2018