Recovering x(t) from IQ samples

If my i(t) and q(t) samples are defined as follows:

i(t) = x(t) * sin(wt)
q(t) = x(t) * cos(wt)

then, given i(t) and q(t), I can recover the magnitude of x(t) as
follows:

|x(t)| = sqrt(i^2(t) + q^2(t))

But how can I recover the sign of x(t)? For each of the four possible
combinations of the signs of i(t) and q(t), x(t) could be either
positive or negative.

Thanks.

I supposed I can reconstruct a virtual local oscillator by looking at
the zero crossings and syncing a sine generator to that and then using
the sine generator to determine the sign (making it a sign generator
;-P). Then my entire waveform might be inverted, but that is probably
not much of a concern (at least for my needs).

Please tell me there is a better way.

Bahn William L Civ USAFA/DFCS wrote:

Please tell me there is a better way.

I didn’t follow the start of this thread, but can you reiterate what
you’re trying to accomplish, vs. alternative ways of getting there? It
does seem like things are getting overcomplicated, and some times it’s
useful to go back to a high-level description of the problem.


Johnathan C.
Corgan Enterprises LLC
http://corganenterprises.com

William-

I supposed I can reconstruct a virtual local oscillator by looking at
the zero crossings and syncing a sine generator to that and then using
the sine generator to determine the sign (making it a sign generator ;-P).
Then my entire waveform might be inverted, but that is probably not much
of a concern (at least for my needs).

Please tell me there is a better way.

If I recall, you’re trying to use the USRP as a high speed data
acquisition board and
do some processing on another (external) FPGA or DSP board, is that
correct? With
which daughtercard? If it’s one of the basic daughtercards that doesn’t
downshift,
then you could modify FPGA logic to not multiply I data. I haven’t
looked closely,
but it should be straightforward in the Verilog source to go around that
step.

If you’re using one of the daughtercards that downshifts prior to A/D
then my
understanding is you have to deal with I-Q data.

-Jeff

Just a quick answer - I hope I understood your problem correctly this
time.

On Fri, Aug 17, 2007 at 05:23:06PM -0600, Bahn William L Civ USAFA/DFCS
wrote:

I’m asking the question for several reasons - some theoretical and others practical. The basic driving force is as follows:

I have the following processing chain:

BBC -> FILE -> GR -> USRP -> RF -> USRP -> GR -> FILE -> BBC

[file format of input and output should be equal]

This raises the following questions:

Q1) One of the formats in which I can send data to the USRP is as IQ data. What does the USRP do with IQ data pairs? In the USRP documentation there is a block diagram of the Digital Down Converter, but there is no diagram of the Digital Up Converter.

It is exactly the opposite of the DDC. The fundamental concept here is
that
sine and cosine are orthogonal, i.e., one can transmit a (“real”) valued
signal modulated by a sine and, at the same time, transmit another
(“real”) signal modulated by a cosine. Just add them up
and seperate them by demodulation (and filtering) in the receiver.

This should answer your question: if you’re just concerned with
transmission of the data, you can divide your input stream
into 2 streams and transmit one over I and the other over the Q branch.
You might want to preprocess your signal and transmit it digitally,
though (to add channel coding, synch frame etc.).

If you’re looking at a radar/sonar application or simple AM, you
probably just want one carrier. Leave the I or Q branch blank.

Regards,
Jens

From: Johnathan C. [mailto:[email protected]]

Bahn William L Civ USAFA/DFCS wrote:

Please tell me there is a better way.

I didn’t follow the start of this thread, but can you reiterate what
you’re trying to accomplish, vs. alternative ways of getting there? It
does seem like things are getting overcomplicated, and some times it’s
useful to go back to a high-level description of the problem.

Sure - that sounds like a good idea.

I’m asking the question for several reasons - some theoretical and
others practical. The basic driving force is as follows:

I have the following processing chain:

BBC → FILE → GR → USRP → RF → USRP → GR → FILE → BBC

