sdr: fix loss of samples due to unaligned buffer reads
sdr_rf_to_baseband() processes samples in blocks of size SDR_OVERSAMPLING. If the total number of samples does not align with this block size, the leftover samples are lost and phase and timing glitches result. To mitigate this, sdr_receive() now has an additional parameter that specifies the alignment of the returned data. The number of samples returned is always a multiple of this alignment factor. This feature is used to ensure that the number of returned samples is a multiple of SDR_OVERSAMPLING and therefore no samples are lost in sdr_rf_to_baseband(). sdr_rf_to_baseband() now has an additional check that makes the function fail if the alignment is incorrect.
This commit is contained in:
parent
a3928d0ad0
commit
c6ea578808
|
@ -330,7 +330,7 @@ int main(int argc, char **argv)
|
||||||
size_t n_rf_samples = CHUNKSIZE_RF;
|
size_t n_rf_samples = CHUNKSIZE_RF;
|
||||||
size_t n_bb_samples = CHUNKSIZE_BB;
|
size_t n_bb_samples = CHUNKSIZE_BB;
|
||||||
|
|
||||||
if(sdr_receive(&sdr, rf_samples, &n_rf_samples, 100000) != OK) {
|
if(sdr_receive(&sdr, rf_samples, &n_rf_samples, 100000, SDR_OVERSAMPLING) != OK) {
|
||||||
rx_retries++;
|
rx_retries++;
|
||||||
fprintf(stderr, "sdr_receive() failed %d times.\n", rx_retries);
|
fprintf(stderr, "sdr_receive() failed %d times.\n", rx_retries);
|
||||||
if(rx_retries >= 3) {
|
if(rx_retries >= 3) {
|
||||||
|
|
|
@ -4,8 +4,9 @@
|
||||||
typedef enum {
|
typedef enum {
|
||||||
OK,
|
OK,
|
||||||
ERR_INVALID_STATE,
|
ERR_INVALID_STATE,
|
||||||
ERR_NO_MEM,
|
ERR_INVALID_PARAM, // invalid / nonsense parameters given
|
||||||
ERR_SIZE,
|
ERR_NO_MEM, // not enough memory or allocation error
|
||||||
|
ERR_SIZE, // a given size is invalid
|
||||||
ERR_LIQUID, // an error occurred in the LiquidDSP library.
|
ERR_LIQUID, // an error occurred in the LiquidDSP library.
|
||||||
ERR_SYSCALL, // a syscall failed. Use errno to determine the cause.
|
ERR_SYSCALL, // a syscall failed. Use errno to determine the cause.
|
||||||
ERR_SOAPY, // an error occurred in the SoapySDR library.
|
ERR_SOAPY, // an error occurred in the SoapySDR library.
|
||||||
|
|
|
@ -313,7 +313,7 @@ result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us)
|
result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us, size_t alignment)
|
||||||
{
|
{
|
||||||
(void)timeout_us; // not implemented yet
|
(void)timeout_us; // not implemented yet
|
||||||
|
|
||||||
|
@ -324,6 +324,16 @@ result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, l
|
||||||
return ERR_SDR;
|
return ERR_SDR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure that an aligned number of bytes is read from the buffer in any case.
|
||||||
|
if(alignment > 1) {
|
||||||
|
unsigned int samples_avail = cbuffercf_size(ctx->rx_buf);
|
||||||
|
if(samples_avail < *nsamples) {
|
||||||
|
*nsamples = samples_avail - (samples_avail % alignment);
|
||||||
|
} else {
|
||||||
|
*nsamples -= *nsamples % alignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned int samples_read;
|
unsigned int samples_read;
|
||||||
float complex *buf_samples;
|
float complex *buf_samples;
|
||||||
result = cbuffercf_read(ctx->rx_buf, *nsamples, &buf_samples, &samples_read);
|
result = cbuffercf_read(ctx->rx_buf, *nsamples, &buf_samples, &samples_read);
|
||||||
|
@ -425,6 +435,11 @@ result_t sdr_rf_to_baseband(sdr_ctx_t *ctx,
|
||||||
const float complex *rf_samples, size_t nrf,
|
const float complex *rf_samples, size_t nrf,
|
||||||
float complex *bb_samples, size_t *nbb)
|
float complex *bb_samples, size_t *nbb)
|
||||||
{
|
{
|
||||||
|
if((nrf % SDR_OVERSAMPLING) != 0) {
|
||||||
|
fprintf(stderr, "sdr_rf_to_baseband: the given number of RF samples (%zd) is not a multiple of SDR_OVERSAMPLING (%d).\n", nrf, SDR_OVERSAMPLING);
|
||||||
|
return ERR_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
if((*nbb * SDR_OVERSAMPLING) < nrf) {
|
if((*nbb * SDR_OVERSAMPLING) < nrf) {
|
||||||
fprintf(stderr, "sdr_rf_to_baseband: result would not fit in output: %zd * %d < %zd\n", *nbb, SDR_OVERSAMPLING, nrf);
|
fprintf(stderr, "sdr_rf_to_baseband: result would not fit in output: %zd * %d < %zd\n", *nbb, SDR_OVERSAMPLING, nrf);
|
||||||
return ERR_SIZE;
|
return ERR_SIZE;
|
||||||
|
|
|
@ -45,7 +45,20 @@ result_t sdr_stop_rx(sdr_ctx_t *ctx);
|
||||||
result_t sdr_stop_tx(sdr_ctx_t *ctx);
|
result_t sdr_stop_tx(sdr_ctx_t *ctx);
|
||||||
|
|
||||||
result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, long timeout_us);
|
result_t sdr_transmit(sdr_ctx_t *ctx, const float complex *samples, size_t nsamples, long timeout_us);
|
||||||
result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us);
|
|
||||||
|
/*!
|
||||||
|
* \brief Read samples from the SDR device.
|
||||||
|
*
|
||||||
|
* \param ctx The SDR device context to use.
|
||||||
|
* \param samples Pointer to the output array.
|
||||||
|
* \param nsamples Pointer to the number of samples requested. Will be
|
||||||
|
* adjusted to the number of samples actually read.
|
||||||
|
* \param timeout_us Read timeout in microseconds (currently unused).
|
||||||
|
* \param alignment If greater than 1, the number of returned samples will be
|
||||||
|
* adjusted such that it is divisable by this number.
|
||||||
|
* \returns The result code of the read operation.
|
||||||
|
*/
|
||||||
|
result_t sdr_receive(sdr_ctx_t *ctx, float complex *samples, size_t *nsamples, long timeout_us, size_t alignment);
|
||||||
|
|
||||||
result_t sdr_flush_tx_buffer(sdr_ctx_t *ctx);
|
result_t sdr_flush_tx_buffer(sdr_ctx_t *ctx);
|
||||||
size_t sdr_get_tx_buffer_free_space(sdr_ctx_t *ctx);
|
size_t sdr_get_tx_buffer_free_space(sdr_ctx_t *ctx);
|
||||||
|
|
Loading…
Reference in a new issue