/comms-physical-layer

Primary LanguageC++GNU General Public License v3.0GPL-3.0

This repository contains the Physical and Coding Layer as defined in the CCSDS Layered model. More specifically, this implements:

Error Correction Codes

BCH Decoder

The CCSDS 231.0-B-4 book defines a (63,56) modified Bose-Chaudhuri-Hocquenghem (BCH) code, using the following generator polynomial:

$$g(x) = x^7 + x^6 + x^2 + 1$$

The BCH codeword consists of three fields: 56 information bits, 7 parity bits, and 1 appended filler bit. BCH codeword fields
The (63,56) modified BCH code generator is shown in the image below. During the transmission of information bits, the switch is set to position (1) and during the transmission of parity bits, the switch is set to position (2). Position (3) is reserved for the filler bit.
BCH code generator

Class Definition

The decoder is defined in inc/BCHDecoder.hpp

Methods

[[nodiscard]] etl::optional<uint64_t> decodeBCH(uint64_t codeword)
  • codeword : Provide the input to the decoder in the form of a 64bit unsigned integer
  • Returns an optional object. The optional is empty in case of an input that contains more than one mistakes. Otherwise, a 64bit unsigned integer with only the 56 least significant bits occupied can be unwrapped from the returned object.

Convolutional Encoder

The CCSDS 130.1-G-3 (7,1/2) Convolutional Encoder (meaning rate r = 1/2 and constraint length k = 7) is implemented. The Convolutional Encoder is shown in the image below. It consists of a shift register and some exclusive OR gates that implement the two parity checks. Preceding bits are considered to be 0. convolutional encoder

Class Definition

The encoder is defined in inc/Convolutional.hpp

Methods

void encode(const etl::bitset<inputLength>& input, etl::bitset<outputLength>& output);
  • input : Provide the input to the encoder in the form of a reference to an etl::bitset of size inputLength
  • output : Provide the input to the encoder in the form of a reference to an etl::bitset of size outputLength

LDPC Encoder

The CCSDS 130.1-G-3 LDPC Encoder at rate of r = 4/5 with information block length k = 4096 (encoded size is then 5120) is implemented.

Class Definition

The encoder is defined in inc/LDPCEncoder.hpp. inc/PostionRowsEsoteric.hpp and inc\RowsParityBitsEsoteric.hpp are also used in the implementation.

Methods

void encode(const etl::bitset<inputLength>& input, etl::bitset<outputLength>& output);
  • input : Provide the input to the encoder in the form of a reference to an etl::bitset of size inputLength
  • output : Provide the input to the encoder in the form of a reference to an etl::bitset of size outputLength

Modulations

The GMSK and OQPSK modulation were mostly ported to C++ from the codec2 project by Rowetel.

FM Modulation

As part of the GMSK modulator, an FM modulator is also provided:

Class definition

FMTranscoder(uint32_t samplingFrequency, uint32_t maxModulatingFrequency, uint32_t basebandFrequency, uint16_t maxDeviation, bool preDeEmphasis, bool limitDeltaPhase)
  • samplingFrequency: Sample frequency of the signal
  • maxModulatingFrequency: Highest frequency component present in the modulated signal
  • basebandFrequency: Baseband frequency (usually set to 0)
  • maxDeviation: Maximum deviation from the carrier frequency
  • preDeEmphasis: Defines whether pre- and and de-emphasis filters of high frequencies is applied

Methods

modulate(const double *signal, uint16_t signal_length, double *in_phase_signal, double *quadrature_signal)
  • signal: Pointer to the input signal to be modulated
  • signal_length: Input signal length
  • in_phase_signal: Pointer to output in-phase component
  • quadrature_signal: Pointer to output quadrature component

GMSK Transcoder

Warning: The class internally initializes internal buffers (size TBC with configurable sps) for calculations that can't happen in-place. So take this into account that if you have severe space restrictions, this will take-up a non-negligible amount of memory

The GMSK modulator also automatically uses NRZ encoding in the input to minimize the BER on the receiving end. The filter on the transceiver uses pre-coded taps for BTs = 0.5 (for more information refer to CCSDS 413.0-G-3 Section 3.1)

Class definition

GMSKTranscoder(uint32_t sampleFrequency, uint32_t symbolRate, bool equalize)
  • sampleFrequency: Sampling frequency
  • symbolRate: Symbol rate
  • equalize: Whether equalization will be used in the demodulator to offset the effects of the (non-Nyquist) Gaussian filter used in the modulator

img.png

Methods

modulate(bool *signal, uint16_t signalLength, double *inPhaseSignal, double *quadratureSignal)
  • signal: Pointer to the input signal to be modulated
  • signalLength: Input signal signal length
  • inPhaseSignal: Pointer to output in-phase component
  • quadratureSignal: Pointer to output quadrature component
demodulate(double *inputInPhaseSignal, double *inputQuadratureSignal, uint16_t signalLength, bool *signal)
  • inputInPhaseSignal: Pointer to input in-phase component
  • inputQuadratureSignal: Pointer to input quadrature component
  • signalLength: Input signal length
  • signal: Pointer to output signal

OQPSK Transcoder

Warning: The class internally initializes internal buffers (size TBC with configurable sps) for calculations that can't happen in-place. So take this into account that if you have severe space restrictions, this will take-up a non-negligible amount of memory

Class definition

OQPSKTranscoder(uint32_t samplingFrequency, uint32_t symbolRate)
  • sampleFrequency: Sampling frequency
  • symbolRate: Symbol rate

Methods

modulate(bool *signal, uint16_t signalLength, double *inPhaseSignal, double *quadratureSignal)
  • signal: Pointer to the input signal to be modulated
  • signalLength: Input signal length
  • inPhaseSignal: Pointer to output in-phase component
  • quadratureSignal: Pointer to output quadrature component
I/Q Plot

OQPSK Modulation I/Q

Synchronization

The GMSK detector/synchronization algorithm used, is based on an article by Daniel Estevez: "DSLWP-B GMSK detector"

The gmsk_detector.py contains code that is based on the jupyter_notebooks repository and mainly on the gmsk_dslwp.py GMSK detector script. The Synchronizer class is based on this implementation.

Class Definition

Synchronizer(int sampleFrequency, int symbolRate)
  • sampleFrequency: Sampling frequency
  • symbolRate: Symbol Rate

Methods

void computeCorrelation(double *inPhaseSignal, double *quadratureSignal, int signalLength)
  • inPhaseSignal: Pointer to input in-phase component
  • quadratureSignal: Pointer to input quadrature signal
  • signalLength: Input signal length

This method takes as input the GMSK modulated received signal and calculates the acquisition matrix in acqBuffer. From this matrix it is possible to compute the correlation of the received signal to a synchronization marker to then conclude whether the signal contains the marker and at which sample it begins. An example is showcased in syncTest.cpp.

If a spike exists in the correlation signal then the synchronization marker exists, and starts at the sample the spike is

Correlation Plot

Correlation: Sync Marker exists