SENDER:

  1. An external program (called BBC) takes messages from the user and
    produces the waveform data that we want to transmit from the sender to
    the receiver.
  2. The data is written to a file in a format that GNU Radio can read.
  3. GNU Radio reads the data from the file and sends it to the USRP.
  4. The USRP upconverts it and transmits it via RF.
  5. The (other) USRP receives the RF signal, downconverts it, and sends
    the data to GNU Radio.
  6. GNU Radio receives the data from the USRP and writes it to a file.
  7. The BBC program reads the data file and extracts the messages.

It would be very nice if the two files, the one being read by GNU Radio
and the one being written by GNU Radio, used the same format. If I
leverage the existing usrp_rx_cfile.py program, then the data written by
GR is in IQ data pairs and BBC will need to convert this to a stream of
real-valued data samples. Conversely, BBC will need to convert the
real-valued data stream that it generates into IQ data before writing it
to the file that GR will later read and transmit via the USRP.

This raises the following questions:

Q1) One of the formats in which I can send data to the USRP is as IQ
data. What does the USRP do with IQ data pairs? In the USRP
documentation there is a block diagram of the Digital Down Converter,
but there is no diagram of the Digital Up Converter.

Q2) If I have x(t) data (just time-domain data samples that have been
generated by an external program that is completely unrelated to GNU
Radio) that I want to transmit, how do I convert it to the necessary IQ
data? What frequency do I use in the calculations?

Q3) Given a stream of IQ data pairs, how do I convert them to plain-ole
vanilla x(t) time-domain samples?

Supposedly, as near as I can tell, there is a direct equivalency between
data represented as time-domain samples and the same data represented as
IQ data pairs. Is this true? If so, then it should be possible to
convert back and forth between the two representations? Is this the
case?

Here is what I see from where I am sitting:

There is a time domain signal at the front of the Digital Down Converter
(DDC) in the USRP that I will call x(t). This signal (assuming the same
signal is applied to both DDC inputs) follows two paths to produce the
i(t) and q(t) samples that are delivered to the user over the USB
interface.

Therefore the relationship between x(t), the signal that I am interested
in, and the i(t) and q(t) samples that I actually get to see are:

i(t) = x(t) * sin(wt)
q(t) = x(t) * cos(wt)

Now, I know that there is also the decimation low pass filter which, up
to this point, I have been ignoring but may actually hold the key. I
don’t know.

Assuming that x(t) has no frequency components that are going to get
aliased, how do I recover x(t) from the i(t) and q(t) samples?

Several people have responded, some to the list and some to me
privately, that you just treat i(t) and q(t) and the components of a
complex number and use the four-quadrant arctangent function. Typical of
these responses has been:

=====================================================
Interpret I and Q as real and imaginary part of a complex number:

R = I + jQ.

Then |R| = sqrt(I^2 + Q^2) and ang(R) = atan2(imag(z),real(z)), where
“atan2” (four-quadrant inverse tangent, a Matlab function, to get the
signs right).

You’re simply looking for magnitude and phase (angle) of a complex
number.

But that doesn’t work because there is, as I am looking at things, a
fundamental sign ambiguity involved. I tried to make that clear in my
original post and obviously failed to do so, hence I will be explicit in
my reasoning here. If I am wrong at some step, perhaps someone can spot
it and point it out.

First off, R is not the x(t) I am looking for. R is a complex sequence.
So unless there is an unambiguous mapping between R and x(t), then it
doesn’t help.

Second, the closest mapping is not R = I + jQ, but rather R = Q + jI. To
see this, consider:

Z(t) = x(t) * e^(jwt)

Z(t) = x(t) * (cos(wt) + j*sin(wt))

Z(t) = x(t)cos(wt) + jx(t)*sin(wt)

Z(t) = q(t) + j*i(t)

Now, finding the magnitude of x(t) is very straightforward since:

|Z(t)| = sqrt(q^2(t)+i^2(t))

|Z(t)| = sqrt(x^2(t)*cos^2(wt) + x^2(t)*sin^2(t))

