************ SPS Analyser ************ In the context of AA0.5, SPS will be constituted of 6 stations. From these stations, it will generate traffic over a 75MHz bandwidth with two 16-bits polarisations oversampled at 32/27. As a results this will generate 17Gbps of raw data. Computation for the various data rate can be found at this `website `_. This raw data is encapsulated in `SPEAD `_ packets of 8264 bytes. .. image:: diagrams/spead_headers.png :width: 400 :alt: SPEAD header In regards to Low CBF, we need to be able to analyse incoming traffic. To do so, the Perentie team has developed a set of analysing methods that can validate incoming traffic from either CNIC, CNIV-VD, or the TPM. Initialisation ############## The SPS analyser only takes a single json configuration string, it should contain the following for 2 stations and 2 channels: .. code-block:: json { "coarse_channels": [124, 125], "stations": [345, 350] } Using this json string, let's now create the object .. code-block:: python sps_analyser = SPSAnalyser(json.dumps({ "coarse_channels": [channel for channel in range(330, 330+96)], "stations": [1, 2, 3, 4, 5, 6] })) Once the object initialised, the visibility analyser can now extract visibilities from the pcap file. This is done as follows: .. code-block:: python sps_analyser.extract_sps_data("/path/to/pcap/sps.pcap") At this point, the SPSAnalyser object would contain the following public attributes: * ``coarse_channels``: list of coarse channels to analyse * ``stations``: list of stations to analyse * ``nb_station``: the number of stations * ``time_sequence``: the set containing all timestamps from the data * ``samples``: containing all samples from the SPS source. Those are stored as ((self.channels, self.n_pol, self.time_steps), dtype=np.int8) Use cases ######### SPS data unpacking ================================= In the following function, we want to have a quick overview of the data from SPS sources wether it is a CNIC or a TPM. To do so we have implemented a series of function that plot various time series and histogram of the data. Histograms of the data ---------------------- We have implemented 2 main functions that build histogram of the data. The first one is counting the number of samples for each coarse channel and each (sub)station. This function can be called as follows: .. code-block:: python sps_analyser.print_number_of_samples_per_channel() As a result, this function produce the following type of histogram for station 1 and channel 171 as an example .. image:: diagrams/SPS_traffic_sample_per_channel.svg :width: 400 :alt: SPS samples per station and channel The second type of histograms is plotting the distribution of SPS data for each coarse channel and station and for the different polarisations. Those polarisation are Vertical and Horizontal with a real and imaginary component. In total that creates 4 plot per frequency-(sub)station and it is produced with the following function .. code-block:: python sps_analyser.histogram_channel_station( channels_of_interest, station_of_interest) where * channels_of_interest are the coarse channels on which the histogram is calculated. * station_of_interest are the origin stations of the data. As a result, this function produce the following type of histogram for station 1 and channel 173 .. image:: diagrams/histo_173_station_1.svg :width: 400 :alt: SPS value distribution Time series of the data ----------------------- Another typical usage of the SPS analyser consists in analysing one channel at the time. To do so, we have implemented a function that produce a time series for the 4 different polarisation of the data. Those polarisation are Vertical and Horizontal with a real and imaginary component. Those time series are plotted on the same figure in function of the sample number. This produces one figure per (sub)station .. code-block:: python sps_analyser.print_channel_of_interest(channel_to_inspect: int, slice_of_samples) where * channel_to_inspect is a coarse channel to inspect * slice_of_samples is the slice of sample number as in from sample number a to b is slice_of_sample = (a, b) For example the following call .. code-block:: python sps_traffic.print_channel_of_interest(173, (2000, 2800)) produces 6 figures (one per station) for the channel 173, zooming on samples 2000 to 2800 similar to the figure below .. image:: diagrams/channel_173_station_1.0.svg :width: 400 :alt: Station 1 channel 173 time series Advanced SPS data analysis ================================= So far we have implemented 2 advanced analysis, namely the FFT of the data and the RMS calculation. FFT of the data ----------------------- We have implemented 2 functions that Fourier transform the captured SPS traffic. Be aware that depending on the number of sample collected those 2 functions can take a significant amount of time to perform. The reason behind the 2 function is to perform FFT on either the real data or the complex data, with the complex data the more commonly used version of the FFT. Nonetheless, they both offer similar interface as follow. .. code-block:: python sps_analyser.print_fft_real(channels_of_interest: list, station_of_interest: list) sps_analyser.print_fft_complex(channels_of_interest: list, station_of_interest: list): where for both function * channels_of_interest are the coarse channels on which the FFT is centered. * station_of_interest are the origin (sub)stations of the data. As a result, both function will create a single figure for each combination of channel and station. As an example below are the FFTs in real and complex for station 1 and channel 171 .. image:: diagrams/FFT_real_channel_171_station_1.png :width: 400 :alt: Station 1 channel 171 real FFT .. image:: diagrams/FFT_channel_171_station_1.png :width: 400 :alt: Station 1 channel 171 complex FFT RMS of the data ---------------- When receiving data from SPS, we might want to know the various power contained in each coarse channel. For that we have implemented the following RMS calculation based on the SPS data. In short the following function calculates and saves a figure containing RMS per coarse channel from SPS. It also returns a dictionary containing the RMS for further investigation if needed .. code-block:: python sps_analyser.rms_calculation_and_printing(channels_of_interest: list, station_of_interest: list) where * channels_of_interest are the coarse channels on which the RMS is calculated. * station_of_interest are the origin (sub)stations of the data. As a result we can produce the following figure .. image:: diagrams/rms_db.svg :width: 400 :alt: Station 1 channel 171 complex FFT