pothosware / SoapyAirspyHF

SoapySDR plugin to support the Airspy HF+
https://github.com/pothosware/SoapyAirspyHF/wiki
MIT License
24 stars 17 forks source link

Support more sample formats by using ConverterRegistry #18

Closed antonblanchard closed 4 years ago

antonblanchard commented 4 years ago

The SoapyAirspyHF driver only supports CF32 samples. The ConverterRegistry gives us CS16, CS8, CU16 and CU8.

antonblanchard commented 4 years ago

I haven't found an example of using ConverterRegistry anywhere, but here is an attempt to add it to the AirspyHF driver. Thoughts?

antonblanchard commented 4 years ago

I tested this by dumping various sample formats for a local WBFM station and verifying I could demodulate it in gqrx:

# CF32
rx_sdr -f 105.7M -s 768000 -I CF32 -F CF32 test-cf32.out & sleep 10 && killall rx_sdr
cp test-cf32.out test-cf32-processed.out

# CS16
rx_sdr -f 105.7M -s 768000 -I CS16 -F CS16 test-cs16.out & sleep 10 && killall rx_sdr
sox -t raw -e signed-integer -b 16 -c 2 -r 768000 test-cs16.out -t raw -e floating-point -b 32 -c 2 -r 768000 test-cs16-processed.out

# CS8
rx_sdr -f 105.7M -s 768000 -I CS8 -F CS8 test-cs8.out & sleep 10 && killall rx_sdr
sox -t raw -e signed-integer -b 8 -c 2 -r 768000 test-cs8.out -t raw -e floating-point -b 32 -c 2 -r 768000 test-cs8-processed.out

# CU8
rx_sdr -f 105.7M -s 768000 -I CU8 -F CU8 test-cu8.out & sleep 10 && killall rx_sdr
sox -t raw -e unsigned-integer -b 8 -c 2 -r 768000 test-cu8.out -t raw -e floating-point -b 32 -c 2 -r 768000 test-cu8-processed.out
antonblanchard commented 4 years ago

I'm not sure I follow. The default CF32 to CS16 converter does scale:

const uint16_t S16_FULL_SCALE = uint16_t(1<<15);

...

inline int16_t F32toS16(float from){
  return int16_t(from * S16_FULL_SCALE);
}

...

// CF32 <> CS16
static void genericCF32toCS16(const void *srcBuff, void *dstBuff, const size_t numElems, const double scaler)
{
  const size_t elemDepth = 2;

  auto *src = (float*)srcBuff;
  auto *dst = (int16_t*)dstBuff;
  for (size_t i = 0; i < numElems*elemDepth; i++)
    {
      dst[i] = SoapySDR::F32toS16(src[i] * scaler);
    }
}

So full scale CF32 (1.0) should map to full scale CS16 (2^15). Actually that makes me wonder if we have a corner case in the converter. If the device can return 1.0 that will map to -32768 for this specific case. Very unlikely I know.

guruofquality commented 4 years ago

your right, scaling looks good nevermind.

If the device can return 1.0 that will map to -32768 for this specific case. Very unlikely I know.

We made a decision to map floating point and fixed point values with a linear symmetric scaling. Which means the floating point range is just like the fixed point range, so you can have -1.0 inclusive, but you cant have 1.0 (which is exclusive). But you know, its probably one of those debatable trade off things just like rounding modes.

antonblanchard commented 4 years ago

@guruofquality thanks for the explanation, that makes sense.