I’m writing a Soapy SDR plugin for the FL2K-SDR. Soapy SDR expects plugins to produce and consume IQ samples. However, the FL2K-SDR driver consumes only real samples. I know you can convert a real signal to a complex signal using a Hilbert transform. How do I convert IQ samples to real samples? Do I use an inverse Hilbert transform? Do I just drop every other sample to get only the I samples? One of my goals is to minimize the processing latency of this plugin (I.e. use lookup tables if possible).

Part of my quandary is that I don't know how the user is going to configure their flow-graph. They may:

  • Simply feed me a complex cosine and expect some sort of real cosine output.
  • Sample the PC microphone, convert that to a complex signal, and send that to me (no modulation involved).
  • Attach an analog low-pass filter (~ 70 MHz), do their modulation in their flow-graph, and use the FL2K USB VGA dongle for an HF Ham radio transmitter
  • Generate an IF in their flow graph, and then attach an analog band-pass filter to transmit an image frequency higher than 70 MHz.

Unfortunately, I don't know which of these they might do.

  • $\begingroup$ where that complex baseband comes from or what it represents makes absolutely no difference – as with any other SDR device, it's up to the user to define: 1. the sampling rate of their signal and 2. the target frequency. $\endgroup$ Jan 17, 2020 at 17:47

2 Answers 2


So the point is that "classically", communications theory tends to be done in complex baseband, i.e. signals centered around 0 Hz, but not necessarily symmetric in spectrum.

When you want to represent such signals, you need complex values. When you want to transmit such signals over the air, you need to:

  1. Convert them from digital to analog,
  2. mix the I(nphase) and Q(uadrature) components with the carrier (say, a cosine) and a 90° shifted version of the carrier, respectively,
  3. and add up the result.

Since I and Q themselves are just real values, the result of 3. is just a real signal.

Now, if you do the above in the order that I've written it in, then you need two DACs running in step at the baseband sampling rate, and you can produce any RF frequency that the carrier synthesizer can generate.

But, you don't have to do it in the order 1., 2. and last 3.: You can also first digitally upsample to a higher sampling rate, then multiply the complex baseband signal with a complex sinusoid of frequency $f_\text{IF}$ to move it up to an intermediate frequency, and just discard the imaginary part of the signal. Then, you DAC just that real signal.

You could then use an LO of frequency $f_\text{carrier}-f_\text{IF}$ to move it to the final carrier frequency. But:

The FL2K is just a DAC. So it doesn't have a mixer. So you can't do that.

However, every DAC produces images at multiples of the sampling rate (that's why you always need an analog reconstruction filter, which classically is a low-pass cutting off at half the sampling rate). So, if, say your IF is $f_\text{IF}=10\,\text{MHz}$ and your sampling rate is 50 MHz, then you can produce a signal at 210 MHz simply by not low-passing the output of the DAC to below 25 MHz, but bandpassing for say 200-220 MHz.

  • $\begingroup$ Thanks for the answer. I've learned some. However, it sounds like all the options you've presented assume that the user wands to accomplish some sort of modulation or frequency shift. I've edited my question to show that I can't even be sure that that's what they want to do. What would you expect of a general-purpose plugin which takes complex samples and feeds a real DAC? $\endgroup$
    – watkipet
    Jan 17, 2020 at 17:38
  • $\begingroup$ So, as said, the user will give you complex baseband, and in any case, that means you need to convert that to a real passband signal. So, there's really no problem here – as with any other SDR device, the user needs to specify 1. their signal's sampling rate, 2. the target frequency (in your case, $f_\text{IF}$). $\endgroup$ Jan 17, 2020 at 17:45
  • $\begingroup$ Suppose the user wants $\left\{f_\text{IF} = e^{j\left(\omega_\text{IF}t+\phi_\text{IF} \right)} \mathrel{}\middle|\mathrel{} w_\text{IF} = 0, \phi_\text{IF} = 0 \right\}$. i.e., they don't want to frequency shift the output. Then, using the digital method you described, wouldn't I just be 1) up-sampling the signal, 2) multiplying by $1$, and 3) dropping the quadrature part of the signal? Is that what's expected? $\endgroup$
    – watkipet
    Jan 22, 2020 at 17:12
  • 1
    $\begingroup$ If the user wants zero IF, they can't be providing you with a complex signal; that mathematically makes no sense. $\endgroup$ Jan 22, 2020 at 17:25
  • $\begingroup$ @watkipet, try reading about "analytic signal", you need to frequency shift your complex baseband signal for it to become an analytic signal before you can convert it to a real signal. $\endgroup$
    – axk
    Jan 22, 2020 at 17:58

Let us assume a baseband complex sampled noisy signal with a power spectrum as depicted below: enter image description here

The signal spectrum is depicted with a notch to emphasize that it is complex and therefore not conjugate symmetric. The noise is depicted as white with double-sided power spectral density of $\frac{N_0}{2}$. The filter necessary to create the complex signal in the first place is also depicted.

To reconstruct the real signal, the spectrum must be conjugate symmetric. This means that the spectrum shown represents only the upper (or lower) sideband of the real signal. To reconstruct, we must upsample by two, shift this spectrum up in frequency, then also flip it and shift it down in frequency, adding the results together.

First, we need to upsample and low pass filter so as to create a signal that will not alias when shifted in frequency. To do that, we simply add a zero between every sample, then low-pass filter the signal with cut-off $\omega_c=\frac{\pi}{2}$. This creates a spectrum that now looks like below: enter image description here

Because modulation in the time domain is a shift in the frequency domain, we can now simply multiply the complex signal by $e^{j\omega n}$, where $\omega$ is nominally $\frac{\pi}{2}$. Conjugation in the time domain is a reversal in the frequency domain, so we will also multiply the conjugated signal by $e^{-j\omega n}$ to shift the flipped spectrum to the left. After adding the two results together, the spectrum now looks like below: enter image description here

And you have your real sampled signal back. Any residual imaginary component is just rounding error, so it should simply be thrown out.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.