2014-05-21 07:42:26 +00:00
|
|
|
/*!
|
2014-06-01 11:22:26 +00:00
|
|
|
* \file galileo_e5_signal_processing.cc
|
2014-05-21 07:42:26 +00:00
|
|
|
* \brief This library implements various functions for Galileo E5 signals such
|
|
|
|
* as replica code generation
|
|
|
|
* \author Marc Sales, 2014. marcsales92(at)gmail.com
|
2014-05-20 19:53:12 +00:00
|
|
|
*
|
2014-05-21 07:42:26 +00:00
|
|
|
* -------------------------------------------------------------------------
|
|
|
|
*
|
2019-07-26 10:38:20 +00:00
|
|
|
* Copyright (C) 2010-2019 (see AUTHORS file for a list of contributors)
|
2014-05-21 07:42:26 +00:00
|
|
|
*
|
|
|
|
* GNSS-SDR is a software defined Global Navigation
|
|
|
|
* Satellite Systems receiver
|
|
|
|
*
|
|
|
|
* This file is part of GNSS-SDR.
|
|
|
|
*
|
2020-02-08 00:20:02 +00:00
|
|
|
* SPDX-License-Identifier: GPL-3.0-or-later
|
2014-05-21 07:42:26 +00:00
|
|
|
*
|
|
|
|
* -------------------------------------------------------------------------
|
2014-05-20 19:53:12 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "galileo_e5_signal_processing.h"
|
2016-01-10 21:21:31 +00:00
|
|
|
#include "Galileo_E5a.h"
|
|
|
|
#include "gnss_signal_processing.h"
|
2018-02-26 02:15:53 +00:00
|
|
|
#include <gnuradio/gr_complex.h>
|
2019-06-30 02:47:15 +00:00
|
|
|
#include <memory>
|
2019-08-17 11:56:54 +00:00
|
|
|
#include <utility>
|
2019-11-30 00:09:07 +00:00
|
|
|
#include <vector>
|
2016-01-10 21:21:31 +00:00
|
|
|
|
|
|
|
|
2020-05-07 19:47:45 +00:00
|
|
|
void galileo_e5_a_code_gen_complex_primary(std::span<std::complex<float>> _dest, int32_t _prn, const std::array<char, 3>& _Signal)
|
2014-05-20 19:53:12 +00:00
|
|
|
{
|
2018-08-13 08:18:05 +00:00
|
|
|
uint32_t prn = _prn - 1;
|
|
|
|
uint32_t index = 0;
|
2019-07-14 12:09:12 +00:00
|
|
|
std::array<int32_t, 4> a{};
|
2014-06-17 17:13:24 +00:00
|
|
|
if ((_prn < 1) || (_prn > 50))
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2015-03-16 23:22:20 +00:00
|
|
|
if (_Signal[0] == '5' && _Signal[1] == 'Q')
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-02-22 09:47:24 +00:00
|
|
|
for (size_t i = 0; i < GALILEO_E5A_Q_PRIMARY_CODE[prn].length() - 1; i++)
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_Q_PRIMARY_CODE[prn][i]);
|
2019-09-28 11:41:24 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), 0.0);
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), 0.0);
|
|
|
|
_dest[index + 2] = std::complex<float>(static_cast<float>(a[2]), 0.0);
|
|
|
|
_dest[index + 3] = std::complex<float>(static_cast<float>(a[3]), 0.0);
|
2016-05-02 21:46:30 +00:00
|
|
|
index = index + 4;
|
|
|
|
}
|
|
|
|
// last 2 bits are filled up zeros
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_Q_PRIMARY_CODE[prn][GALILEO_E5A_Q_PRIMARY_CODE[prn].length() - 1]);
|
2019-09-28 11:41:24 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), 0.0);
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), 0.0);
|
2016-05-02 21:46:30 +00:00
|
|
|
}
|
2015-03-16 23:22:20 +00:00
|
|
|
else if (_Signal[0] == '5' && _Signal[1] == 'I')
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-02-22 09:47:24 +00:00
|
|
|
for (size_t i = 0; i < GALILEO_E5A_I_PRIMARY_CODE[prn].length() - 1; i++)
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_I_PRIMARY_CODE[prn][i]);
|
2019-08-18 10:54:16 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), 0.0);
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), 0.0);
|
|
|
|
_dest[index + 2] = std::complex<float>(static_cast<float>(a[2]), 0.0);
|
|
|
|
_dest[index + 3] = std::complex<float>(static_cast<float>(a[3]), 0.0);
|
2016-05-02 21:46:30 +00:00
|
|
|
index = index + 4;
|
|
|
|
}
|
|
|
|
// last 2 bits are filled up zeros
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_I_PRIMARY_CODE[prn][GALILEO_E5A_I_PRIMARY_CODE[prn].length() - 1]);
|
2019-08-18 10:54:16 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), 0.0);
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), 0.0);
|
2016-05-02 21:46:30 +00:00
|
|
|
}
|
2015-03-16 23:22:20 +00:00
|
|
|
else if (_Signal[0] == '5' && _Signal[1] == 'X')
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-07-14 12:09:12 +00:00
|
|
|
std::array<int32_t, 4> b{};
|
2019-02-22 09:47:24 +00:00
|
|
|
for (size_t i = 0; i < GALILEO_E5A_I_PRIMARY_CODE[prn].length() - 1; i++)
|
2016-05-02 21:46:30 +00:00
|
|
|
{
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_I_PRIMARY_CODE[prn][i]);
|
|
|
|
hex_to_binary_converter(b, GALILEO_E5A_Q_PRIMARY_CODE[prn][i]);
|
2019-08-18 10:54:16 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), static_cast<float>(b[0]));
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), static_cast<float>(b[1]));
|
|
|
|
_dest[index + 2] = std::complex<float>(static_cast<float>(a[2]), static_cast<float>(b[2]));
|
|
|
|
_dest[index + 3] = std::complex<float>(static_cast<float>(a[3]), static_cast<float>(b[3]));
|
2016-05-02 21:46:30 +00:00
|
|
|
index = index + 4;
|
|
|
|
}
|
|
|
|
// last 2 bits are filled up zeros
|
2019-09-09 17:08:15 +00:00
|
|
|
hex_to_binary_converter(a, GALILEO_E5A_I_PRIMARY_CODE[prn][GALILEO_E5A_I_PRIMARY_CODE[prn].length() - 1]);
|
|
|
|
hex_to_binary_converter(b, GALILEO_E5A_Q_PRIMARY_CODE[prn][GALILEO_E5A_Q_PRIMARY_CODE[prn].length() - 1]);
|
2019-08-18 10:54:16 +00:00
|
|
|
_dest[index] = std::complex<float>(static_cast<float>(a[0]), static_cast<float>(b[0]));
|
|
|
|
_dest[index + 1] = std::complex<float>(static_cast<float>(a[1]), static_cast<float>(b[1]));
|
2016-05-02 21:46:30 +00:00
|
|
|
}
|
2014-06-17 17:13:24 +00:00
|
|
|
}
|
|
|
|
|
2018-08-13 08:18:05 +00:00
|
|
|
|
2020-05-07 19:47:45 +00:00
|
|
|
void galileo_e5_a_code_gen_complex_sampled(std::span<std::complex<float>> _dest, const std::array<char, 3>& _Signal,
|
2018-08-13 08:18:05 +00:00
|
|
|
uint32_t _prn, int32_t _fs, uint32_t _chip_shift)
|
2014-05-20 19:53:12 +00:00
|
|
|
{
|
2018-08-13 08:18:05 +00:00
|
|
|
uint32_t _samplesPerCode;
|
|
|
|
uint32_t delay;
|
2019-02-22 09:47:24 +00:00
|
|
|
const uint32_t _codeLength = GALILEO_E5A_CODE_LENGTH_CHIPS;
|
2019-08-31 09:37:29 +00:00
|
|
|
const int32_t _codeFreqBasis = GALILEO_E5A_CODE_CHIP_RATE_CPS;
|
2014-06-17 17:13:24 +00:00
|
|
|
|
2019-11-29 23:31:07 +00:00
|
|
|
std::vector<std::complex<float>> _code(_codeLength);
|
|
|
|
galileo_e5_a_code_gen_complex_primary(_code, _prn, _Signal);
|
2014-06-17 17:13:24 +00:00
|
|
|
|
2018-08-13 08:18:05 +00:00
|
|
|
_samplesPerCode = static_cast<uint32_t>(static_cast<double>(_fs) / (static_cast<double>(_codeFreqBasis) / static_cast<double>(_codeLength)));
|
2014-08-05 00:01:37 +00:00
|
|
|
|
2015-03-16 23:22:20 +00:00
|
|
|
delay = ((_codeLength - _chip_shift) % _codeLength) * _samplesPerCode / _codeLength;
|
2014-05-20 19:53:12 +00:00
|
|
|
|
|
|
|
if (_fs != _codeFreqBasis)
|
|
|
|
{
|
2019-11-29 23:31:07 +00:00
|
|
|
std::vector<std::complex<float>> _resampled_signal(_samplesPerCode);
|
|
|
|
resampler(_code, _resampled_signal, _codeFreqBasis, _fs); // resamples code to fs
|
2019-06-30 02:47:15 +00:00
|
|
|
_code = std::move(_resampled_signal);
|
2014-05-20 19:53:12 +00:00
|
|
|
}
|
2019-11-29 23:55:13 +00:00
|
|
|
|
2018-08-13 08:18:05 +00:00
|
|
|
for (uint32_t i = 0; i < _samplesPerCode; i++)
|
2014-05-20 19:53:12 +00:00
|
|
|
{
|
2019-11-29 23:31:07 +00:00
|
|
|
_dest[(i + delay) % _samplesPerCode] = _code[i];
|
2014-05-20 19:53:12 +00:00
|
|
|
}
|
|
|
|
}
|