From f8078ac3f0e3d93e900556ad45b4dfa99e04ba61 Mon Sep 17 00:00:00 2001 From: AlexandreRouma Date: Mon, 23 Sep 2024 00:51:06 +0200 Subject: [PATCH] more work on DAB decoding --- decoder_modules/dab_decoder/src/dab_dsp.h | 200 ++++----- decoder_modules/dab_decoder/src/main.cpp | 8 +- decoder_modules/dab_decoder/src/ofdm.h | 276 ++++++++---- .../dab_decoder/src/optimized_algo.txt | 34 -- decoder_modules/dab_decoder/src/optmized.txt | 31 ++ decoder_modules/dab_decoder/src/test.txt | 397 ++++++++++++++++++ 6 files changed, 728 insertions(+), 218 deletions(-) delete mode 100644 decoder_modules/dab_decoder/src/optimized_algo.txt create mode 100644 decoder_modules/dab_decoder/src/optmized.txt create mode 100644 decoder_modules/dab_decoder/src/test.txt diff --git a/decoder_modules/dab_decoder/src/dab_dsp.h b/decoder_modules/dab_decoder/src/dab_dsp.h index 974ca042..5dd508cb 100644 --- a/decoder_modules/dab_decoder/src/dab_dsp.h +++ b/decoder_modules/dab_decoder/src/dab_dsp.h @@ -5,139 +5,139 @@ #include "dab_phase_sym.h" namespace dab { - class CyclicSync : public dsp::Processor { - using base_type = dsp::Processor; - public: - CyclicSync() {} + // class CyclicSync : public dsp::Processor { + // using base_type = dsp::Processor; + // public: + // CyclicSync() {} - // TODO: The default AGC rate is probably way too fast, plot out the avgCorr to see how much it moves - CyclicSync(dsp::stream* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) { init(in, symbolLength, cyclicPrefixLength, samplerate, agcRate); } + // // TODO: The default AGC rate is probably way too fast, plot out the avgCorr to see how much it moves + // CyclicSync(dsp::stream* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) { init(in, symbolLength, cyclicPrefixLength, samplerate, agcRate); } - void init(dsp::stream* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) { - // Computer the number of samples for the symbol and its cyclic prefix - symbolSamps = round(samplerate * symbolLength); - prefixSamps = round(samplerate * cyclicPrefixLength); + // void init(dsp::stream* in, double symbolLength, double cyclicPrefixLength, double samplerate, float agcRate = 1e-3) { + // // Computer the number of samples for the symbol and its cyclic prefix + // symbolSamps = round(samplerate * symbolLength); + // prefixSamps = round(samplerate * cyclicPrefixLength); - // Allocate and clear the delay buffer - delayBuf = dsp::buffer::alloc(STREAM_BUFFER_SIZE + 64000); - dsp::buffer::clear(delayBuf, symbolSamps); + // // Allocate and clear the delay buffer + // delayBuf = dsp::buffer::alloc(STREAM_BUFFER_SIZE + 64000); + // dsp::buffer::clear(delayBuf, symbolSamps); - // Allocate and clear the history buffer - histBuf = dsp::buffer::alloc(prefixSamps); - dsp::buffer::clear(histBuf, prefixSamps); + // // Allocate and clear the history buffer + // histBuf = dsp::buffer::alloc(prefixSamps); + // dsp::buffer::clear(histBuf, prefixSamps); - // Compute the delay input addresses - delayBufInput = &delayBuf[symbolSamps]; + // // Compute the delay input addresses + // delayBufInput = &delayBuf[symbolSamps]; - // Compute the correlation AGC configuration - this->agcRate = agcRate; - agcRateInv = 1.0f - agcRate; + // // Compute the correlation AGC configuration + // this->agcRate = agcRate; + // agcRateInv = 1.0f - agcRate; - base_type::init(in); - } + // base_type::init(in); + // } - void reset() { - assert(base_type::_block_init); - std::lock_guard lck(base_type::ctrlMtx); - base_type::tempStop(); + // void reset() { + // assert(base_type::_block_init); + // std::lock_guard lck(base_type::ctrlMtx); + // base_type::tempStop(); - base_type::tempStart(); - } + // base_type::tempStart(); + // } - int run() { - int count = base_type::_in->read(); - if (count < 0) { return -1; } + // int run() { + // int count = base_type::_in->read(); + // if (count < 0) { return -1; } - // Copy the data into the normal delay buffer - memcpy(delayBufInput, base_type::_in->readBuf, count * sizeof(dsp::complex_t)); + // // Copy the data into the normal delay buffer + // memcpy(delayBufInput, base_type::_in->readBuf, count * sizeof(dsp::complex_t)); - // Flush the input stream - base_type::_in->flush(); + // // Flush the input stream + // base_type::_in->flush(); - // Do cross-correlation - for (int i = 0; i < count; i++) { - // Get the current history slot - dsp::complex_t* slot = &histBuf[histId++]; + // // Do cross-correlation + // for (int i = 0; i < count; i++) { + // // Get the current history slot + // dsp::complex_t* slot = &histBuf[histId++]; - // Wrap around the history slot index (TODO: Check that the history buffer's length is correct) - histId %= prefixSamps; + // // Wrap around the history slot index (TODO: Check that the history buffer's length is correct) + // histId %= prefixSamps; - // Kick out last value from the correlation - corr -= *slot; + // // Kick out last value from the correlation + // corr -= *slot; - // Save input value and compute the new prodct - dsp::complex_t val = delayBuf[i]; - dsp::complex_t prod = val.conj()*delayBuf[i+symbolSamps]; + // // Save input value and compute the new prodct + // dsp::complex_t val = delayBuf[i]; + // dsp::complex_t prod = val.conj()*delayBuf[i+symbolSamps]; - // Add the new value to the correlation - *slot = prod; + // // Add the new value to the correlation + // *slot = prod; - // Add the new value to the history buffer - corr += prod; + // // Add the new value to the history buffer + // corr += prod; - // Compute sample amplitude - float rcorr = corr.amplitude(); + // // Compute sample amplitude + // float rcorr = corr.amplitude(); - // If a high enough peak is reached, reset the symbol counter - if (rcorr > avgCorr && rcorr > peakCorr) { // Note keeping an average level might not be needed - peakCorr = rcorr; - peakLCorr = lastCorr; - samplesSincePeak = 0; - } + // // If a high enough peak is reached, reset the symbol counter + // if (rcorr > avgCorr && rcorr > peakCorr) { // Note keeping an average level might not be needed + // peakCorr = rcorr; + // peakLCorr = lastCorr; + // samplesSincePeak = 0; + // } - // If this is the sample right after the peak, save it - if (samplesSincePeak == 1) { - peakRCorr = rcorr; - } + // // If this is the sample right after the peak, save it + // if (samplesSincePeak == 1) { + // peakRCorr = rcorr; + // } - // Write the sample to the output - out.writeBuf[samplesSincePeak++] = val; + // // Write the sample to the output + // out.writeBuf[samplesSincePeak++] = val; - // If the end of the symbol is reached, send it off - if (samplesSincePeak >= symbolSamps) { - if (!out.swap(symbolSamps)) { - return -1; - } - samplesSincePeak = 0; - peakCorr = 0; - } + // // If the end of the symbol is reached, send it off + // if (samplesSincePeak >= symbolSamps) { + // if (!out.swap(symbolSamps)) { + // return -1; + // } + // samplesSincePeak = 0; + // peakCorr = 0; + // } - // Update the average correlation - lastCorr = rcorr; + // // Update the average correlation + // lastCorr = rcorr; - // Update the average correlation value - avgCorr = agcRate*rcorr + agcRateInv*avgCorr; - } + // // Update the average correlation value + // avgCorr = agcRate*rcorr + agcRateInv*avgCorr; + // } - // Move unused data - memmove(delayBuf, &delayBuf[count], symbolSamps * sizeof(dsp::complex_t)); + // // Move unused data + // memmove(delayBuf, &delayBuf[count], symbolSamps * sizeof(dsp::complex_t)); - return count; - } + // return count; + // } - protected: - int symbolSamps; - int prefixSamps; + // protected: + // int symbolSamps; + // int prefixSamps; - int histId = 0; - dsp::complex_t* histBuf; + // int histId = 0; + // dsp::complex_t* histBuf; - dsp::complex_t* delayBuf; - dsp::complex_t* delayBufInput; + // dsp::complex_t* delayBuf; + // dsp::complex_t* delayBufInput; - dsp::complex_t corr = { 0.0f, 0.0f }; + // dsp::complex_t corr = { 0.0f, 0.0f }; - int samplesSincePeak = 0; - float lastCorr = 0.0f; - float peakCorr = 0.0f; - float peakLCorr = 0.0f; - float peakRCorr = 0.0f; + // int samplesSincePeak = 0; + // float lastCorr = 0.0f; + // float peakCorr = 0.0f; + // float peakLCorr = 0.0f; + // float peakRCorr = 0.0f; - // Note only required for DAB - float avgCorr = 0.0f; - float agcRate; - float agcRateInv; - }; + // // Note only required for DAB + // float avgCorr = 0.0f; + // float agcRate; + // float agcRateInv; + // }; class FrameFreqSync : public dsp::Processor { using base_type = dsp::Processor; diff --git a/decoder_modules/dab_decoder/src/main.cpp b/decoder_modules/dab_decoder/src/main.cpp index eac947cc..04b21797 100644 --- a/decoder_modules/dab_decoder/src/main.cpp +++ b/decoder_modules/dab_decoder/src/main.cpp @@ -14,6 +14,7 @@ #include #include "dab_dsp.h" #include +#include "ofdm.h" #define CONCAT(a, b) ((std::string(a) + b).c_str()) @@ -35,7 +36,7 @@ public: M17DecoderModule(std::string name) { this->name = name; - file = std::ofstream("sync4.f32", std::ios::out | std::ios::binary); + file = std::ofstream("sync5.f32", std::ios::out | std::ios::binary); // Load config config.acquire(); @@ -47,7 +48,7 @@ public: vfo->setSnapInterval(250); // Initialize DSP here - csync.init(vfo->output, 1e-3, 246e-6, INPUT_SAMPLE_RATE); + csync.init(vfo->output, 2048, 504, 1e-3, INPUT_SAMPLE_RATE, 1e-6, 0.01, 0.005); ffsync.init(&csync.out); ns.init(&ffsync.out, handler, this); @@ -131,8 +132,9 @@ private: std::string name; bool enabled = true; - dab::CyclicSync csync; + //dab::CyclicSync csync; dab::FrameFreqSync ffsync; + dsp::ofdm::CyclicTimeSync csync; dsp::sink::Handler ns; ImGui::ConstellationDiagram constDiagram; diff --git a/decoder_modules/dab_decoder/src/ofdm.h b/decoder_modules/dab_decoder/src/ofdm.h index 1f3fb5a5..074f8a79 100644 --- a/decoder_modules/dab_decoder/src/ofdm.h +++ b/decoder_modules/dab_decoder/src/ofdm.h @@ -11,67 +11,93 @@ namespace dsp::ofdm { public: CyclicTimeSync() {} - CyclicTimeSync(stream* in, int fftSize, double usefulSymbolTime, double cyclicPrefixRatio, double samplerate, + CyclicTimeSync(stream* in, int fftSize, int cpSize, double usefulSymbolTime, double samplerate, double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) { - init(in, fftSize, usefulSymbolTime, cyclicPrefixRatio, samplerate, omegaGain, muGain, omegaRelLimit, interpPhaseCount, interpTapCount); + init(in, fftSize, cpSize, usefulSymbolTime, samplerate, omegaGain, muGain, omegaRelLimit, interpPhaseCount, interpTapCount); } ~CyclicTimeSync() { if (!base_type::_block_init) { return; } base_type::stop(); dsp::multirate::freePolyphaseBank(interpBank); + buffer::free(corrSampCache); + buffer::free(corrProdCache); buffer::free(buffer); } - void init(stream* in, int fftSize, double usefulSymbolTime, double cyclicPrefixRatio, double samplerate, + void init(stream* in, int fftSize, int cpSize, double usefulSymbolTime, double samplerate, double omegaGain, double muGain, double omegaRelLimit, int interpPhaseCount = 128, int interpTapCount = 8) { - omega = 0; // TODO - _omegaGain = omegaGain; - _muGain = muGain; - _omegaRelLimit = omegaRelLimit; - _interpPhaseCount = interpPhaseCount; - _interpTapCount = interpTapCount; + // Save parameters + this->fftSize = fftSize; + this->cpSize = cpSize; + period = fftSize + cpSize; + + // Compute the interpolator settings + omega = (usefulSymbolTime * samplerate) / (double)fftSize; + this->omegaGain = omegaGain; + this->muGain = muGain; + this->omegaRelLimit = omegaRelLimit; + this->interpPhaseCount = interpPhaseCount; + this->interpTapCount = interpTapCount; - pcl.init(_muGain, _omegaGain, 0.0, 0.0, 1.0, omega, omega * (1.0 - omegaRelLimit), omega * (1.0 + omegaRelLimit)); + // Compute the correlator AGC settings + // TODO: Compute it using he FFT and CP sizes + this->corrAgcRate = 1e-4; + corrAgcInvRate = 1.0f - corrAgcRate; + + // Initialize the control loop + pcl.init(muGain, omegaGain, 0.0, 0.0, 1.0, omega, omega * (1.0 - omegaRelLimit), omega * (1.0 + omegaRelLimit)); + + // Generate the interpolation taps generateInterpTaps(); - buffer = buffer::alloc(STREAM_BUFFER_SIZE + _interpTapCount); - bufStart = &buffer[_interpTapCount - 1]; + + // Allocate the buffers + corrSampCache = buffer::alloc(fftSize); + corrProdCache = buffer::alloc(cpSize); + buffer = buffer::alloc(STREAM_BUFFER_SIZE + interpTapCount); + bufStart = &buffer[interpTapCount - 1]; + + // Clear the buffers + buffer::clear(corrSampCache, fftSize); + buffer::clear(corrProdCache, cpSize); + buffer::clear(buffer, interpTapCount - 1); base_type::init(in); } + void setOmegaGain(double omegaGain) { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); - _omegaGain = omegaGain; - pcl.setCoefficients(_muGain, _omegaGain); + this->omegaGain = omegaGain; + pcl.setCoefficients(muGain, omegaGain); } void setMuGain(double muGain) { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); - _muGain = muGain; - pcl.setCoefficients(_muGain, _omegaGain); + this->muGain = muGain; + pcl.setCoefficients(muGain, omegaGain); } void setOmegaRelLimit(double omegaRelLimit) { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); - _omegaRelLimit = omegaRelLimit; - pcl.setFreqLimits(omega * (1.0 - _omegaRelLimit), omega * (1.0 + _omegaRelLimit)); + this->omegaRelLimit = omegaRelLimit; + pcl.setFreqLimits(omega * (1.0 - omegaRelLimit), omega * (1.0 + omegaRelLimit)); } void setInterpParams(int interpPhaseCount, int interpTapCount) { assert(base_type::_block_init); std::lock_guard lck(base_type::ctrlMtx); base_type::tempStop(); - _interpPhaseCount = interpPhaseCount; - _interpTapCount = interpTapCount; + this->interpPhaseCount = interpPhaseCount; + this->interpTapCount = interpTapCount; dsp::multirate::freePolyphaseBank(interpBank); buffer::free(buffer); generateInterpTaps(); - buffer = buffer::alloc(STREAM_BUFFER_SIZE + _interpTapCount); - bufStart = &buffer[_interpTapCount - 1]; + buffer = buffer::alloc(STREAM_BUFFER_SIZE + interpTapCount); + bufStart = &buffer[interpTapCount - 1]; base_type::tempStart(); } @@ -82,59 +108,139 @@ namespace dsp::ofdm { offset = 0; pcl.phase = 0.0f; pcl.freq = omega; + // TODO: The rest base_type::tempStart(); } - inline int process(int count, const complex_t* in, complex_t* out) { + int run() { + int count = base_type::_in->read(); + if (count < 0) { return -1; } + // Copy data to work buffer - memcpy(bufStart, in, count * sizeof(complex_t)); + memcpy(bufStart, base_type::_in->readBuf, count * sizeof(complex_t)); // Process all samples - int outCount = 0; while (offset < count) { + // Get the cache slots + complex_t* sampSlot = &corrSampCache[corrSampCacheId++]; + complex_t* prodSlot = &corrProdCache[corrProdCacheId++]; + corrSampCacheId %= fftSize; + corrProdCacheId %= cpSize; + // Compute the interpolated sample complex_t sample; - int phase = std::clamp(floorf(pcl.phase * (float)_interpPhaseCount), 0, _interpPhaseCount - 1); - volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&sample, (lv_32fc_t*)&buffer[offset], interpBank.phases[phase], _interpTapCount); + int phase = std::clamp(floorf(pcl.phase * (float)interpPhaseCount), 0, interpPhaseCount - 1); + volk_32fc_32f_dot_prod_32fc((lv_32fc_t*)&sample, (lv_32fc_t*)&buffer[offset], interpBank.phases[phase], interpTapCount); - // Update autocorrelation + // Write the sample to the output + if (outCount >= cpSize) { + out.writeBuf[outCount - cpSize] = sample; + } + + // Send out a symbol when it's fully received + if ((++outCount) >= fftSize+cpSize) { + if (!out.swap(outCount)) { break; } + outCount = 0; + } + + // Run autocorrelation + complex_t prod = sample.conj()*(*sampSlot); + corr += prod; + corr -= *prodSlot; + + // Write back the new sample and product value to the cache + *sampSlot = sample; + *prodSlot = prod; // Compute the correlation level float corrLvl = corr.amplitude(); - // Detect peak in autocorrelation - if (0/*TODO*/) { + // Detect peak in autocorrelation (TODO: level check maybe not needed now that corrPeak is reset to corrLvl) + if (corrLvl > corrAvg && corrLvl > corrPeak) { // Save the current correlation as the peak corrPeak = corrLvl; // Save the value of the previous correlation as the left side of the peak - corrPeakL = corrLastLvl; + corrPeakL = corrLast; - // Save the symbol period - measuredSymbolPeriod = sampCount; - - // Reset the sample count - sampCount = 0; - - // TODO: Maybe save the error to apply it at the end of the frame? (will cause issues with the longer null symbol in DAB) + // Reset the peak distance counter + sincePeak = 0; } - // Write the sample to the frame if within it - if (sampCount < symbolSize) { - symbol[sampCount++] = sample; + // The first sample after a peak is the right-side sample + if (sincePeak == 1) { + corrPeakR = corrLvl; } - - // When the end of the symbol is reached - if (sampCount == symbolSize) { - // Send out the symbol - // TODO + else if (sincePeak == cpSize) { + // Start the useful symbol counter + sinceCp = 0; + + // Compute the fractional error (TODO: Probably very inaccurate with noise, use real slopes instead) + if (corrPeakL > corrPeakR) { + float maxSlope = corrPeakR - corrPeak; + float slope = corrPeak - corrPeakL; + fracErr = std::clamp(0.5f * (1.0f + slope / maxSlope), -0.5f, 0.5f); + } + else { + float maxSlope = corrPeak - corrPeakL; + float slope = corrPeakR - corrPeak; + fracErr = std::clamp(-0.5f * (1.0f + slope / maxSlope), -0.5f, 0.5f); + } } + else if (sincePeak == fftSize) { + // Reset the peak detector + corrPeak = corrAvg; + } + // NOTE: THIS IS ONLY NEEDED FOR DAB + // Detect a wider-than-normal distance to adapt the output counter + else if (sincePeak == 2656) { + // Reset the output counter + outCount = 50; + } + + // Last sample of useful symbol + if (sinceCp == fftSize) { + // If the fractional error is valid, run closed-loop + float err = 0.0f; + if (!std::isnan(fracErr)) { + // Compute the measured period using the distance to the last symbol + float measuredPeriod = (float)sinceLastSym - fracErr; + // NOTE: THIS IS ONLY NEEDED FOR DAB + if (measuredPeriod > 3828.0f) { + // Null symbol + err = measuredPeriod - (2552.0f+2656.0f); + } + else { + // Regular symbol + err = measuredPeriod - period; + } - // TODO: limit how much the sample count can grow otherwise otherflows will trigger a false frame detection + err = std::clamp(err, -10.0f, 10.0f); - // Run the control loop - //pcl.advance(error); // TODO - pcl.advancePhase(); + // Run the control loop in closed-loop mode + pcl.advance(err); + } + else { + // Otherwise, run open-loop + pcl.advancePhase(); + } + + // printf("%d\n", outCount); + + // Nudge the symbol window if it's too out of sync + if (outCount > 100) { + // TODO: MOVE THE LAST SAMPLES OR THE SYMBOL WILL BE CORRUPTED! + outCount = 50; + flog::debug("NUDGE!"); + } + + // Reset the period counter + sinceLastSym = 0; + } + else { + // Run the control loop in open-loop mode + pcl.advancePhase(); + } // Update the offset and phase float delta = floorf(pcl.phase); @@ -142,44 +248,45 @@ namespace dsp::ofdm { pcl.phase -= delta; // Update the last correlation level - corrLastLvl = corrLvl; + corrLast = corrLvl; + + // Update correlation AGC + corrAvg = corrAvg*corrAgcInvRate + corrLvl*corrAgcRate; + + // Increment the distance counters (TODO: Check if they happen at the right point, eg. after being reset to zero) + sincePeak++; + sinceLastSym++; + sinceCp++; } // Prepare offset for next buffer of samples offset -= count; // Update delay buffer - memmove(buffer, &buffer[count], (_interpTapCount - 1) * sizeof(complex_t)); - - return outCount; - } - - int run() { - int count = base_type::_in->read(); - if (count < 0) { return -1; } - - int outCount = process(count, base_type::_in->readBuf, base_type::out.writeBuf); + memmove(buffer, &buffer[count], (interpTapCount - 1) * sizeof(complex_t)); // Swap if some data was generated base_type::_in->flush(); - if (outCount) { - if (!base_type::out.swap(outCount)) { return -1; } - } - return outCount; + return count; } protected: void generateInterpTaps() { - double bw = 0.5 / (double)_interpPhaseCount; - dsp::tap lp = dsp::taps::windowedSinc(_interpPhaseCount * _interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, _interpPhaseCount); - interpBank = dsp::multirate::buildPolyphaseBank(_interpPhaseCount, lp); + double bw = 0.5 / (double)interpPhaseCount; + dsp::tap lp = dsp::taps::windowedSinc(interpPhaseCount * interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, interpPhaseCount); + interpBank = dsp::multirate::buildPolyphaseBank(interpPhaseCount, lp); taps::free(lp); } + // OFDM Configuration + int fftSize; + int cpSize; + float period; + // Interpolator dsp::multirate::PolyphaseBank interpBank; - int _interpPhaseCount; - int _interpTapCount; + int interpPhaseCount; + int interpTapCount; int offset = 0; complex_t* buffer = NULL; complex_t* bufStart; @@ -187,24 +294,31 @@ namespace dsp::ofdm { // Control loop loop::PhaseControlLoop pcl; double omega; - double _omegaGain; - double _muGain; - double _omegaRelLimit; + double omegaGain; + double muGain; + double omegaRelLimit; + float fracErr = 0.0f; // Autocorrelator - complex_t corr; - complex_t* corrProducts = NULL; + complex_t corr = {0.0f, 0.0f}; + complex_t* corrSampCache = NULL; + complex_t* corrProdCache = NULL; + int corrSampCacheId = 0; + int corrProdCacheId = 0; float corrAgcRate; float corrAgcInvRate; - float corrLastLvl = 0; + float corrAvg = 0; + float corrLast = 0; float corrPeakR = 0; float corrPeak = 0; float corrPeakL = 0; - // Symbol - complex_t* symbol; // TODO: Will use output stream buffer instead - int symbolSize; - int sampCount = 0; - int measuredSymbolPeriod = 0; + // Peak detection + int sincePeak = 0; + int sinceLastSym = 0; + int sinceCp = 0; + + // Other shit to categorize + int outCount = 0; }; }; \ No newline at end of file diff --git a/decoder_modules/dab_decoder/src/optimized_algo.txt b/decoder_modules/dab_decoder/src/optimized_algo.txt deleted file mode 100644 index ec940337..00000000 --- a/decoder_modules/dab_decoder/src/optimized_algo.txt +++ /dev/null @@ -1,34 +0,0 @@ -0123456789 ---- --- - -0*4 -1*5 -2*6 - -1*5 -2*6 = L + 3*7 - 0*4 -3*7 - -2*6 -3*7 = L + 4*8 - 1*5 -4*8 - -3*7 -4*8 = L + 5*9 - 2*6 -5*9 - - - -0*5 -1*6 -2*7 - -1*6 -2*7 -3*8 - -2*7 -3*8 -4*9 - -=> Use same technique to cache the interpolation results \ No newline at end of file diff --git a/decoder_modules/dab_decoder/src/optmized.txt b/decoder_modules/dab_decoder/src/optmized.txt new file mode 100644 index 00000000..086039a9 --- /dev/null +++ b/decoder_modules/dab_decoder/src/optmized.txt @@ -0,0 +1,31 @@ +cyclicLen = 4 +usefulLen = 12 + +A = 0*12 + 1*13 + 2*14 + 3*15 +B = 1*13 + 2*14 + 3*15 + 4*16 = A - 0*12 + 4*16 +C = 2*14 + 3*15 + 4*16 + 5*17 = B - 1*13 + 5*17 +D = 3*15 + 4*16 + 5*17 + 6*18 = C - 2*14 + 6*18 +E = 4*16 + 5*17 + 6*18 + 7*19 = D - 3*15 + 7*19 +F = 5*17 + 6*18 + 7*19 + 8*20 = E - 4*16 + 8*20 +G = 6*18 + 7*19 + 8*20 + 9*21 = F - 5*17 + 9*21 +H = 7*19 + 8*20 + 9*21 + 10*22 = G - 6*18 + 10*22 +I = 8*20 + 9*21 + 10*22 + 11*23 = H - 7*19 + 11*23 +J = 9*21 + 10*22 + 11*23 + 12*24 = I - 8*20 + 12*24 +K = 10*22 + 11*23 + 12*24 + 13*25 = J - 9*21 + 13*25 +L = 11*23 + 12*24 + 13*25 + 14*26 = K - 10*22 + 14*26 +M = 12*24 + 13*25 + 14*26 + 15*27 = L - 11*23 + 15*27 +N = 13*25 + 14*26 + 15*27 + 16*28 = M - 12*24 + 16*28 +O = 14*26 + 15*27 + 16*28 + 17*29 = N - 13*25 + 17*29 +P = 15*27 + 16*28 + 17*29 + 18*30 = O - 14*26 + 18*30 +Q = 16*28 + 17*29 + 18*30 + 19*31 = P - 15*27 + 19*31 +R = 17*29 + 18*30 + 19*31 + 20*32 = Q - 16*28 + 20*32 +S = 18*30 + 19*31 + 20*32 + 21*33 = R - 17*29 + 21*33 +T = 19*31 + 20*32 + 21*33 + 22*34 = S - 18*30 + 22*34 +U = 20*32 + 21*33 + 22*34 + 23*35 = T - 19*31 + 23*35 + +Conclusion: +sampCacheLen = usefulLen +prodCacheLen = cyclicLen + +Peak correlation occurs when the current interpolated value is the last FFT sample + diff --git a/decoder_modules/dab_decoder/src/test.txt b/decoder_modules/dab_decoder/src/test.txt new file mode 100644 index 00000000..f29df3ea --- /dev/null +++ b/decoder_modules/dab_decoder/src/test.txt @@ -0,0 +1,397 @@ +5209 +2553 +2551 +2551 +2552 +2551 +2553 +2555 +2549 +2552 +2552 +2554 +2550 +2553 +2553 +2550 +2553 +2552 +2550 +2552 +2548 +2558 +2551 +2546 +2559 +2551 +2552 +2552 +2551 +2554 +2555 +2549 +2550 +2549 +2557 +2551 +2554 +2550 +2552 +2546 +2559 +2551 +2554 +2550 +2550 +2557 +2550 +2556 +2543 +2556 +2551 +2554 +2551 +2553 +2554 +2550 +2551 +2552 +2552 +2553 +2550 +2553 +2546 +2558 +2552 +2552 +2552 +2550 +2555 +2551 +2551 +2554 +2553 +2553 +2549 +2552 +5208 +2554 +2550 +2552 +2551 +2553 +2551 +2553 +2551 +2553 +2550 +2554 +2553 +2551 +2553 +2552 +2546 +2557 +2551 +2553 +2552 +2551 +2553 +2551 +2548 +2557 +2553 +2551 +2562 +2539 +2559 +2548 +2551 +2551 +2550 +2556 +2551 +2554 +2550 +2552 +2552 +2548 +2556 +2550 +2554 +2553 +2553 +2550 +2552 +2552 +2550 +2555 +2558 +2545 +2552 +2553 +2548 +2555 +2552 +2552 +2557 +2550 +2548 +2553 +2554 +2550 +2552 +2547 +2558 +2551 +2552 +2552 +2552 +2555 +2549 +2552 +5208 +2552 +2552 +2552 +2550 +2555 +2550 +2553 +2553 +2551 +2552 +2547 +2557 +2552 +2552 +2552 +2552 +2552 +2552 +2552 +2546 +2558 +2551 +2552 +2553 +2551 +2553 +2553 +2552 +2551 +2552 +2552 +2551 +2553 +2552 +2552 +2552 +2552 +2552 +2552 +2556 +2548 +2551 +2555 +2550 +2552 +2555 +2549 +2552 +2552 +2550 +2553 +2551 +2554 +2552 +2551 +2553 +2553 +2551 +2548 +2550 +2555 +2554 +2553 +2556 +2547 +2552 +2554 +2552 +2550 +2552 +2552 +2553 +2552 +2551 +2552 +5209 +2553 +2551 +2551 +2547 +2558 +2550 +2553 +2552 +2553 +2552 +2549 +2551 +2557 +2549 +2554 +2551 +2554 +2550 +2553 +2553 +2551 +2551 +2548 +2559 +2549 +2552 +2552 +2552 +2551 +2551 +2550 +2557 +2551 +2552 +2555 +2549 +2557 +2549 +2550 +2553 +2549 +2554 +2553 +2553 +2550 +2552 +2553 +2550 +2553 +2553 +2551 +2547 +2557 +2552 +2552 +2551 +2553 +2549 +2555 +2556 +2550 +2550 +2553 +2551 +2552 +2553 +2551 +2552 +2552 +2552 +2553 +2551 +2541 +2563 +2552 +5210 +2550 +2551 +2552 +2553 +2553 +2551 +2552 +2552 +2552 +2552 +2558 +2547 +2551 +2552 +2552 +2552 +2552 +2550 +2554 +2551 +2553 +2552 +2551 +2553 +2551 +2553 +2553 +2550 +2551 +2555 +2550 +2552 +2552 +2553 +2553 +2550 +2552 +2553 +2550 +2553 +2558 +2546 +2553 +2554 +2550 +2552 +2553 +2548 +2554 +2552 +2552 +2552 +2551 +2554 +2550 +2553 +2553 +2550 +2551 +2552 +2554 +2553 +2551 +2551 +2555 +2550 +2553 +2552 +2550 +2554 +2550 +2553 +2553 +2553 +2550 +5210 +2553 +2549 +2553 +2551 +2552 +2552 +2556 +2548 +2549 +2555 +2551 +2557 +2548 +2552 +2552 +2552 \ No newline at end of file