1
0
mirror of https://github.com/gnss-sdr/gnss-sdr synced 2026-03-02 05:49:45 +00:00

Improve documentation

This commit is contained in:
Carles Fernandez
2026-01-21 19:21:02 +01:00
parent f6c90ba436
commit 99e2ea0509

View File

@@ -22,24 +22,114 @@
#include <cstdint>
#include <vector>
/** \addtogroup Tracking
* \{ */
/** \addtogroup Tracking_libs
* \{ */
/**
* @brief Histogram-based navigation data bit synchronizer.
*/
class HistogramBitSynchronizer
{
public:
/**
* @brief Configuration parameters for HistogramBitSynchronizer.
*
* These parameters define the bit period, the update cadence, the lock criteria,
* and the transition detection method.
*/
struct Config
{
int bit_period_ms; // e.g., 20 for GPS L1 C/A
int epoch_ms; // e.g., 1
int min_events_for_lock; // e.g., 30
double dominance_ratio; // e.g., 0.55
int stable_best_required; // e.g., 5
float min_prompt_mag; // gate: ignore |P| below this
bool use_phase_dot_detector; // true: dot(Pk,Pk-1) sign; false: sign(Re(P))
/**
* @brief Navigation data bit period in milliseconds.
*
* This is the nominal duration of one navigation data bit.
*/
int bit_period_ms;
/**
* @brief Time interval between successive calls to update(), in milliseconds.
*
* This should match the minimum integration interval (epoch) produced by the
* tracking loop and used to generate the provided prompt correlator output.
*/
int epoch_ms;
/**
* @brief Minimum number of detected transition events required before lock evaluation.
*
* The histogram is built from detected candidate transitions. Lock decisions are
* not attempted until at least this many events have been accumulated.
*
* Trade-offs:
* - Larger values increase robustness against false locks but increase time-to-lock.
* - Smaller values reduce time-to-lock but increase sensitivity to noise/spurious transitions.
*/
int min_events_for_lock;
/**
* @brief Required dominance ratio of the winning histogram bin.
*
* Lock requires the most frequent histogram bin to be sufficiently dominant:
* @f[
* \text{dominance\_ratio} = \frac{\text{best\_bin\_count}}{\text{total\_detected\_events}}
* @f]
*
* Guidance:
* - Values near 0.5 may lock faster but increase false-lock probability.
* - Values closer to 1.0 are conservative and require a clearly dominant phase.
*/
double dominance_ratio;
/**
* @brief Required stability of the dominant histogram bin (consecutive evaluations).
*
* Even if the dominance ratio is met, the algorithm requires that the same histogram
* bin remains dominant for this many consecutive lock evaluations before declaring lock.
*
* This helps prevent locking on transient peaks caused by noise or short-lived disturbances.
*/
int stable_best_required;
/**
* @brief Minimum magnitude of the prompt correlator output.
*
* Candidate transition detection is suppressed when @f$|P| < \text{min\_prompt\_mag}@f$,
* where @f$P@f$ is the prompt correlator output.
*
* Use this to avoid counting unreliable transitions when tracking quality is poor or
* the prompt output is dominated by noise.
*/
float min_prompt_mag;
/**
* @brief Select the transition detection method.
*
* If true (recommended), uses a “phase-dot” detector:
* - A candidate transition is detected when:
* @f[
* \Re\{ P_k \cdot P^*_{k-1} \} < 0
* @f]
* where @f$P_k@f$ is the current prompt and @f$P^*_{k-1}@f$ the conjugate of the previous.
*
* This method is largely insensitive to constant carrier phase rotations and is often
* more robust during early tracking / imperfect carrier phase alignment.
*
* If false, uses a simpler sign-change detector on the real part:
* - A candidate transition is detected when sign(Re(P_k)) != sign(Re(P_{k-1})).
*
* This assumes the prompt output is already aligned with the data bit polarity
* (i.e., stable PLL lock and correct navigation bit polarity mapping).
*/
bool use_phase_dot_detector;
Config()
: bit_period_ms(20),
epoch_ms(1),
min_events_for_lock(30),
dominance_ratio(0.55),
dominance_ratio(0.6),
stable_best_required(5),
min_prompt_mag(0.0f),
use_phase_dot_detector(true)
@@ -47,66 +137,155 @@ public:
}
};
/**
* @brief Construct a histogram bit synchronizer with the provided configuration.
*
* Initializes internal counters and allocates the histogram with bins() entries,
* all set to zero.
*
* @param cfg Configuration parameters.
*/
explicit HistogramBitSynchronizer(const Config& cfg)
: cfg_(cfg),
hist_(),
total_events_(0),
epoch_count_(0),
locked_(false),
edge_phase_(-1),
has_last_prompt_(false),
last_prompt_(0.0f, 0.0f),
has_last_sign_(false),
edge_phase_(-1),
last_sign_(+1),
has_last_best_bin_(false),
last_best_bin_(0),
stable_best_count_(0)
stable_best_count_(0),
locked_(false),
has_last_prompt_(false),
has_last_sign_(false),
has_last_best_bin_(false)
{
hist_.assign(bins(), 0);
}
/**
* @brief Reset the synchronizer state.
*
* Clears the histogram and all internal counters/flags, returning the instance to the
* pre-lock state:
* - locked() becomes false
* - edge_phase() becomes -1
* - total_events and epoch_count are reset to zero
*/
void reset();
// Call once per epoch (e.g., per coherent integration output).
// Returns true ONLY on the epoch when lock is first declared.
/**
* @brief Update the synchronizer once per epoch.
*
* This method should be called at a fixed cadence defined by Config::epoch_ms
*
* The method:
* - Advances the internal epoch counter,
* - Optionally performs candidate transition detection if tracking quality is acceptable,
* - Updates the phase histogram on detected transitions,
* - Evaluates lock once enough events have been gathered.
*
* @param prompt Prompt correlator output for the current epoch.
* @param tracking_quality_ok Indicates whether tracking quality is sufficient to trust
* the prompt sample for transition detection (e.g., code/carrier lock metrics).
*
* @return True only on the epoch when lock is first declared; false otherwise
* (including subsequent epochs after lock has been achieved).
*/
bool update(const std::complex<float>& prompt, bool tracking_quality_ok);
/**
* @brief Query whether the synchronizer has achieved lock.
*
* @return True if lock has been declared, false otherwise.
*/
bool locked() const { return locked_; }
// Returns -1 if not locked.
/**
* @brief Get the estimated bit edge phase bin.
*
* The edge phase is expressed as an integer histogram bin index in the range
* [0, bins()-1] when locked. The interpretation is “which epoch phase within the
* bit period is most likely to contain a navigation bit transition.”
*
* @return Estimated edge phase bin index, or -1 if not locked.
*/
int edge_phase() const { return edge_phase_; }
// For a given epoch index k (0-based), tells you if it's the predicted edge epoch.
/**
* @brief Predict whether a given epoch index corresponds to a bit edge.
*
* For a given epoch index @p k (0-based), this function returns true when @p k is
* aligned with the currently estimated edge phase (i.e., the predicted transition epoch),
* and false otherwise.
*
* If not locked, this always returns false.
*
* @param k Epoch index (0-based, consistent with the caller's epoch counting).
* @return True if @p k is the predicted edge epoch; false otherwise.
*/
bool is_edge_epoch(std::int64_t k) const;
/**
* @brief Return the number of histogram bins.
*
* Derived from the bit period and epoch duration, e.g.:
* bins = bit_period_ms / epoch_ms
*
* @return Number of histogram bins.
*/
int bins() const;
const std::vector<int>& histogram() const { return hist_; }
std::int64_t total_events() const { return total_events_; }
std::int64_t epoch_count() const { return epoch_count_; }
/**
* @brief Access the internal histogram (read-only).
*
* Each entry counts how many detected candidate transitions occurred at the
* corresponding phase bin within the bit period.
*
* @return Reference to the histogram vector.
*/
const std::vector<int>& get_histogram() const { return hist_; }
/**
* @brief Total number of detected transition events accumulated into the histogram.
*
* @return Total detected events.
*/
std::int64_t get_total_events() const { return total_events_; }
/**
* @brief Total number of epochs processed by update().
*
* This counter increments once per call to update(), regardless of whether a transition
* is detected or whether tracking_quality_ok is true.
*
* @return Total processed epochs.
*/
std::int64_t get_epoch_count() const { return epoch_count_; }
private:
void best_bin_and_count(int& best_bin, int& best_count) const;
Config cfg_;
std::vector<int> hist_;
std::int64_t total_events_;
std::int64_t epoch_count_;
bool locked_;
std::complex<float> last_prompt_; // Sign history (for simple detector)
int edge_phase_;
int last_sign_; // Sign history (for simple detector)
int last_best_bin_; // Stability tracking for best bin
int stable_best_count_; // Stability tracking for best bin
// Prompt history (for dot detector)
bool has_last_prompt_;
std::complex<float> last_prompt_;
// Sign history (for simple detector)
bool has_last_sign_;
int last_sign_;
// Stability tracking for best bin
bool has_last_best_bin_;
int last_best_bin_;
int stable_best_count_;
bool locked_;
bool has_last_prompt_; // Prompt history (for dot detector)
bool has_last_sign_; // Sign history (for simple detector)
bool has_last_best_bin_; // Stability tracking for best bin
};
#endif // GNSS_SDR_BIT_SYNCHRONIZER_H
/** \} */
/** \} */
#endif // GNSS_SDR_BIT_SYNCHRONIZER_H