mirror of
https://git.vladimir.cc/vladimir/ewsdr.git
synced 2026-08-25 20:37:33 +00:00
fix: Pluto TX buffer scaled by sample-rate (SoapyPlutoSDR model)
Fixed 4096-pair TX buffer was too small for full-duplex above ~1 Msps
("not enough ... samples getting dropped" per SoapyPlutoSDR), causing
clicks/dropouts. Now sized as round(rate/60) rounded up to a power of 2,
clamped [4096..65536] (576k→16384, 1536k→32768). FIFO cushion (~4 buffers)
resizes to match in StartTX.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+30
-4
@@ -68,6 +68,7 @@ type
|
|||||||
FTxThread: TThread;
|
FTxThread: TThread;
|
||||||
FTxStreaming: Boolean;
|
FTxStreaming: Boolean;
|
||||||
FTxRatio: Integer; // FSampleRate div 192000 (целочисленный апсемпл)
|
FTxRatio: Integer; // FSampleRate div 192000 (целочисленный апсемпл)
|
||||||
|
FTxBufPairs: Integer; // размер TX-буфера в IQ-парах (по sample-rate, см. TxBufPairsForRate)
|
||||||
FTxPrevI: LongInt; // последний 24-бит сэмпл (линейная интерполяция между вызовами)
|
FTxPrevI: LongInt; // последний 24-бит сэмпл (линейная интерполяция между вызовами)
|
||||||
FTxPrevQ: LongInt;
|
FTxPrevQ: LongInt;
|
||||||
// FIFO int16-пар @ device-rate (кольцо): продюсер — SendDUCIQ, консьюмер — push-поток.
|
// FIFO int16-пар @ device-rate (кольцо): продюсер — SendDUCIQ, консьюмер — push-поток.
|
||||||
@@ -140,7 +141,11 @@ const
|
|||||||
RX_BUF_SAMPLES = 8192; // IQ-пар за один refill (~5.3 мс @ 1.536 MS/s)
|
RX_BUF_SAMPLES = 8192; // IQ-пар за один refill (~5.3 мс @ 1.536 MS/s)
|
||||||
PAIRS_PER_PKT = 238; // как DDC IQ HPSDR (238*6 = 1428 байт IQData)
|
PAIRS_PER_PKT = 238; // как DDC IQ HPSDR (238*6 = 1428 байт IQData)
|
||||||
TX_SRC_RATE = 192000; // фиксированный TX-рейт WDSP (TX_SAMPLE_RATE)
|
TX_SRC_RATE = 192000; // фиксированный TX-рейт WDSP (TX_SAMPLE_RATE)
|
||||||
TX_BUF_PAIRS = 4096; // IQ-пар в одном TX-буфере push (~2.7 мс @ 1.536 MS/s)
|
// Размер TX-буфера масштабируется от sample-rate (как SoapyPlutoSDR):
|
||||||
|
// round(rate/60) → следующая степень 2. Фикс 4096 «недостаточно для full-duplex
|
||||||
|
// выше 1 Msps — сэмплы дропаются» (комментарий драйвера). Минимум — TX_BUF_MIN.
|
||||||
|
TX_BUF_MIN = 4096; // нижняя граница (~7 мс @ 576k)
|
||||||
|
TX_BUF_MAX = 65536; // верхняя граница (защита от гигантских буферов)
|
||||||
PLUTO_TX_OFF = -89.75; // макс. аттенюация AD9361 — TX практически выключен
|
PLUTO_TX_OFF = -89.75; // макс. аттенюация AD9361 — TX практически выключен
|
||||||
|
|
||||||
type
|
type
|
||||||
@@ -285,6 +290,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TxBufPairsForRate(Rate: Integer): Integer;
|
||||||
|
// Размер TX-буфера в IQ-парах под device-rate (как SoapyPlutoSDR): round(rate/60)
|
||||||
|
// округлённое вверх до степени 2, с клампом [TX_BUF_MIN..TX_BUF_MAX].
|
||||||
|
// 576k→16384, 1536k→32768, 3072k→65536.
|
||||||
|
var
|
||||||
|
Target, P: Integer;
|
||||||
|
begin
|
||||||
|
Target := (Rate + 30) div 60; // round(rate/60)
|
||||||
|
P := TX_BUF_MIN;
|
||||||
|
while P < Target do P := P shl 1; // следующая степень 2 ≥ Target
|
||||||
|
if P < TX_BUF_MIN then P := TX_BUF_MIN;
|
||||||
|
if P > TX_BUF_MAX then P := TX_BUF_MAX;
|
||||||
|
Result := P;
|
||||||
|
end;
|
||||||
|
|
||||||
function PlutoSyntheticMAC(const S: string): TBytes;
|
function PlutoSyntheticMAC(const S: string): TBytes;
|
||||||
var
|
var
|
||||||
H: QWord;
|
H: QWord;
|
||||||
@@ -323,8 +343,10 @@ begin
|
|||||||
FTxBuf := nil; FTxChI := nil; FTxChQ := nil; FTxThread := nil;
|
FTxBuf := nil; FTxChI := nil; FTxChQ := nil; FTxThread := nil;
|
||||||
FTxStreaming := False; FTxRatio := 8; FTxPrevI := 0; FTxPrevQ := 0;
|
FTxStreaming := False; FTxRatio := 8; FTxPrevI := 0; FTxPrevQ := 0;
|
||||||
FTxAttDb := PLUTO_TX_OFF; // на старте TX выключен (макс. аттенюация)
|
FTxAttDb := PLUTO_TX_OFF; // на старте TX выключен (макс. аттенюация)
|
||||||
// FIFO на ~4 TX-буфера запаса под джиттер продюсера/консьюмера.
|
// FIFO на ~4 TX-буфера запаса под джиттер продюсера/консьюмера. Окончательный
|
||||||
FTxFifoCap := TX_BUF_PAIRS * 2 * 4;
|
// размер выставляется в StartTX по фактическому device-rate (TxBufPairsForRate).
|
||||||
|
FTxBufPairs := TxBufPairsForRate(FSampleRate);
|
||||||
|
FTxFifoCap := FTxBufPairs * 2 * 4;
|
||||||
SetLength(FTxFifo, FTxFifoCap);
|
SetLength(FTxFifo, FTxFifoCap);
|
||||||
FTxFifoHead := 0; FTxFifoTail := 0; FTxFifoCount := 0;
|
FTxFifoHead := 0; FTxFifoTail := 0; FTxFifoCount := 0;
|
||||||
InitCriticalSection(FTxLock);
|
InitCriticalSection(FTxLock);
|
||||||
@@ -645,10 +667,14 @@ begin
|
|||||||
FTxRatio := FSampleRate div TX_SRC_RATE;
|
FTxRatio := FSampleRate div TX_SRC_RATE;
|
||||||
if FTxRatio < 1 then FTxRatio := 1;
|
if FTxRatio < 1 then FTxRatio := 1;
|
||||||
FTxPrevI := 0; FTxPrevQ := 0;
|
FTxPrevI := 0; FTxPrevQ := 0;
|
||||||
|
// Размер push-буфера под текущий rate + FIFO на ~4 таких буфера запаса.
|
||||||
|
FTxBufPairs := TxBufPairsForRate(FSampleRate);
|
||||||
EnterCriticalSection(FTxLock);
|
EnterCriticalSection(FTxLock);
|
||||||
|
FTxFifoCap := FTxBufPairs * 2 * 4;
|
||||||
|
if Length(FTxFifo) <> FTxFifoCap then SetLength(FTxFifo, FTxFifoCap);
|
||||||
FTxFifoHead := 0; FTxFifoTail := 0; FTxFifoCount := 0;
|
FTxFifoHead := 0; FTxFifoTail := 0; FTxFifoCount := 0;
|
||||||
LeaveCriticalSection(FTxLock);
|
LeaveCriticalSection(FTxLock);
|
||||||
FTxBuf := iio_device_create_buffer(FTxDev, TX_BUF_PAIRS, False);
|
FTxBuf := iio_device_create_buffer(FTxDev, FTxBufPairs, False);
|
||||||
if FTxBuf = nil then begin FLastError := 'TX create_buffer failed'; Exit; end;
|
if FTxBuf = nil then begin FLastError := 'TX create_buffer failed'; Exit; end;
|
||||||
ApplyTxAtten; // стартуем с текущей аттенюации (по умолчанию OFF до PTT)
|
ApplyTxAtten; // стартуем с текущей аттенюации (по умолчанию OFF до PTT)
|
||||||
FTxStreaming := True;
|
FTxStreaming := True;
|
||||||
|
|||||||
Reference in New Issue
Block a user