diff --git a/src/algorithms/PVT/libs/signal_enabled_flags.cc b/src/algorithms/PVT/libs/signal_enabled_flags.cc
index 031eacf13..9f984c083 100644
--- a/src/algorithms/PVT/libs/signal_enabled_flags.cc
+++ b/src/algorithms/PVT/libs/signal_enabled_flags.cc
@@ -36,8 +36,8 @@ uint32_t flags_from_config(const ConfigurationInterface* configuration)
{GLO_2G, "Channels_2G.count"},
{BDS_B1, "Channels_B1.count"},
{BDS_B3, "Channels_B3.count"},
- {QZS_L1, "Channels_Q1.count"},
- {QZS_L5, "Channels_Q5.count"}
+ {QZS_J1, "Channels_J1.count"},
+ {QZS_J5, "Channels_J5.count"}
};
for (const auto& pair_aux : signal_flag_to_prop)
@@ -67,9 +67,11 @@ Signal_Enabled_Flags::Signal_Enabled_Flags(uint32_t flags_) : flags(flags_),
has_galileo(check_any_enabled(GAL_1B, GAL_E5a, GAL_E5b, GAL_E6)),
has_glonass(check_any_enabled(GLO_1G, GLO_2G)),
has_beidou(check_any_enabled(BDS_B1, BDS_B3)),
- only_gps(has_gps && !(has_galileo || has_glonass || has_beidou)),
- only_galileo(has_galileo && !(has_gps || has_glonass || has_beidou)),
- only_glonass(has_glonass && !(has_gps || has_galileo || has_beidou)),
- only_beidou(has_beidou && !(has_gps || has_galileo || has_glonass))
+ has_qzss(check_any_enabled(QZS_J1, QZS_J5)),
+ only_gps(has_gps && !(has_galileo || has_glonass || has_beidou || has_qzss)),
+ only_galileo(has_galileo && !(has_gps || has_glonass || has_beidou || has_qzss)),
+ only_glonass(has_glonass && !(has_gps || has_galileo || has_beidou || has_qzss)),
+ only_beidou(has_beidou && !(has_gps || has_galileo || has_glonass || has_qzss)),
+ only_qzss(has_qzss && !(has_gps || has_galileo || has_glonass || has_beidou))
{
}
diff --git a/src/algorithms/PVT/libs/signal_enabled_flags.h b/src/algorithms/PVT/libs/signal_enabled_flags.h
index 66dfd5a4c..5092eb620 100644
--- a/src/algorithms/PVT/libs/signal_enabled_flags.h
+++ b/src/algorithms/PVT/libs/signal_enabled_flags.h
@@ -34,8 +34,8 @@ enum signal_flag : uint32_t
GLO_2G = 0x1 << 8,
BDS_B1 = 0x1 << 9,
BDS_B3 = 0x1 << 10,
- QZS_L1 = 0x1 << 11,
- QZS_L5 = 0x1 << 12
+ QZS_J1 = 0x1 << 11,
+ QZS_J5 = 0x1 << 12
};
class Signal_Enabled_Flags
@@ -74,11 +74,13 @@ public:
const bool has_galileo;
const bool has_glonass;
const bool has_beidou;
+ const bool has_qzss;
const bool only_gps;
const bool only_galileo;
const bool only_glonass;
const bool only_beidou;
+ const bool only_qzss;
};
#endif // GNSS_SDR_SIGNAL_ENABLED_FLAGS_H
diff --git a/src/algorithms/acquisition/adapters/CMakeLists.txt b/src/algorithms/acquisition/adapters/CMakeLists.txt
index 003ed544a..ede6b2cae 100644
--- a/src/algorithms/acquisition/adapters/CMakeLists.txt
+++ b/src/algorithms/acquisition/adapters/CMakeLists.txt
@@ -28,6 +28,8 @@ set(ACQ_ADAPTER_SOURCES
glonass_l2_ca_pcps_acquisition.cc
beidou_b1i_pcps_acquisition.cc
beidou_b3i_pcps_acquisition.cc
+ qzss_l1_pcps_acquisition.cc
+ qzss_l5i_pcps_acquisition.cc
)
set(ACQ_ADAPTER_HEADERS
@@ -53,6 +55,8 @@ set(ACQ_ADAPTER_HEADERS
glonass_l2_ca_pcps_acquisition.h
beidou_b1i_pcps_acquisition.h
beidou_b3i_pcps_acquisition.h
+ qzss_l1_pcps_acquisition.h
+ qzss_l5i_pcps_acquisition.h
)
if(ENABLE_FPGA)
diff --git a/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.cc
new file mode 100644
index 000000000..14cfd04f2
--- /dev/null
+++ b/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.cc
@@ -0,0 +1,46 @@
+/*!
+ * \file qzss_l1_pcps_acquisition.cc
+ * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
+ * QZSS L1 signals
+ * \authors
+ * - Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+
+#include "qzss_l1_pcps_acquisition.h"
+#include "qzss.h"
+#include "qzss_signal_replica.h"
+
+
+QzssL1PcpsAcquisition::QzssL1PcpsAcquisition(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams)
+ : BasePcpsAcquisition(configuration,
+ role,
+ in_streams,
+ out_streams,
+ QZSS_L1_CHIP_RATE,
+ QZSS_L1_OPT_ACQ_FS_SPS,
+ QZSS_L1_CODE_LENGTH,
+ QZSS_L1_PERIOD_MS)
+{
+}
+
+
+void QzssL1PcpsAcquisition::code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq)
+{
+ qzss_l1_code_gen_complex_sampled(dest, prn, sampling_freq);
+}
\ No newline at end of file
diff --git a/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.h b/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.h
new file mode 100644
index 000000000..957ce47e3
--- /dev/null
+++ b/src/algorithms/acquisition/adapters/qzss_l1_pcps_acquisition.h
@@ -0,0 +1,62 @@
+/*!
+ * \file qzss_l1_pcps_acquisition.h
+ * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
+ * QZSS L1 signals
+ * \authors
+ * - Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#ifndef GNSS_SDR_QZSS_L1_PCPS_ACQUISITION_H
+#define GNSS_SDR_QZSS_L1_PCPS_ACQUISITION_H
+
+#include "base_pcps_acquisition.h"
+
+/** \addtogroup Acquisition
+ * \{ */
+/** \addtogroup Acq_adapters
+ * \{ */
+
+/*!
+ * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface
+ * for QZSS L1 signals
+ */
+class QzssL1PcpsAcquisition : public BasePcpsAcquisition
+{
+public:
+ QzssL1PcpsAcquisition(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams);
+
+ ~QzssL1PcpsAcquisition() = default;
+
+ /*!
+ * \brief Returns "QZSS_L1_PCPS_Acquisition"
+ */
+ inline std::string implementation() override
+ {
+ return "QZSS_L1_PCPS_Acquisition";
+ }
+
+private:
+ void code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq) override;
+};
+
+
+/** \} */
+/** \} */
+
+
+#endif // GNSS_SDR_QZSS_L1_PCPS_ACQUISITION_H
\ No newline at end of file
diff --git a/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.cc b/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.cc
new file mode 100644
index 000000000..6af23fe74
--- /dev/null
+++ b/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.cc
@@ -0,0 +1,46 @@
+/*!
+ * \file qzss_l5i_pcps_acquisition.cc
+ * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
+ * QZSS L5I signals
+ * \authors
+ * - Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+
+#include "qzss_l5i_pcps_acquisition.h"
+#include "qzss.h"
+#include "qzss_signal_replica.h"
+
+
+QzssL5iPcpsAcquisition::QzssL5iPcpsAcquisition(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams)
+ : BasePcpsAcquisition(configuration,
+ role,
+ in_streams,
+ out_streams,
+ QZSS_L5_CHIP_RATE,
+ QZSS_L5_OPT_ACQ_FS_SPS,
+ QZSS_L5_CODE_LENGTH,
+ QZSS_L5I_PERIOD_MS)
+{
+}
+
+
+void QzssL5iPcpsAcquisition::code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq)
+{
+ qzss_l5i_code_gen_complex_sampled(dest, prn, sampling_freq);
+}
\ No newline at end of file
diff --git a/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.h b/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.h
new file mode 100644
index 000000000..bdc033cd5
--- /dev/null
+++ b/src/algorithms/acquisition/adapters/qzss_l5i_pcps_acquisition.h
@@ -0,0 +1,62 @@
+/*!
+ * \file qzss_l5i_pcps_acquisition.h
+ * \brief Adapts a PCPS acquisition block to an AcquisitionInterface for
+ * QZSS L5I signals
+ * \authors
+ * - Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#ifndef GNSS_SDR_QZSS_L5I_PCPS_ACQUISITION_H
+#define GNSS_SDR_QZSS_L5I_PCPS_ACQUISITION_H
+
+#include "base_pcps_acquisition.h"
+
+/** \addtogroup Acquisition
+ * \{ */
+/** \addtogroup Acq_adapters
+ * \{ */
+
+/*!
+ * \brief This class adapts a PCPS acquisition block to an AcquisitionInterface
+ * for QZSS L5I signals
+ */
+class QzssL5iPcpsAcquisition : public BasePcpsAcquisition
+{
+public:
+ QzssL5iPcpsAcquisition(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams);
+
+ ~QzssL5iPcpsAcquisition() = default;
+
+ /*!
+ * \brief Returns "QZSS_L5I_PCPS_Acquisition"
+ */
+ inline std::string implementation() override
+ {
+ return "QZSS_L5I_PCPS_Acquisition";
+ }
+
+private:
+ void code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq) override;
+};
+
+
+/** \} */
+/** \} */
+
+
+#endif // GNSS_SDR_QZSS_L5I_PCPS_ACQUISITION_H
\ No newline at end of file
diff --git a/src/algorithms/libs/CMakeLists.txt b/src/algorithms/libs/CMakeLists.txt
index 898aa8194..dc564821a 100644
--- a/src/algorithms/libs/CMakeLists.txt
+++ b/src/algorithms/libs/CMakeLists.txt
@@ -32,6 +32,7 @@ set(GNSS_SPLIBS_SOURCES
pass_through.cc
short_x2_to_cshort.cc
gnss_sdr_string_literals.cc
+ qzss_signal_replica.cc
)
set(GNSS_SPLIBS_HEADERS
@@ -66,6 +67,7 @@ set(GNSS_SPLIBS_HEADERS
gnss_sdr_string_literals.h
gnss_time.h
matlab_writter_helper.h
+ qzss_signal_replica.h
)
set(GNSS_SPLIBS_HEADERS ${GNSS_SPLIBS_HEADERS}
diff --git a/src/algorithms/libs/qzss_signal_replica.cc b/src/algorithms/libs/qzss_signal_replica.cc
new file mode 100644
index 000000000..9317d3e8f
--- /dev/null
+++ b/src/algorithms/libs/qzss_signal_replica.cc
@@ -0,0 +1,352 @@
+/*!
+ * \file qzss_signal_replica.cc
+ * \brief This file implements signal generators for QZSS signals
+ * \author Carles Fernández-Prades, 2026. cfernandez (at) cttc.es
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "qzss_signal_replica.h"
+#include "qzss.h"
+#include
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#endif
+
+// -----------------------------
+// QZSS L1 C/A utils
+// -----------------------------
+
+struct QzssL1Entry
+{
+ uint16_t g2_delay_chips; // Provided by ICD, but not applied if using init_g2_octal
+ uint16_t init_g2_octal; // 10-bit value expressed in octal digits in ICD
+};
+
+
+// IS-QZSS-PNT-006 Table 3.2.2-1 (PRN 193..206)
+static QzssL1Entry qzss_l1_table(uint32_t prn)
+{
+ switch (prn)
+ {
+ case 193:
+ return {339, 01050};
+ case 194:
+ return {208, 01607};
+ case 195:
+ return {711, 01747};
+ case 196:
+ return {189, 01305};
+ case 197:
+ return {263, 00540};
+ case 198:
+ return {537, 01363}; // non-standard
+ case 199:
+ return {663, 00727};
+ case 200:
+ return {942, 00147};
+ case 201:
+ return {173, 01206};
+ case 202:
+ return {900, 01045}; // non-standard
+ case 203:
+ return {30, 00476}; // L1C/B
+ case 204:
+ return {500, 00604}; // L1C/B
+ case 205:
+ return {935, 01757}; // L1C/B
+ case 206:
+ return {556, 01330}; // L1C/B
+ default:
+ LOG(WARNING) << "Unsupported QZSS L1 PRN";
+ return {0, 0};
+ }
+}
+
+// -----------------------------
+// QZSS L5 utils
+// -----------------------------
+
+struct QzssL5Entry
+{
+ uint16_t init_i5;
+ uint16_t init_q5;
+ int advance_i5;
+ int advance_q5;
+};
+
+
+// IS-QZSS-PNT-006 Table 3.2.5-1
+static QzssL5Entry qzss_l5_table(uint32_t prn)
+{
+ switch (prn)
+ {
+ case 193:
+ return {0b0110000101110, 0b1001110000111, 5836, 4757};
+ case 194:
+ return {0b0110010011111, 0b0110100111010, 926, 427};
+ case 195:
+ return {0b1000111001100, 0b0110001100110, 6086, 5452};
+ case 196:
+ return {0b111101110001, 0b0000100001100, 950, 5182};
+ case 197:
+ return {0b0011111100001, 0b0101000101101, 5905, 6606};
+ case 198:
+ return {0b0000001110001, 0b1000001010111, 3240, 6531};
+ case 199:
+ return {0b1010110100100, 0b0011001110001, 6675, 4268};
+ case 200:
+ return {0b0100001110110, 0b0100011100110, 3197, 3115};
+ case 201:
+ return {0b0111110100011, 0b0100101100101, 1555, 6835};
+ case 202:
+ return {0b0001111001011, 0b1110001010111, 3589, 862};
+ default:
+ LOG(WARNING) << "Unsupported QZSS L5 PRN";
+ return {0, 0, 0, 0};
+ }
+}
+
+
+// -----------------------------------
+// QZSS L1 C/A code generation
+// -----------------------------------
+
+// Generates real QZSS L1 C/A code (1023 chips, +/-1)
+void qzss_l1_code_gen_float(own::span dest, uint32_t prn)
+{
+ if (dest.size() != QZSS_L1_CODE_LENGTH)
+ {
+ LOG(WARNING) << "QZSS L1 code must be 1023 chips";
+ return;
+ }
+
+ const auto entry = qzss_l1_table(prn);
+
+ std::array g1{};
+ std::array g2{};
+
+ g1.fill(1);
+ const uint16_t init = entry.init_g2_octal;
+ for (int s = 0; s < 10; ++s)
+ {
+ g2[s] = static_cast((init >> s) & 0x1);
+ }
+
+ // Generate 1023 chips
+ for (int i = 0; i < QZSS_L1_CODE_LENGTH; ++i)
+ {
+ const uint8_t g1_out = g1[9];
+ const uint8_t g2_out = g2[9];
+ const uint8_t prn_bit = static_cast(g1_out ^ g2_out);
+
+ // Map 0 -> -1, 1 -> +1
+ dest[i] = prn_bit ? 1.0F : -1.0F;
+
+ // Step G1
+ const uint8_t g1_fb = static_cast(g1[2] ^ g1[9]);
+ for (int k = 9; k > 0; --k)
+ {
+ g1[k] = g1[k - 1];
+ }
+ g1[0] = g1_fb;
+
+ // Step G2
+ const uint8_t g2_fb = static_cast(
+ g2[1] ^ g2[2] ^ g2[5] ^ g2[7] ^ g2[8] ^ g2[9]);
+ for (int k = 9; k > 0; --k)
+ {
+ g2[k] = g2[k - 1];
+ }
+ g2[0] = g2_fb;
+ }
+}
+
+
+void qzss_l1_code_gen_complex_sampled(
+ own::span> dest,
+ uint32_t prn,
+ int32_t sampling_freq)
+{
+ if (sampling_freq <= 0)
+ {
+ LOG(WARNING) << "Invalid sampling frequency";
+ return;
+ }
+
+ std::array code{};
+ qzss_l1_code_gen_float(own::span(code.data(), code.size()), prn);
+
+ const double phase_step = QZSS_L1_CHIP_RATE / static_cast(sampling_freq);
+ double code_phase = 0.0;
+
+ for (size_t i = 0; i < dest.size(); ++i)
+ {
+ int chip = static_cast(code_phase);
+ chip %= QZSS_L1_CODE_LENGTH;
+ dest[i] = {code[static_cast(chip)], 0.0F};
+
+ code_phase += phase_step;
+ if (code_phase >= QZSS_L1_CODE_LENGTH)
+ {
+ code_phase -= QZSS_L1_CODE_LENGTH;
+ }
+ }
+}
+
+
+// -----------------------------------
+// QZSS L5 (I&Q) code generation
+// -----------------------------------
+
+static uint8_t xa_step(uint16_t& state)
+{
+ const uint8_t out = static_cast(state & 0x1);
+ const uint8_t fb = static_cast(
+ ((state >> 4) ^ (state >> 3) ^ (state >> 1) ^ (state >> 0)) & 0x1);
+
+ uint16_t next = static_cast((state >> 1) | (static_cast(fb) << 12));
+
+ if (state == XA_SHORT_DECODE)
+ {
+ next = XA_ALL_ONES;
+ }
+
+ state = next;
+ return out;
+}
+
+
+static uint8_t xb_step(uint16_t& state)
+{
+ const uint8_t out = static_cast(state & 0x1);
+ const uint8_t fb = static_cast(
+ ((state >> 12) ^ (state >> 10) ^ (state >> 9) ^ (state >> 7) ^
+ (state >> 6) ^ (state >> 5) ^ (state >> 1) ^ (state >> 0)) &
+ 0x1);
+
+ state = static_cast((state >> 1) | (static_cast(fb) << 12));
+ return out;
+}
+
+
+void qzss_l5i_code_gen_float(own::span dest, uint32_t prn)
+{
+ if (dest.size() != QZSS_L5_CODE_LENGTH)
+ {
+ LOG(WARNING) << "L5I code must be 10230 chips";
+ return;
+ }
+
+ const auto entry = qzss_l5_table(prn);
+ uint16_t xa_state = XA_ALL_ONES;
+ uint16_t xb_state = entry.init_i5;
+
+ for (int i = 0; i < QZSS_L5_CODE_LENGTH; ++i)
+ {
+ const uint8_t xa = xa_step(xa_state);
+ const uint8_t xb = xb_step(xb_state);
+ const uint8_t bit = static_cast(xa ^ xb);
+
+ dest[i] = bit ? 1.0F : -1.0F;
+ }
+}
+
+
+void qzss_l5q_code_gen_float(own::span dest, uint32_t prn)
+{
+ if (dest.size() != QZSS_L5_CODE_LENGTH)
+ {
+ LOG(WARNING) << "L5Q code must be 10230 chips";
+ return;
+ }
+
+ const auto entry = qzss_l5_table(prn);
+ uint16_t xa_state = XA_ALL_ONES;
+ uint16_t xb_state = entry.init_q5;
+
+ for (int i = 0; i < QZSS_L5_CODE_LENGTH; ++i)
+ {
+ const uint8_t xa = xa_step(xa_state);
+ const uint8_t xb = xb_step(xb_state);
+ const uint8_t bit = static_cast(xa ^ xb);
+
+ dest[i] = bit ? 1.0F : -1.0F;
+ }
+}
+
+
+void qzss_l5i_code_gen_complex_sampled(
+ own::span> dest,
+ uint32_t prn,
+ int32_t sampling_freq)
+{
+ if (sampling_freq <= 0)
+ {
+ LOG(WARNING) << "Invalid sampling frequency";
+ return;
+ }
+
+ std::array code{};
+ qzss_l5i_code_gen_float(own::span(code.data(), code.size()), prn);
+
+ const double phase_step = QZSS_L5_CHIP_RATE / static_cast(sampling_freq);
+ double code_phase = 0.0;
+
+ for (size_t i = 0; i < dest.size(); ++i)
+ {
+ int chip = static_cast(code_phase);
+ chip %= QZSS_L5_CODE_LENGTH;
+
+ dest[i] = {code[static_cast(chip)], 0.0F};
+
+ code_phase += phase_step;
+ if (code_phase >= QZSS_L5_CODE_LENGTH)
+ {
+ code_phase -= QZSS_L5_CODE_LENGTH;
+ }
+ }
+}
+
+
+void qzss_l5q_code_gen_complex_sampled(
+ own::span> dest,
+ uint32_t prn,
+ int32_t sampling_freq)
+{
+ if (sampling_freq <= 0)
+ {
+ LOG(WARNING) << "Invalid sampling frequency";
+ return;
+ }
+
+ std::array code{};
+ qzss_l5q_code_gen_float(own::span(code.data(), code.size()), prn);
+
+ const double phase_step = QZSS_L5_CHIP_RATE / static_cast(sampling_freq);
+ double code_phase = 0.0;
+
+ for (size_t i = 0; i < dest.size(); ++i)
+ {
+ int chip = static_cast(code_phase);
+ chip %= QZSS_L5_CODE_LENGTH;
+
+ dest[i] = {0.0F, code[static_cast(chip)]};
+
+ code_phase += phase_step;
+ if (code_phase >= QZSS_L5_CODE_LENGTH)
+ {
+ code_phase -= QZSS_L5_CODE_LENGTH;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/algorithms/libs/qzss_signal_replica.h b/src/algorithms/libs/qzss_signal_replica.h
new file mode 100644
index 000000000..c0f511a3f
--- /dev/null
+++ b/src/algorithms/libs/qzss_signal_replica.h
@@ -0,0 +1,55 @@
+/*!
+ * \file qzss_signal_replica.h
+ * \brief This file implements signal generators for QZSS signals
+ * \author Carles Fernández-Prades, 2026. cfernandez (at) cttc.es
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#ifndef GNSS_SDR_QZSS_SIGNAL_REPLICA_H
+#define GNSS_SDR_QZSS_SIGNAL_REPLICA_H
+
+#include
+#include
+#if HAS_STD_SPAN
+#include
+namespace own = std;
+#else
+#include
+namespace own = gsl_lite;
+#endif
+
+/** \addtogroup Algorithms_Library
+ * \{ */
+/** \addtogroup Algorithm_libs algorithms_libs
+ * \{ */
+
+//! Generates complex QZSS L1 C/A code for the desired SV ID, and sampled to specific sampling frequency
+void qzss_l1_code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq);
+
+//! Generates real QZSS L1 C/A code for the desired SV ID
+void qzss_l1_code_gen_float(own::span dest, uint32_t prn);
+
+//! Generates complex QZSS L5I code for the desired SV ID, and sampled to specific sampling frequency
+void qzss_l5i_code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq);
+
+//! Generates real QZSS L5I code for the desired SV ID
+void qzss_l5i_code_gen_float(own::span dest, uint32_t prn);
+
+//! Generates complex QZSS L5Q code for the desired SV ID, and sampled to specific sampling frequency
+void qzss_l5q_code_gen_complex_sampled(own::span> dest, uint32_t prn, int32_t sampling_freq);
+
+//! Generates real QZSS L5I code for the desired SV ID
+void qzss_l5q_code_gen_float(own::span dest, uint32_t prn);
+
+/** \} */
+/** \} */
+#endif // GNSS_SDR_QZSS_SIGNAL_REPLICA_H
\ No newline at end of file
diff --git a/src/algorithms/tracking/adapters/CMakeLists.txt b/src/algorithms/tracking/adapters/CMakeLists.txt
index 1bc8ab106..4806fdbd1 100644
--- a/src/algorithms/tracking/adapters/CMakeLists.txt
+++ b/src/algorithms/tracking/adapters/CMakeLists.txt
@@ -53,6 +53,8 @@ set(TRACKING_ADAPTER_SOURCES
gps_l1_ca_tcp_connector_tracking.cc
gps_l1_ca_gaussian_tracking.cc
gps_l1_ca_kf_tracking.cc
+ qzss_l1_dll_pll_tracking.cc
+ qzss_l5_dll_pll_tracking.cc
${OPT_TRACKING_ADAPTERS_SOURCES}
)
@@ -73,6 +75,8 @@ set(TRACKING_ADAPTER_HEADERS
gps_l1_ca_tcp_connector_tracking.h
gps_l1_ca_gaussian_tracking.h
gps_l1_ca_kf_tracking.h
+ qzss_l1_dll_pll_tracking.h
+ qzss_l5_dll_pll_tracking.h
${OPT_TRACKING_ADAPTERS_HEADERS}
)
diff --git a/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.cc
new file mode 100644
index 000000000..ff33768ab
--- /dev/null
+++ b/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.cc
@@ -0,0 +1,115 @@
+/*!
+ * \file qzss_l1_dll_pll_tracking.cc
+ * \brief Interface of an adapter of a DLL+PLL tracking loop block
+ * for QZSS L1 signals to a TrackingInterface
+ * \author Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ * Code DLL + carrier PLL according to the algorithms described in:
+ * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
+ * A Software-Defined GPS and Galileo Receiver. A Single-Frequency
+ * Approach, Birkhauser, 2007
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "qzss_l1_dll_pll_tracking.h"
+#include "configuration_interface.h"
+#include "display.h"
+#include "qzss.h"
+#include
+#include
+#include
+#include
+
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#endif
+
+QzssL1DllPllTracking::QzssL1DllPllTracking(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams)
+ : BaseDllPllTracking(configuration, role, in_streams, out_streams)
+{
+ configure_tracking_parameters(configuration);
+ create_tracking_block();
+}
+
+
+void QzssL1DllPllTracking::configure_tracking_parameters(
+ const ConfigurationInterface* configuration __attribute__((unused)))
+{
+ // Set basic signal identifiers
+ config_params().system = 'Q';
+ const std::array sig{'J', '1', '\0'};
+ std::copy_n(sig.data(), 3, config_params().signal);
+
+ const auto vector_length = static_cast(std::round(config_params().fs_in / (QZSS_L1_CHIP_RATE / QZSS_L1_CODE_LENGTH)));
+ config_params().vector_length = vector_length;
+
+ // Sanity checks and warnings
+ if (config_params().extend_correlation_symbols < 1)
+ {
+ config_params().extend_correlation_symbols = 1;
+ std::cout << TEXT_RED
+ << "WARNING: QZSS L1 C/A: extend_correlation_symbols must be > 0. "
+ << "Coherent integration set to 1 ms."
+ << TEXT_RESET << std::endl;
+ }
+ else if (config_params().extend_correlation_symbols > 20)
+ {
+ config_params().extend_correlation_symbols = 20;
+ std::cout << TEXT_RED
+ << "WARNING: QZSS L1 C/A: extend_correlation_symbols limited to 20 (20 ms)."
+ << TEXT_RESET << std::endl;
+ }
+
+ // QZSS L1 C/A does not have a pilot component
+ config_params().track_pilot = configuration->property(this->role() + ".track_pilot", false);
+ if (config_params().track_pilot)
+ {
+ config_params().track_pilot = false;
+ std::cout << TEXT_RED
+ << "WARNING: QZSS L1 C/A does not have pilot signal. "
+ << "Data tracking enabled instead."
+ << TEXT_RESET << std::endl;
+ }
+
+ // Ensure bandwidth sanity when narrow-band is enabled
+ if ((config_params().extend_correlation_symbols > 1) &&
+ (config_params().pll_bw_narrow_hz > config_params().pll_bw_hz ||
+ config_params().dll_bw_narrow_hz > config_params().dll_bw_hz))
+ {
+ std::cout << TEXT_RED
+ << "WARNING: QZSS L1 C/A: Narrow tracking bandwidth is higher than wide bandwidth."
+ << TEXT_RESET << std::endl;
+ }
+}
+
+
+void QzssL1DllPllTracking::create_tracking_block()
+{
+ // Create GNU Radio block
+ if (config_params().item_type == "gr_complex")
+ {
+ tracking_sptr_ = dll_pll_veml_make_tracking(config_params());
+ DLOG(INFO) << "Tracking block (" << tracking_sptr_->unique_id() << ")";
+ }
+ else
+ {
+ set_item_size(0);
+ tracking_sptr_ = nullptr;
+ LOG(WARNING) << config_params().item_type << " unknown tracking item type.";
+ }
+}
diff --git a/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.h b/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.h
new file mode 100644
index 000000000..6f3106f43
--- /dev/null
+++ b/src/algorithms/tracking/adapters/qzss_l1_dll_pll_tracking.h
@@ -0,0 +1,62 @@
+/*!
+ * \file qzss_l1_dll_pll_tracking.h
+ * \brief Interface of an adapter of a DLL+PLL tracking loop block
+ * for QZSS L1 signals to a TrackingInterface
+ * \author Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ * Code DLL + carrier PLL according to the algorithms described in:
+ * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
+ * A Software-Defined GPS and Galileo Receiver. A Single-Frequency
+ * Approach, Birkhauser, 2007
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#ifndef GNSS_SDR_QZSS_L1_DLL_PLL_TRACKING_H
+#define GNSS_SDR_QZSS_L1_DLL_PLL_TRACKING_H
+
+#include "base_dll_pll_tracking.h"
+
+/** \addtogroup Tracking
+ * Classes for GNSS signal tracking.
+ * \{ */
+/** \addtogroup Tracking_adapters tracking_adapters
+ * Wrap GNU Radio blocks for GNSS signal tracking with a TrackingInterface
+ * \{ */
+
+
+/*!
+ * \brief This class implements a code DLL + carrier PLL tracking loop
+ * block adapter for QZSS L1 signals
+ */
+class QzssL1DllPllTracking : public BaseDllPllTracking
+{
+public:
+ //! Constructor
+ QzssL1DllPllTracking(const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams);
+
+ //! Returns "QZSS_L1_CA_DLL_PLL_Tracking"
+ inline std::string implementation() override
+ {
+ return "QZSS_L1_CA_DLL_PLL_Tracking";
+ }
+
+private:
+ void configure_tracking_parameters(const ConfigurationInterface* configuration) override;
+ void create_tracking_block() override;
+};
+
+/** \} */
+/** \} */
+#endif // GNSS_SDR_QZSS_L1_CA_DLL_PLL_TRACKING_H
diff --git a/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.cc b/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.cc
new file mode 100644
index 000000000..fe96a71b7
--- /dev/null
+++ b/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.cc
@@ -0,0 +1,87 @@
+/*!
+ * \file qzss_l5_dll_pll_tracking.cc
+ * \brief Interface of an adapter of a DLL+PLL tracking loop block
+ * for QZSS L5 signals to a TrackingInterface
+ * \author Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ * Code DLL + carrier PLL according to the algorithms described in:
+ * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
+ * A Software-Defined GPS and Galileo Receiver. A Single-Frequency
+ * Approach, Birkhauser, 2007
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "qzss_l5_dll_pll_tracking.h"
+#include "qzss.h"
+#include "configuration_interface.h"
+#include "display.h"
+#include
+#include
+
+#if USE_GLOG_AND_GFLAGS
+#include
+#else
+#include
+#endif
+
+QzssL5DllPllTracking::QzssL5DllPllTracking(
+ const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams)
+ : BaseDllPllTracking(configuration, role, in_streams, out_streams)
+{
+ configure_tracking_parameters(configuration);
+ create_tracking_block();
+}
+
+
+void QzssL5DllPllTracking::configure_tracking_parameters(
+ const ConfigurationInterface* configuration __attribute__((unused)))
+{
+ const auto vector_length = static_cast(std::round(static_cast(config_params().fs_in) / (static_cast(QZSS_L5_CHIP_RATE) / static_cast(QZSS_L5_CODE_LENGTH))));
+ config_params().vector_length = vector_length;
+ if (config_params().extend_correlation_symbols < 1)
+ {
+ config_params().extend_correlation_symbols = 1;
+ std::cout << TEXT_RED << "WARNING: QZSS L5. extend_correlation_symbols must be bigger than 0. Coherent integration has been set to 1 symbol (1 ms)" << TEXT_RESET << '\n';
+ }
+ else if (!config_params().track_pilot and config_params().extend_correlation_symbols > QZSS_L5I_NH_CODE_LENGTH)
+ {
+ config_params().extend_correlation_symbols = QZSS_L5I_NH_CODE_LENGTH;
+ std::cout << TEXT_RED << "WARNING: QZSS L5. extend_correlation_symbols must be lower than 11 when tracking the data component. Coherent integration has been set to 10 symbols (10 ms)" << TEXT_RESET << '\n';
+ }
+ if ((config_params().extend_correlation_symbols > 1) and (config_params().pll_bw_narrow_hz > config_params().pll_bw_hz or config_params().dll_bw_narrow_hz > config_params().dll_bw_hz))
+ {
+ std::cout << TEXT_RED << "WARNING: QZSS L5. PLL or DLL narrow tracking bandwidth is higher than wide tracking one" << TEXT_RESET << '\n';
+ }
+ config_params().system = 'Q';
+ const std::array sig{'J', '5', '\0'};
+ std::copy_n(sig.data(), 3, config_params().signal);
+}
+
+
+void QzssL5DllPllTracking::create_tracking_block()
+{
+ // ################# Make a GNU Radio Tracking block object ################
+ if (config_params().item_type == "gr_complex")
+ {
+ tracking_sptr_ = dll_pll_veml_make_tracking(config_params());
+ DLOG(INFO) << "tracking(" << tracking_sptr_->unique_id() << ")";
+ }
+ else
+ {
+ set_item_size(0);
+ tracking_sptr_ = nullptr;
+ LOG(WARNING) << config_params().item_type << " unknown tracking item type.";
+ }
+}
diff --git a/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.h b/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.h
new file mode 100644
index 000000000..4e56791e4
--- /dev/null
+++ b/src/algorithms/tracking/adapters/qzss_l5_dll_pll_tracking.h
@@ -0,0 +1,62 @@
+/*!
+ * \file qzss_l5_dll_pll_tracking.h
+ * \brief Interface of an adapter of a DLL+PLL tracking loop block
+ * for QZSS L5 signals to a TrackingInterface
+ * \author Carles Fernandez, 2026. cfernandez(at)cttc.es
+ *
+ * Code DLL + carrier PLL according to the algorithms described in:
+ * K.Borre, D.M.Akos, N.Bertelsen, P.Rinder, and S.H.Jensen,
+ * A Software-Defined GPS and Galileo Receiver. A Single-Frequency
+ * Approach, Birkhauser, 2007
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#ifndef GNSS_SDR_QZSS_L5_DLL_PLL_TRACKING_H
+#define GNSS_SDR_QZSS_L5_DLL_PLL_TRACKING_H
+
+#include "base_dll_pll_tracking.h"
+
+/** \addtogroup Tracking
+ * Classes for GNSS signal tracking.
+ * \{ */
+/** \addtogroup Tracking_adapters tracking_adapters
+ * Wrap GNU Radio blocks for GNSS signal tracking with a TrackingInterface
+ * \{ */
+
+
+/*!
+ * \brief This class implements a code DLL + carrier PLL tracking loop
+ * block adapter for QZSS L5 signals
+ */
+class QzssL5DllPllTracking : public BaseDllPllTracking
+{
+public:
+ //! Constructor
+ QzssL5DllPllTracking(const ConfigurationInterface* configuration,
+ const std::string& role,
+ unsigned int in_streams,
+ unsigned int out_streams);
+
+ //! Returns "QZSS_L5_DLL_PLL_Tracking"
+ inline std::string implementation() override
+ {
+ return "QZSS_L5_DLL_PLL_Tracking";
+ }
+
+private:
+ void configure_tracking_parameters(const ConfigurationInterface* configuration) override;
+ void create_tracking_block() override;
+};
+
+/** \} */
+/** \} */
+#endif // GNSS_SDR_QZSS_L5_DLL_PLL_TRACKING_H
diff --git a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc
index 5e7fe327f..375ceaf9b 100644
--- a/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc
+++ b/src/algorithms/tracking/gnuradio_blocks/dll_pll_veml_tracking.cc
@@ -49,6 +49,8 @@
#include "gps_sdr_signal_replica.h"
#include "lock_detectors.h"
#include "matlab_writter_helper.h"
+#include "qzss.h"
+#include "qzss_signal_replica.h"
#include "tracking_discriminators.h"
#include // for io_signature
#include // for scoped_lock
@@ -179,6 +181,8 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_)
map_signal_pretty_name["B1"] = "B1I";
map_signal_pretty_name["B3"] = "B3I";
map_signal_pretty_name["E6"] = "E6";
+ map_signal_pretty_name["J1"] = "L1 C/A";
+ map_signal_pretty_name["J5"] = "L5";
d_signal_pretty_name = map_signal_pretty_name[d_signal_type];
@@ -509,6 +513,77 @@ dll_pll_veml_tracking::dll_pll_veml_tracking(const Dll_Pll_Conf &conf_)
d_symbols_per_bit = 0;
}
}
+ else if (d_trk_parameters.system == 'Q')
+ {
+ d_systemName = "QZSS";
+ if (d_signal_type == "J1")
+ {
+ d_signal_carrier_freq = QZSS_L1_FREQ_HZ;
+ d_code_period = QZSS_L1_CA_CODE_PERIOD_S;
+ d_code_chip_rate = QZSS_L1_CHIP_RATE;
+ d_correlation_length_ms = 1;
+ d_code_samples_per_chip = 1;
+ d_code_length_chips = static_cast(QZSS_L1_CODE_LENGTH);
+ // QZSS L1 C/A does not have pilot component nor secondary code
+ d_secondary = false;
+ d_trk_parameters.track_pilot = false;
+ d_trk_parameters.slope = 1.0;
+ d_trk_parameters.spc = d_trk_parameters.early_late_space_chips;
+ d_trk_parameters.y_intercept = 1.0;
+ // symbol integration: 20 trk symbols (20 ms) = 1 tlm bit
+ // set the bit transition pattern in secondary code to obtain bit synchronization
+ d_secondary_code_length = static_cast(QZSS_CA_PREAMBLE_LENGTH_SYMBOLS);
+ d_secondary_code_string = QZSS_CA_PREAMBLE_SYMBOLS_STR;
+ d_symbols_per_bit = QZSS_CA_TELEMETRY_SYMBOLS_PER_BIT;
+ }
+ else if (d_signal_type == "J5")
+ {
+ d_signal_carrier_freq = QZSS_L5_FREQ_HZ;
+ d_code_period = QZSS_L5I_CODE_PERIOD_S;
+ d_code_chip_rate = QZSS_L5_CHIP_RATE;
+ // symbol integration: 10 trk symbols (10 ms) = 1 tlm bit
+ d_symbols_per_bit = QZSS_L5_SAMPLES_PER_SYMBOL;
+ d_correlation_length_ms = 1;
+ d_code_samples_per_chip = 1;
+ d_code_length_chips = static_cast(QZSS_L5_CODE_LENGTH);
+ d_secondary = true;
+ d_trk_parameters.slope = 1.0;
+ d_trk_parameters.spc = d_trk_parameters.early_late_space_chips;
+ d_trk_parameters.y_intercept = 1.0;
+ if (d_trk_parameters.track_pilot)
+ {
+ // synchronize pilot secondary code
+ d_secondary_code_length = static_cast(QZSS_L5Q_NH_CODE_LENGTH);
+ d_secondary_code_string = QZSS_L5Q_NH_CODE_STR;
+ // remove data secondary code
+ // remove Neuman-Hofman Code
+ d_data_secondary_code_length = static_cast(QZSS_L5I_NH_CODE_LENGTH);
+ d_data_secondary_code_string = QZSS_L5I_NH_CODE_STR;
+ d_signal_pretty_name = d_signal_pretty_name + "Q";
+ }
+ else
+ {
+ // synchronize and remove data secondary code
+ // remove Neuman-Hofman Code
+ d_secondary_code_length = static_cast(QZSS_L5I_NH_CODE_LENGTH);
+ d_secondary_code_string = QZSS_L5I_NH_CODE_STR;
+ d_signal_pretty_name = d_signal_pretty_name + "I";
+ d_interchange_iq = true;
+ }
+ }
+ else
+ {
+ LOG(WARNING) << "Invalid Signal argument when instantiating tracking blocks";
+ std::cerr << "Invalid Signal argument when instantiating tracking blocks\n";
+ d_correlation_length_ms = 1;
+ d_secondary = false;
+ d_signal_carrier_freq = 0.0;
+ d_code_period = 0.0;
+ d_code_length_chips = 0;
+ d_code_samples_per_chip = 0U;
+ d_symbols_per_bit = 0;
+ }
+ }
else
{
LOG(WARNING) << "Invalid System argument when instantiating tracking blocks";
@@ -933,6 +1008,25 @@ void dll_pll_veml_tracking::start_tracking()
d_extend_correlation_symbols = GLONASS_GNAV_TELEMETRY_SYMBOLS_PER_BIT;
}
}
+ else if (d_systemName == "QZSS" && d_signal_type == "J1")
+ {
+ qzss_l1_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN);
+ }
+ else if (d_systemName == "QZSS" && d_signal_type == "J5")
+ {
+ if (d_trk_parameters.track_pilot)
+ {
+ qzss_l5q_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN);
+ qzss_l5i_code_gen_float(d_data_code, d_acquisition_gnss_synchro->PRN);
+ d_Prompt_Data[0] = gr_complex(0.0, 0.0);
+ d_correlator_data_cpu.set_local_code_and_taps(d_code_length_chips, d_data_code.data(), d_prompt_data_shift);
+ }
+ else
+ {
+ qzss_l5i_code_gen_float(d_tracking_code, d_acquisition_gnss_synchro->PRN);
+ }
+ }
+
d_multicorrelator_cpu.set_local_code_and_taps(d_code_samples_per_chip * d_code_length_chips, d_tracking_code.data(), d_local_code_shift_chips.data());
std::fill_n(d_correlator_outs.begin(), d_n_correlator_taps, gr_complex(0.0, 0.0));
diff --git a/src/core/system_parameters/CMakeLists.txt b/src/core/system_parameters/CMakeLists.txt
index 252295207..cc757901b 100644
--- a/src/core/system_parameters/CMakeLists.txt
+++ b/src/core/system_parameters/CMakeLists.txt
@@ -97,6 +97,7 @@ set(SYSTEM_PARAMETERS_HEADERS
osnma_data.h
osnma_dsm_reader.h
tow_to_trk.h
+ qzss.h
)
list(SORT SYSTEM_PARAMETERS_HEADERS)
diff --git a/src/core/system_parameters/gnss_frequencies.h b/src/core/system_parameters/gnss_frequencies.h
index 3099bae68..67664bdd5 100644
--- a/src/core/system_parameters/gnss_frequencies.h
+++ b/src/core/system_parameters/gnss_frequencies.h
@@ -57,6 +57,8 @@ const std::unordered_map SIGNAL_FREQ_MAP = {
{"B1", FREQ1_BDS},
{"B2", FREQ2_BDS},
{"B3", FREQ3_BDS},
+ {"J1", FREQ1},
+ {"J5", FREQ5},
};
diff --git a/src/core/system_parameters/qzss.h b/src/core/system_parameters/qzss.h
new file mode 100644
index 000000000..adb376f67
--- /dev/null
+++ b/src/core/system_parameters/qzss.h
@@ -0,0 +1,58 @@
+/*!
+ * \file qzss.h
+ * \brief Defines system parameters for QZSS signals
+ * \author Carles Fernández-Prades, 2026. cfernandez (at) cttc.es
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+
+#ifndef GNSS_SDR_QZSS_H
+#define GNSS_SDR_QZSS_H
+
+#include "gnss_frequencies.h"
+#include
+
+/** \addtogroup Core
+ * \{ */
+/** \addtogroup System_Parameters
+ * \{ */
+
+static constexpr double QZSS_L1_FREQ_HZ = FREQ1;
+static constexpr double QZSS_L5_FREQ_HZ = FREQ5;
+static constexpr double QZSS_L1_CHIP_RATE = 1.023e6;
+static constexpr double QZSS_L5_CHIP_RATE = 10.23e6;
+static constexpr double QZSS_L1_CA_CODE_PERIOD_S = 0.001;
+static constexpr double QZSS_L5I_CODE_PERIOD_S = 0.001;
+
+static constexpr int QZSS_L1_CODE_LENGTH = 1023;
+static constexpr int QZSS_L5_CODE_LENGTH = 10230;
+static constexpr int QZSS_L1_PERIOD_MS = 1;
+static constexpr int QZSS_L5I_PERIOD_MS = 1;
+static constexpr int32_t QZSS_CA_PREAMBLE_LENGTH_SYMBOLS = 160;
+static constexpr int32_t QZSS_CA_TELEMETRY_SYMBOLS_PER_BIT = 20;
+static constexpr int32_t QZSS_L5_SAMPLES_PER_SYMBOL = 10;
+static constexpr int32_t QZSS_L5Q_NH_CODE_LENGTH = 20;
+static constexpr int32_t QZSS_L5I_NH_CODE_LENGTH = 10;
+static constexpr uint32_t QZSS_L1_OPT_ACQ_FS_SPS = 2000000;
+static constexpr uint32_t QZSS_L5_OPT_ACQ_FS_SPS = 10000000;
+
+static constexpr uint16_t XA_ALL_ONES = 0x1FFF; // 13 bits all ones
+static constexpr uint16_t XA_SHORT_DECODE = 0x1FFD; // 1111111111101 (ICD)
+
+constexpr const char QZSS_CA_PREAMBLE_SYMBOLS_STR[161] = "1111111111111111111100000000000000000000000000000000000000000000000000000000000011111111111111111111000000000000000000001111111111111111111111111111111111111111";
+constexpr const char QZSS_L5Q_NH_CODE_STR[21] = "00000100110101001110";
+constexpr const char QZSS_L5I_NH_CODE_STR[11] = "0000110101";
+
+/** \} */
+/** \} */
+
+#endif // GNSS_SDR_QZSS_H
diff --git a/tests/test_main.cc b/tests/test_main.cc
index 399bb6762..c0462f7fa 100644
--- a/tests/test_main.cc
+++ b/tests/test_main.cc
@@ -137,6 +137,7 @@ private:
#include "unit-tests/system-parameters/glonass_gnav_ephemeris_test.cc"
#include "unit-tests/system-parameters/glonass_gnav_nav_message_test.cc"
#include "unit-tests/system-parameters/has_decoding_test.cc"
+#include "unit-tests/system-parameters/qzss_code_generation_test.cc"
#ifndef EXCLUDE_TESTS_REQUIRING_BINARIES
#include "unit-tests/control-plane/control_thread_test.cc"
diff --git a/tests/unit-tests/system-parameters/qzss_code_generation_test.cc b/tests/unit-tests/system-parameters/qzss_code_generation_test.cc
new file mode 100644
index 000000000..7e5e79492
--- /dev/null
+++ b/tests/unit-tests/system-parameters/qzss_code_generation_test.cc
@@ -0,0 +1,88 @@
+/*!
+ * \file qzss_code_generation_test.cc
+ * \brief This file implements unit tests for the QZSS code generation
+ * \author Carles Fernández-Prades, 2026. cfernandez (at)) cttc.es
+ *
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * GNSS-SDR is a Global Navigation Satellite System software-defined receiver.
+ * This file is part of GNSS-SDR.
+ *
+ * Copyright (C) 2010-2026 (see AUTHORS file for a list of contributors)
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * -----------------------------------------------------------------------------
+ */
+
+#include "qzss_signal_replica.h"
+#include
+#include
+
+
+TEST(QzssL1Code, Periodicity)
+{
+ constexpr uint32_t prn = 193;
+ std::vector code1(1023);
+ std::vector code2(1023);
+
+ qzss_l1_code_gen_float(code1, prn);
+ qzss_l1_code_gen_float(code2, prn);
+
+ EXPECT_EQ(code1, code2);
+}
+
+
+TEST(QzssL1Code, GoldenFirst32Chips)
+{
+ constexpr uint32_t prn = 193;
+ std::vector code(1023);
+ qzss_l1_code_gen_float(code, prn);
+
+ const float golden[32] = {
+ -1, 1, 1, 1, -1, 1, -1, 1,
+ 1, 1, -1, -1, -1, -1, 1, 1,
+ -1, -1, -1, -1, -1, -1, 1, -1,
+ 1, -1, -1, -1, -1, -1, -1, 1};
+
+ for (int i = 0; i < 32; ++i)
+ {
+ EXPECT_FLOAT_EQ(code[i], golden[i]);
+ }
+}
+
+
+TEST(QzssL5Code, L5IGoldenFirst32Chips)
+{
+ std::vector code(10230);
+ qzss_l5i_code_gen_float(code, 193);
+
+ const float golden[32] = {
+ 1, -1, -1, -1, 1, -1, 1, 1,
+ 1, 1, -1, -1, 1, 1, 1, -1,
+ 1, -1, -1, 1, -1, -1, 1, -1,
+ -1, 1, 1, 1, -1, -1, -1, 1};
+
+ for (int i = 0; i < 32; ++i)
+ {
+ EXPECT_FLOAT_EQ(code[i], golden[i]);
+ }
+}
+
+
+TEST(QzssL5Code, L5QGoldenFirst32Chips)
+{
+ std::vector code(10230);
+ qzss_l5q_code_gen_float(code, 193);
+
+ const float golden[32] = {
+ -1, -1, -1, 1, 1, 1, 1, -1,
+ -1, -1, 1, 1, -1, 1, 1, -1,
+ -1, 1, 1, -1, -1, -1, -1, -1,
+ 1, 1, -1, -1, -1, -1, -1, 1};
+
+ for (int i = 0; i < 32; ++i)
+ {
+ EXPECT_FLOAT_EQ(code[i], golden[i]);
+ }
+}
\ No newline at end of file