- CPR/STR: no automatic change of ACQ and TRK states base on SNR

- No use for clock stuff, since buffer_ip is decimated
- use Costas Loop for acquisition


git-svn-id: http://moon:8086/svn/software/trunk/projects/mpsk_rx_gui@1052 b431acfa-c32f-4a4a-93f1-934dc6c82436
This commit is contained in:
2022-06-21 19:39:40 +00:00
parent 4f9efa88bb
commit eec12c9393
2 changed files with 174 additions and 162 deletions
+40 -30
View File
@@ -345,14 +345,14 @@ void Receiver::timerCallback()
} }
// Control // Control
m_params.cprState = cpr_state_acquisition; // m_params.cprState = cpr_state_acquisition;
m_params.strState = str_state_acquisition; // m_params.strState = str_state_acquisition;
if (getStatus().snrCurrent_dB > 30) // if (getStatus().snrCurrent_dB > 30)
{ // {
// statusHasChanged = (m_params.cprState != cpr_state_track) || (m_params.strState != str_state_track); // statusHasChanged = (m_params.cprState != cpr_state_track) || (m_params.strState != str_state_track);
m_params.cprState = cpr_state_track; // m_params.cprState = cpr_state_track;
m_params.strState = str_state_track; // m_params.strState = str_state_track;
} // }
// Announce status changed // Announce status changed
if (statusHasChanged) if (statusHasChanged)
@@ -477,32 +477,21 @@ void Receiver::processBaseband(CVec const &iq, uint32_t len)
m_polyPhase.process(); m_polyPhase.process();
} }
// Further BB processing
// @2 x symbolrate
while(m_buffer_ip.len())
{
ComplexScalar iq_mf = m_buffer_ip.readAt(0);
// -----------------------------------------------------
// Carrier Derotator
// @2 x symbolrate
// -----------------------------------------------------
IQ_cpr = toCpx(m_nco_cpr.mixComplexS(iq_mf, ComplexScalar(1,1)));
m_nco_cpr.process(m_dOmega_vco, m_params.CPR_phase);
IQ_eq_in = IQ_cpr;
// ----------------------------------------------------- // -----------------------------------------------------
// Big and ugly processing loop // Big and ugly processing loop
// Further BB processing
// @1 x symbolrate // @1 x symbolrate
// ----------------------------------------------------- // -----------------------------------------------------
if (ClockIsTick(&m_symClock, 1)) while(m_buffer_ip.len())
{ {
// Buffer contains every 2nd sample from interpolator
ComplexScalar iq_mf = m_buffer_ip.readAt(0);
#ifndef DISABLE_UNUSED_STATISTICS #ifndef DISABLE_UNUSED_STATISTICS
minMaxProcess(&m_statistics.ddcMinMax, IQ_eq_in); minMaxProcess(&m_statistics.ddcMinMax, iq_mf);
#endif #endif
// ----------------------------------------------------- // -----------------------------------------------------
// AGC Blind process samples // AGC Tracker based training
// @1 x symbolrate // @1 x symbolrate
// ----------------------------------------------------- // -----------------------------------------------------
if (m_params.agc_mode != agc_mode_disabled) if (m_params.agc_mode != agc_mode_disabled)
@@ -519,6 +508,22 @@ void Receiver::processBaseband(CVec const &iq, uint32_t len)
} }
} }
// -----------------------------------------------------
// Carrier Derotator
// @1 x symbolrate
// -----------------------------------------------------
IQ_cpr = toCpx(m_nco_cpr.mixComplexS(iq_mf, ComplexScalar(1,1)));
m_nco_cpr.process(m_dOmega_vco, m_params.CPR_phase);
// Carrier Phase Recovery
if (m_params.cprState == cpr_state_acquisition)
{
// Costas loop
vPfdCpr = PhaseErrQPSK(IQ_cpr);
}
IQ_eq_in = IQ_cpr;
// ----------------------------------------------------- // -----------------------------------------------------
// Equalizer Process samples // Equalizer Process samples
// @1 x symbolrate // @1 x symbolrate
@@ -552,12 +557,19 @@ void Receiver::processBaseband(CVec const &iq, uint32_t len)
IQ_hard = sym_err.hard_sym; IQ_hard = sym_err.hard_sym;
// Carrier Phase Recovery // Carrier Phase Recovery
if (m_params.cpr_mode == cpr_mode_enabled) if (m_params.cprState == cpr_state_track)
{ {
// state-based PFD // state-based PFD
vPfdCpr = PfdProcess(&m_pfdCpr, sym_err.err_phi, dabs(sym_err.mag)); vPfdCpr = PfdProcess(&m_pfdCpr, sym_err.err_phi, dabs(sym_err.mag));
}
// use phase error from symbol mapper if (m_params.cpr_mode == cpr_mode_enabled)
{
// Update frequency from Carrier Derotator
// vPfdCpr comes from PhaseErrQPSK forming a Costas Loop when
// cprState == cpr_state_acquisition
// vPfdCpr comes from SymMapper forming a decision directed phase correction loop when
// cprState == cpr_state_track
m_dOmega_vco = LeadLagProcess(&m_loop_filter_cpr, &m_params.cpr_loopfilter_coeff[m_params.cpr_loopfilter_coeff_index], vPfdCpr); m_dOmega_vco = LeadLagProcess(&m_loop_filter_cpr, &m_params.cpr_loopfilter_coeff[m_params.cpr_loopfilter_coeff_index], vPfdCpr);
} }
@@ -647,13 +659,11 @@ void Receiver::processBaseband(CVec const &iq, uint32_t len)
// ----------------------------------------------------- // -----------------------------------------------------
m_pSymbolBuffer[m_numSymsInBuffer++] = sym_err; m_pSymbolBuffer[m_numSymsInBuffer++] = sym_err;
if ((m_params.strState == str_state_track) && (m_params.cprState == cpr_state_track))
{
// Update per-symbol statistic // Update per-symbol statistic
SymStatUpDate(&m_sym_stat, sym, &sym_err); SymStatUpDate(&m_sym_stat, sym, &sym_err);
m_frameReceiver.process((symbol_t)sym); m_frameReceiver.process((symbol_t)sym);
}
if (m_pDataListener) if (m_pDataListener)
{
m_pDataListener->receiverDataChanged(this); m_pDataListener->receiverDataChanged(this);
} }
} }
+3 -1
View File
@@ -306,7 +306,7 @@ class TimingGeneratorGardner : public Interpolation::TimingGenerator
coeff = pCoeff; coeff = pCoeff;
} }
void process(ComplexScalar const &iq) bool process(ComplexScalar const &iq)
{ {
// @2 x symbolrate // @2 x symbolrate
// Symbol timing recovery // Symbol timing recovery
@@ -320,6 +320,8 @@ class TimingGeneratorGardner : public Interpolation::TimingGenerator
is_time = not is_time; is_time = not is_time;
update(m_omega); update(m_omega);
return not is_time;
} }
}; };