|Z(t)| = sqrt(x^2(t)*[cos^2(wt) + sin^2(t)])

|Z(t)| = sqrt(x^2(t)*[cos^2(wt) + sin^2(t)])

|Z(t)| = sqrt(x^2(t))

|Z(t)| = |x(t)|

Fine so far, but now I need to determine if x(t) is positive or
negative.

IF I know what the phase of (wt) is, then I can trivially determine the
sign of x(t). A couple of responses I have gotten basically tell me to
use this information even though the original post specifically stated
that all I have are the i(t) and q(t) data.

What people keep suggesting is to use the four-quadrant arctangent, but
the problem is that knowing which quadrant an i(t),q(t) data pair is in
does not tell me which quadrant (wt) is in. It only allows me to
determine which of two possible quadrants (wt) is in and I need to know
the sign of x(t) in order to distinguish between them.

phi(Z(t)) = atan2(q(t), i(t))

phi(Z(t)) = atan2(x(t)*cos(wt), x(t)*sin(wt))

As a specific example of this ambiguity, let’s say that sample number
34765 yields the following for i(t) and q(t) at that point:

i(34765) = 0.500
q(34765) = 0.866

What is x(34765)?

Well, if (w*34765) = 30 deg, then we have the following:

x(t) = 1.0
wt = 30 degrees
sin(wt) = 0.500
cos(wt) = 0.866
i(t) = 0.500
q(t) = 0.866

But if (w*34765) = 210 deg, then we have:

x(t) = -1.0
wt = 210 degrees
sin(wt) = -0.500
cos(wt) = -0.866
i(t) = 0.500
q(t) = 0.866

So the problem remains: Given only the i(t) and q(t) samples, which is
all the USRP gives back, how do I reconstruct x(t)?

On Sat, 18 Aug 2007, Jens E. wrote:

On Fri, Aug 17, 2007 at 05:23:06PM -0600, Bahn William L Civ USAFA/DFCS wrote:

Q1) One of the formats in which I can send data to the USRP is as IQ data. What does the USRP do with IQ data pairs? In the USRP documentation there is a block diagram of the Digital Down Converter, but there is no diagram of the Digital Up Converter.

It is exactly the opposite of the DDC. …

I’m not sure if this is pertinent for your project, but there is code
that does just this in the FPGA, in the MRFM project in GNU Radio. This
is not the usual FPGA code that runs in the USRP, but it can run in the
USRP. This code implements the block diagram at

http://www.research.cornell.edu/KIC/events/MRFM2006/pdfs/Jacky%20talk/jacky-talk.html

in the slide labelled Heterodyne control. The block labelled DUC does
the upconversion, reconstructing x(t) from I and Q.

The DUC in this code is not the DUC used by the usual USRP FPGA code,
which (as I understand it) uses a built-in DUC in the Analog Devices
chip. For our application, we need to synchronize the DDC and DUC
exactly. The only way to do that was to put the DUC in the same FPGA
program as the DDC.

This FPGA code is in the respository at

http://gnuradio.org/trac/browser/gnuradio/trunk/usrp/fpga/toplevel/mrfm

The Verilog code in mrfm_proc.v describes the block diagram discussed
above.

Matt E. wrote this code.

Jon Jacky

So the problem remains: Given only the i(t) and q(t) samples, which is all the USRP gives back, how do I reconstruct x(t)?

Two options:

  1. you need some kind of phase reference (coherent
    demodulation), insert pilot symbols into x(t)

  2. use AM modulation over one carrier only; this requires x(t) to have a
    known maximum amplitude:

Let’s assume x(t) in [-1, 1] and zero mean.

The carrier c(t) = c_0 cos(wt+phi) is used to modulate x(t):

s(t) = ( c_0 + x(t) ) cos(wt+phi) .

This requires c_0 to be greater than 1, otherwise the sign
ambiguity you’ve been talking about occurs.

Please correct me if I’m mistaken. All in all it would be best to know
what this BBC application is supposed to do.

Regards,
Jens

