sdr_sxceiver: add DC offset correction support
Some checks failed
/ build-hamnet70 (push) Failing after 16s
/ build-doc (push) Successful in 18s
/ deploy-doc (push) Has been skipped

The samples are now split into blocks. The offset is corrected on
each block before it is given to SoapySX for transmission or
corrected after reception of a block from SoapySX. This ensures
there are no huge spikes in CPU usage and therefore delays when a
lot of samples should be transferred at once.
This commit is contained in:
Thomas Kolb 2025-10-26 19:05:34 +00:00
commit 052f5d4612
2 changed files with 77 additions and 16 deletions

View file

@ -70,4 +70,14 @@
#define SDR_GAIN_RX_LNA 30.0f // RF variable gain amplifier.
#define SDR_GAIN_RX_VGA 24.0f // Baseband variable gain amplifier.
// Offset compensation (these values will be subtracted from all samples).
// These generally depend on the gain settings above and need to be adjusted
// when the gain is changed.
#define SDR_TX_OFFSET_I 0.000000f
#define SDR_TX_OFFSET_Q 0.000000f
#define SDR_RX_OFFSET_I 0.000000f
#define SDR_RX_OFFSET_Q 0.000000f
#endif // CONFIG_H

View file

@ -198,7 +198,7 @@ result_t sdr_init(sdr_ctx_t *ctx)
// set up and start RX
// set gains
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "PGA", SDR_GAIN_RX_PGA) != 0) {
/*if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "PGA", SDR_GAIN_RX_PGA) != 0) {
LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
}
@ -206,6 +206,11 @@ result_t sdr_init(sdr_ctx_t *ctx)
if(SoapySDRDevice_setGainElement(ctx->sdr, SOAPY_SDR_RX, 0, "LNA", SDR_GAIN_RX_LNA) != 0) {
LOG(LVL_ERR, "setGainElement fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
}*/
if(SoapySDRDevice_setGain(ctx->sdr, SOAPY_SDR_RX, 0, SDR_GAIN_RX) != 0) {
LOG(LVL_ERR, "setGain fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
}
if(SoapySDRDevice_activateStream(ctx->sdr, ctx->rx_stream, 0, 0, 0) != 0) {
@ -292,15 +297,38 @@ result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamp
flags |= SOAPY_SDR_HAS_TIME;
}
void *buffs[] = {(void*)(samples)};
const size_t BLOCK_SIZE = 4096;
float complex tx_block[BLOCK_SIZE];
int ret = SoapySDRDevice_writeStream(ctx->sdr, ctx->tx_stream, (const void* const*)buffs, nsamples, &flags, time_ns, timeout_us);
size_t samples_transmitted = 0;
if(ret <= 0) {
LOG(LVL_ERR, "writeStream fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
} else if(ret != nsamples) {
LOG(LVL_WARN, "writeStream() did not transmit all samples: %i/%zu", ret, nsamples);
while(samples_transmitted < nsamples) {
size_t samples_remaining = nsamples - samples_transmitted;
size_t block_samples = BLOCK_SIZE;
if(samples_remaining < BLOCK_SIZE) {
block_samples = samples_remaining;
}
const float complex *block_start = samples + samples_transmitted;
for(size_t i = 0; i < block_samples; i++) {
tx_block[i] = block_start[i] - (SDR_TX_OFFSET_I + I * SDR_TX_OFFSET_Q);
}
void *buffs[] = {(void*)(tx_block)};
int64_t block_time = time_ns + samples_transmitted * 1000000000LL / SDR_TX_SAMPLING_RATE;
int ret = SoapySDRDevice_writeStream(ctx->sdr, ctx->tx_stream, (const void* const*)buffs, block_samples, &flags, block_time, timeout_us);
if(ret <= 0) {
LOG(LVL_ERR, "writeStream fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
} else if((size_t)ret != block_samples) {
LOG(LVL_WARN, "writeStream() did not transmit all samples: %i/%zu", ret, block_samples);
}
samples_transmitted += ret;
}
return OK;
@ -313,18 +341,41 @@ result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, l
return ERR_INVALID_STATE;
}
void *buffs[] = {(void*)samples};
const size_t BLOCK_SIZE = 4096;
float complex rx_block[BLOCK_SIZE];
long long timeNs;
int flags;
int ret = SoapySDRDevice_readStream(ctx->sdr, ctx->rx_stream, (void* const*)buffs, *nsamples, &flags, &timeNs, timeout_us);
size_t samples_received = 0;
if(ret <= 0) {
LOG(LVL_ERR, "readStream fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
while(samples_received < *nsamples) {
size_t samples_remaining = *nsamples - samples_received;
size_t block_samples = BLOCK_SIZE;
if(samples_remaining < BLOCK_SIZE) {
block_samples = samples_remaining;
}
void *buffs[] = {(void*)(rx_block)};
long long timeNs;
int flags;
int ret = SoapySDRDevice_readStream(ctx->sdr, ctx->rx_stream, (void* const*)buffs, block_samples, &flags, &timeNs, timeout_us);
if(ret <= 0) {
LOG(LVL_ERR, "readStream fail: %s", SoapySDRDevice_lastError());
return ERR_SOAPY;
} else if((size_t)ret != *nsamples) {
LOG(LVL_WARN, "readStream() did not receive all requested samples: %i/%zu", ret, block_samples);
}
float complex *block_start = samples + samples_received;
for(size_t i = 0; i < (size_t)ret; i++) {
block_start[i] = rx_block[i] - (SDR_RX_OFFSET_I + I * SDR_RX_OFFSET_Q);
}
samples_received += ret;
}
*nsamples = ret;
*nsamples = samples_received;
return OK;
}