From c8785c94bb2f04abf9c4dde2858f9f502a49f781 Mon Sep 17 00:00:00 2001 From: f4exb Date: Wed, 13 Jul 2016 03:31:19 +0200 Subject: [PATCH] SDRdaemonFEC support. auto R/W correction --- .../sdrdaemon/sdrdaemonudphandler.cpp | 4 +- .../sdrdaemonfec/sdrdaemonfecbuffer.cpp | 62 ++++++++++++++++++- .../sdrdaemonfec/sdrdaemonfecbuffer.h | 17 +++-- .../sdrdaemonfec/sdrdaemonfecudphandler.cpp | 11 +++- 4 files changed, 82 insertions(+), 12 deletions(-) diff --git a/plugins/samplesource/sdrdaemon/sdrdaemonudphandler.cpp b/plugins/samplesource/sdrdaemon/sdrdaemonudphandler.cpp index 2ce1bce4d..19ec8859e 100644 --- a/plugins/samplesource/sdrdaemon/sdrdaemonudphandler.cpp +++ b/plugins/samplesource/sdrdaemon/sdrdaemonudphandler.cpp @@ -223,8 +223,6 @@ void SDRdaemonUDPHandler::tick() { m_throttlems = throttlems; m_readLengthSamples = (m_sdrDaemonBuffer.getSampleRate() * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000; - m_readLengthSamples += m_sdrDaemonBuffer.getRWBalanceCorrection(); - m_readLength = m_readLengthSamples * SDRdaemonBuffer::m_iqSampleSize; m_throttleToggle = !m_throttleToggle; } @@ -232,6 +230,8 @@ void SDRdaemonUDPHandler::tick() m_readLengthSamples += m_sdrDaemonBuffer.getRWBalanceCorrection(); } + m_readLength = m_readLengthSamples * SDRdaemonBuffer::m_iqSampleSize; + // read samples directly feeding the SampleFifo (no callback) m_sampleFifo->write(reinterpret_cast(m_sdrDaemonBuffer.readData(m_readLength)), m_readLength); m_samplesCount += m_readLengthSamples; diff --git a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.cpp b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.cpp index 5de6f4da4..e090f03fd 100644 --- a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.cpp +++ b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.cpp @@ -34,11 +34,16 @@ SDRdaemonFECBuffer::SDRdaemonFECBuffer(uint32_t throttlems) : m_readIndex(0), m_readBuffer(0), m_readSize(0), - m_bufferLenSec(0.0f) + m_bufferLenSec(0.0f), + m_nbReads(0), + m_nbWrites(0), + m_balCorrection(0), + m_balCorrLimit(0) { m_currentMeta.init(); m_framesNbBytes = nbDecoderSlots * sizeof(BufferFrame); m_wrDeltaEstimate = m_framesNbBytes / 2; + m_readNbBytes = 1; m_paramsCM256.BlockBytes = sizeof(ProtectedBlock); // never changes m_paramsCM256.OriginalCount = m_nbOriginalBlocks; // never changes } @@ -70,12 +75,62 @@ void SDRdaemonFECBuffer::initReadIndex() { m_readIndex = ((m_decoderIndexHead + (nbDecoderSlots/2)) % nbDecoderSlots) * sizeof(BufferFrame); m_wrDeltaEstimate = m_framesNbBytes / 2; + m_nbReads = 0; + m_nbWrites = 0; +} + +void SDRdaemonFECBuffer::rwCorrectionEstimate(int slotIndex) +{ + if (m_nbReads >= 40) // check every ~1s as tick is ~50ms + { + int targetPivotSlot = (slotIndex + (nbDecoderSlots/2)) % nbDecoderSlots; // slot at half buffer opposite of current write slot + int targetPivotIndex = targetPivotSlot * sizeof(BufferFrame); // buffer index corresponding to start of above slot + int normalizedReadIndex = (m_readIndex < targetPivotIndex ? m_readIndex + nbDecoderSlots * sizeof(BufferFrame) : m_readIndex) + - (targetPivotSlot * sizeof(BufferFrame)); // normalize read index so it is positive and zero at start of pivot slot + int dBytes; + int rwDelta = (m_nbReads * m_readNbBytes) - (m_nbWrites * sizeof(BufferFrame)); + + if (normalizedReadIndex < (nbDecoderSlots/ 2) * sizeof(BufferFrame)) // read leads + { + dBytes = - normalizedReadIndex - rwDelta; + } + else // read lags + { + dBytes = (nbDecoderSlots * sizeof(BufferFrame)) - normalizedReadIndex - rwDelta; + } + + m_balCorrection = (m_balCorrection / 4) + (dBytes / (int) (m_iqSampleSize * m_nbReads)); // correction is in number of samples. Alpha = 0.25 + + if (m_balCorrection < -m_balCorrLimit) { + m_balCorrection = -m_balCorrLimit; + } else if (m_balCorrection > m_balCorrLimit) { + m_balCorrection = m_balCorrLimit; + } + + float rwRatio = (float) (m_nbWrites * sizeof(BufferFrame)) / (float) (m_nbReads * m_readNbBytes); + + qDebug() << "SDRdaemonFECBuffer::rwCorrectionEstimate: " + << " m_nbReads: " << m_nbReads + << " m_nbWrites: " << m_nbWrites + << " rwDelta: " << rwDelta + << " targetPivotSlot: " << targetPivotSlot + << " targetPivotIndex: " << targetPivotIndex + << " m_readIndex: " << m_readIndex + << " normalizedReadIndex: " << normalizedReadIndex + << " dBytes: " << dBytes + << " m_balCorrection: " << m_balCorrection; + + //m_balCorrection = dBytes / (int) (m_iqSampleSize * m_nbReads); + m_nbReads = 0; + m_nbWrites = 0; + } } void SDRdaemonFECBuffer::checkSlotData(int slotIndex) { int pseudoWriteIndex = slotIndex * sizeof(BufferFrame); m_wrDeltaEstimate = pseudoWriteIndex - m_readIndex; + m_nbWrites++; if (!m_decoderSlots[slotIndex].m_decoded) //if (m_decoderSlots[slotIndex].m_blockCount < m_nbOriginalBlocks) @@ -95,6 +150,8 @@ void SDRdaemonFECBuffer::checkSlotData(int slotIndex) if (sampleRate > 0) { m_bufferLenSec = (float) m_framesNbBytes / (float) (sampleRate * m_iqSampleSize); + m_balCorrLimit = sampleRate / 1000; // +/- 1 ms correction max per read + m_readNbBytes = (sampleRate * m_iqSampleSize) / 20; } printMeta("SDRdaemonFECBuffer::checkSlotData: new meta", metaData); // print for change other than timestamp @@ -143,6 +200,7 @@ void SDRdaemonFECBuffer::writeData(char *array, uint32_t length) m_decoderIndexHead = decoderIndex; // new decoder slot head m_frameHead = frameIndex; // new frame head checkSlotData(decoderIndex); // check slot before re-init + rwCorrectionEstimate(decoderIndex); initDecodeSlot(decoderIndex); // collect stats and re-initialize current slot } @@ -417,6 +475,8 @@ uint8_t *SDRdaemonFECBuffer::readData(int32_t length) uint8_t *buffer = (uint8_t *) m_frames; uint32_t readIndex = m_readIndex; + m_nbReads++; + if (m_readIndex + length < m_framesNbBytes) // ends before buffer bound { m_readIndex += length; diff --git a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.h b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.h index 3b5e1e1d1..1fd423395 100644 --- a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.h +++ b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecbuffer.h @@ -24,9 +24,9 @@ #include "util/movingaverage.h" -#define SDRDAEMONFEC_UDPSIZE 512 // UDP payload size -#define SDRDAEMONFEC_NBORIGINALBLOCKS 128 // number of sample blocks per frame excluding FEC blocks -#define SDRDAEMONFEC_NBDECODERSLOTS 16 // power of two sub multiple of uint16_t size. A too large one is superfluous. +#define SDRDAEMONFEC_UDPSIZE 512 // UDP payload size +#define SDRDAEMONFEC_NBORIGINALBLOCKS 128 // number of sample blocks per frame excluding FEC blocks +#define SDRDAEMONFEC_NBDECODERSLOTS 16 // power of two sub multiple of uint16_t size. A too large one is superfluous. class SDRdaemonFECBuffer { @@ -99,7 +99,7 @@ public: float getAvgNbRecovery() const { return m_avgNbRecovery; } float getBufferLengthInSecs() const { return m_bufferLenSec; } - int32_t getRWBalanceCorrection(int throttlems) const { return m_balCorrection; } + int32_t getRWBalanceCorrection() const { return m_balCorrection; } /** Get buffer gauge value in % of buffer size ([-50:50]) * [-50:0] : write leads or read lags @@ -164,17 +164,22 @@ private: MovingAverage m_avgNbRecovery; //!< (stats) average number of recovery blocks used int m_readIndex; //!< current byte read index in frames buffer int m_wrDeltaEstimate; //!< Sampled estimate of write to read indexes difference + int m_readNbBytes; //!< Nominal number of bytes per read (50ms) uint32_t m_throttlemsNominal; //!< Initial throttle in ms uint8_t* m_readBuffer; //!< Read buffer to hold samples when looping back to beginning of raw buffer uint32_t m_readSize; //!< Read buffer size - int32_t m_balCorrection; //!< R/W balance correction in number of samples per nominal tick period float m_bufferLenSec; + int m_nbReads; //!< Number of buffer reads since start of auto R/W balance correction period + int m_nbWrites; //!< Number of buffer writes since start of auto R/W balance correction period + int m_balCorrection; //!< R/W balance correction in number of samples + int m_balCorrLimit; //!< Correction absolute value limit in number of samples + void initDecodeAllSlots(); void initReadIndex(); - void rwSkewEstimate(int slotIndex); + void rwCorrectionEstimate(int slotIndex); void checkSlotData(int slotIndex); void initDecodeSlot(int slotIndex); diff --git a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecudphandler.cpp b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecudphandler.cpp index add2b0cbc..91568e259 100644 --- a/plugins/samplesource/sdrdaemonfec/sdrdaemonfecudphandler.cpp +++ b/plugins/samplesource/sdrdaemonfec/sdrdaemonfecudphandler.cpp @@ -202,11 +202,16 @@ void SDRdaemonFECUDPHandler::tick() { m_throttlems = throttlems; m_readLengthSamples = (m_sdrDaemonBuffer.getCurrentMeta().m_sampleRate * (m_throttlems+(m_throttleToggle ? 1 : 0))) / 1000; - m_readLength = m_readLengthSamples * SDRdaemonFECBuffer::m_iqSampleSize; m_throttleToggle = !m_throttleToggle; } - // read samples directly feeding the SampleFifo (no callback) + if (m_autoCorrBuffer) { + m_readLengthSamples += m_sdrDaemonBuffer.getRWBalanceCorrection(); + } + + m_readLength = m_readLengthSamples * SDRdaemonFECBuffer::m_iqSampleSize; + + // read samples directly feeding the SampleFifo (no callback) m_sampleFifo->write(reinterpret_cast(m_sdrDaemonBuffer.readData(m_readLength)), m_readLength); m_samplesCount += m_readLengthSamples; @@ -227,7 +232,7 @@ void SDRdaemonFECUDPHandler::tick() m_sdrDaemonBuffer.getCurNbRecovery(), m_sdrDaemonBuffer.getAvgNbBlocks(), m_sdrDaemonBuffer.getAvgNbRecovery()); - m_outputMessageQueueToGUI->push(report); + m_outputMessageQueueToGUI->push(report); } }