Hello list,
I have recently changed the USRP clock with an external PLL. Then I used
the previously precompiled standard firmware std_4rx_0tx.rbf , using 2
sinusoidal inputs to RXA, RXB and it was confirmed that everything was
working fine. I then downloaded the 3.0.4 version and tried to recompile
the usrp_std project. I used the usrp_std.rbf file produced in the
rx_cfile.py, feeding the RXA, RXB each with a sinusoidal signal and when
I plotted the output I found out that I was getting 0s and -1s only, as
if I was getting clock pulses.

I then used again the std_4rx_0tx.rbf file which resulted in the
expected output (sinusoidal signals at the same frequency) with
amplitudes ranging from -15500 to 15500. .
I then used another firmware which actually produces known data from
within the rx_buffer.v file, (a signal that cycles from 0 to 15 and back
to 0) and the output was as expected again, linear increase from 0 to 15
and then back to 0.
I then tried other versions of the firmware that there were working, as
Peter M.'s variable width and shift firmware, but again I was getting
values almost down to 0.

Does anyone has an idea what might be wrong? Why do some .rbfs working
and some not?

Thank you

Rigas

Jon-

implements the block diagram at
This FPGA code is in the respository at

http://gnuradio.org/trac/browser/gnuradio/trunk/usrp/fpga/toplevel/mrfm

The Verilog code in mrfm_proc.v describes the block diagram discussed above.

Yes – if you can exactly synchronize another complex multiply with the
first one, then there is no ambiguity. Just
like FFT/iFFT. But so far William is trying to avoid programming the
FPGA. I’ve already pointed out that if he’s
willing to do this, then he can disable the downshift (complex multiply)
and not have to deal with I-Q data in the
first place. Or, he could modify the host buffer format to include two
data streams, I-Q and original ADC data.

I don’t know why programming the FPGA should look like a black hole.
Verilog is straightforward, Matt’s code is well
structured and seems fairly well commented, there are tons of examples
on Altera’s website, etc. Sometimes I think
people take “do everything in Linux software” to an extreme. There’s a
reason Altera, Xilinx, Texas Inst, sell more
chips every year, even though Intel has tried for 15 years now to create
a world without those guys.

-Jeff

On Sat, 18 Aug 2007, Jeff B. wrote:

I don’t know why programming the FPGA should look like a black hole. Verilog is straightforward, Matt’s code is well
structured and seems fairly well commented, there are tons of examples on Altera’s website, etc. Sometimes I think
people take “do everything in Linux software” to an extreme. There’s a reason Altera, Xilinx, Texas Inst, sell more
chips every year, even though Intel has tried for 15 years now to create a world without those guys.

One of the great strengths of GNU Radio is that it opens
the entire technology stack, from the FPGA all the way up to the GUI.
You can optimize your application across the whole stack, putting each
function where it makes the most sense. This contrasts with the usual
approach where application developers are encouraged put everything in
one layer.

Verilog is no more difficult or mysterious than C++, wxPython, autotools
etc.

Jon Jacky

On 8/20/07, Chris S. [email protected] wrote:

Does it come with a debugger? I’d love to get into it, but things like
learning how to debug/compile/etc are what scare me personally.

Sure, check out Icarus Verilog and GTKWave. You basically write a
testbench to stimulate your inputs, and make sure your outputs toggle
the way they should.

Or if you want to get into non-free software, check out ModelSim.
Both Xilinx and Altera have bundled versions.

With enough proper testing, you should be able to get a good 99%
coverage on all statements and logic - which should be pretty darn
good.

Links:
http://home.nc.rr.com/gtkwave/
http://www.icarus.com/eda/verilog/
http://www.model.com/
http://www.asic-world.com/verilog/art_testbench_writing1.html

Brian

Jonathan Jacky wrote:

Verilog is no more difficult or mysterious than C++, wxPython, autotools
etc.

Does it come with a debugger? I’d love to get into it, but things like
learning how to debug/compile/etc are what scare me personally.

Chris