mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
SDRdaemonFEC support. auto R/W correction
This commit is contained in:
parent
95804345d5
commit
c8785c94bb
@ -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<quint8*>(m_sdrDaemonBuffer.readData(m_readLength)), m_readLength);
|
||||
m_samplesCount += m_readLengthSamples;
|
||||
|
@ -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;
|
||||
|
@ -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<int, int, 10> 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);
|
||||
|
||||
|
@ -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<quint8*>(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user