∿ LEARN DSPFrom signal to HF transceiver
Lab / lesson

A complex number as a vector: I and Q

The two coordinates of one sample, its magnitude, phase and conjugate.

← Quantization

Why we keep two coordinates

In the circle experiment, we recorded only the horizontal coordinate. Points above and below the horizontal axis could give the same cosine value. Now we keep both coordinates. This lets us tell such positions apart, and also tell the directions of rotation apart.

We call the horizontal coordinate II and the vertical coordinate QQ. For example, (I,Q)=(0.8,0.6)(I,Q)=(0.8,0.6) means: 0.8 to the right and 0.6 up.

It is easy to write this pair as one complex number:

z=I+jQ=0.8+j0.6.z=I+jQ=0.8+j0.6.

zz is the name of the full number. It joins the two coordinates; there is no third dimension here. The coefficient of jj is QQ, and the part without jj is II.

The number jj is the imaginary unit. It satisfies j2=−1j^2=-1. This rule defines the arithmetic of complex numbers. Radio engineering uses the letter jj because ii often means current. In Python, the imaginary unit is written as 1j:

z = 0.8 + 1j * 0.6
I = z.real  # 0.8: real part
Q = z.imag  # 0.6: imaginary part

In the figure, the number is shown as a vector from (0,0)(0,0) to (I,Q)(I,Q).

IQ+1−1+1−1Quadrant 1Quadrant 2Quadrant 3Quadrant 4I = 0.500Q = 0.866z = 0.500 + j0.866 · |z| = 1.000 · phase: 60°

Keep the amplitude at 1 and change the angle. At 0∘0^\circ you get (1,0)(1,0) and z=1z=1, at 90∘90^\circ you get (0,1)(0,1) and z=jz=j, at 180∘180^\circ you get (−1,0)(-1,0) and z=−1z=-1.

The four quadrants of the plane

The II and QQ axes divide the plane into four areas, the quadrants. The numbering goes counterclockwise and starts at the upper right:

QuadrantWhere the point isAngle in the quadrantSign of IISign of QQ
1upper right0∘<θ<90∘0^\circ<\theta<90^\circ++
2upper left90∘<θ<180∘90^\circ<\theta<180^\circ−+
3lower left180∘<θ<270∘180^\circ<\theta<270^\circ−−
4lower right270∘<θ<360∘270^\circ<\theta<360^\circ+−

Points on the axes are not in any quadrant. For example, the angle 90∘90^\circ is on the positive QQ axis.

Length, angle and Euler’s formula

For a point on the unit circle, geometry gives I=cos⁡θI=\cos\theta, Q=sin⁡θQ=\sin\theta. The complex number is

z=cos⁡θ+jsin⁡θ.z=\cos\theta+j\sin\theta.

Euler’s formula lets us write it in a shorter form:

ejθ=cos⁡θ+jsin⁡θ.e^{j\theta}=\cos\theta+j\sin\theta.

For now, read ejθe^{j\theta} as: a unit vector at angle θ\theta. If its length is AA, we get

z=Aejθ=Acos⁡θ+jAsin⁡θ.z=Ae^{j\theta}=A\cos\theta+jA\sin\theta.

Why is this form useful? When you multiply two such numbers, their angles add. A rotation by 30∘30^\circ and then by 40∘40^\circ gives a rotation by 70∘70^\circ. In radians, we write it like this:

ejπ/6ej2π/9=ej7π/18.e^{j\pi/6}e^{j2\pi/9}=e^{j7\pi/18}.

This is an example of the property, not a proof of Euler’s formula. For now, we use the formula and check it with the known sin and cos coordinates. This is sufficient for our current experiments.

Degrees and radians

These are two units for the same angle: 360∘=2π360^\circ=2\pi radians.

DegreesRadiansejθe^{j\theta}
0°0011
90°π/2\pi/2jj
180°π\pi−1-1
270°3π/23\pi/2−j-j
360°2π2\pi11

On diagrams, degrees are often easier. In the calculations np.sin(theta), np.cos(theta) and np.exp(1j * theta), the angle theta must be in radians. To convert, we use:

import numpy as np

theta = np.deg2rad(90)       # pi/2
degrees = np.rad2deg(theta)  # 90.0
z = np.exp(1j * theta)      # approximately 0 + 1j

The number 90 without conversion would mean 90 radians.

How to find the length and angle from I/Q

We find the length of the vector (the magnitude of the number) with the Pythagorean theorem:

A=∣z∣=I2+Q2.A=|z|=\sqrt{I^2+Q^2}.

For the angle, we use the function atan2⁡(Q,I)\operatorname{atan2}(Q,I). It uses the signs of both coordinates and selects the correct quadrant. The usual atan⁡(Q/I)\operatorname{atan}(Q/I) loses this information, and when I=0I=0 the division is not possible.

z = 1 + 1j * np.sqrt(3)
amplitude = np.abs(z)                   # 2
phase_rad = np.arctan2(z.imag, z.real)   # pi/3
phase_deg = np.rad2deg(phase_rad)        # 60 degrees

np.angle(z) also returns the angle in radians. The number z=0z=0 has no defined direction: a vector of zero length does not point anywhere.

From one number to a signal

A complex digital signal is a sequence of complex samples:

z[n]=I[n]+jQ[n].z[n]=I[n]+jQ[n].

Each sample contains two real numbers. For example, if the angle increases at a constant rate,

θ[n]=2πfFsn+ϕ,z[n]=Aejθ[n],\theta[n]=2\pi\frac{f}{F_s}n+\phi, \qquad z[n]=Ae^{j\theta[n]},

we get a complex tone: a vector of constant length AA turns at frequency ff. Its coordinates are:

I[n]=Acos⁡θ[n],Q[n]=Asin⁡θ[n].I[n]=A\cos\theta[n],\qquad Q[n]=A\sin\theta[n].

Let f=1f=1 kHz, Fs=8F_s=8 kS/s, A=1A=1, ϕ=0\phi=0. The angle step is 360∘f/Fs=45∘360^\circ f/F_s=45^\circ:

nnAngleI[n]I[n]Q[n]Q[n]z[n]z[n]
00°1011
145°0.7070.7070.707+j0.7070.707+j0.707
290°01jj
3135°−0.7070.707−0.707+j0.707-0.707+j0.707

The II coordinate alone gives a usual cosine. The pair I,QI,Q also shows on which side of the horizontal axis the vector is.

In an I/Q receiver, two matched processing channels give the two coordinates. Their names are in-phase and quadrature: the reference oscillations of the two channels have a 90∘90^\circ shift. It is also possible to calculate I/Q digitally from a sequence of real samples. But one single number x[n]x[n] does not give the unknown coordinate Q[n]Q[n] by itself. We will examine how these chains work later. Now we learn to work with a pair that is already available.

The complex conjugate

Conjugation keeps the real part and changes the sign of the imaginary part:

z=I+jQ⟶z∗=I−jQ.z=I+jQ\quad\longrightarrow\quad z^*=I-jQ.

Here the asterisk means conjugation. On the plane, it is a reflection across the horizontal II axis. The length stays the same, and the angle changes sign:

Aejθ⟶Ae−jθ.Ae^{j\theta}\quad\longrightarrow\quad Ae^{-j\theta}.

For example, −0.866+j0.5-0.866+j0.5 is in the second quadrant at an angle of approximately 150∘150^\circ. After conjugation, we get −0.866−j0.5-0.866-j0.5 in the third quadrant. Its angle is −150∘-150^\circ, which is the same direction as 210∘210^\circ.

If you conjugate each sample of a rotating vector, the direction of rotation becomes the opposite. One more useful property:

zz∗=(I+jQ)(I−jQ)=I2+Q2=∣z∣2.zz^*=(I+jQ)(I-jQ)=I^2+Q^2=|z|^2.

The product of a number and its conjugate is equal to the square of its magnitude. In Python, you calculate the conjugate like this:

z = -0.866 + 1j * 0.5
z_conjugate = np.conj(z)  # -0.866 - 0.5j

Lab: one signal in four representations

The script shows the position of the selected vector, the II and QQ sequences, the magnitude and the phase:

uv run labs/02/01-complex-iq.py --show

Complex vector, I/Q coordinates, magnitude and phase

On the phase plot, the angle continues to increase after a full turn. This is the unwrapped phase: we keep the accumulated turns. The usual np.angle returns an angle in the range from −π-\pi to +π+\pi, so you see a jump at the limit of this range. np.unwrap removes such jumps between adjacent samples. For our slow rotation, this lets us see a straight line.

Select a different sample and initial phase:

uv run labs/02/01-complex-iq.py --index 12 --phase-deg 45 --show --output-dir /tmp/dsp-iq

To open interactive Python after the script runs:

PYTHONINSPECT=1 uv run labs/02/01-complex-iq.py

In it, the arrays z, i, q, theta are available. Try z[8], np.abs(z[8]), np.rad2deg(np.angle(z[8])) and np.conj(z[8]).

Self-check

A vector has length 1 and an angle of 150∘150^\circ counterclockwise from the positive II axis.

In which quadrant is the end of the vector, and what are the signs of II and QQ?

Explanation

150∘150^\circ is between 90∘90^\circ and 180∘180^\circ, so it is quadrant 2. The point is to the left of the QQ axis and above the II axis: I=cos⁡150∘≈−0.866I=\cos150^\circ\approx-0.866, Q=sin⁡150∘=0.5Q=\sin150^\circ=0.5.

We apply conjugation. Which coordinate changes sign, and in which quadrant is the end of the vector now?

Explanation

Conjugation is a reflection across the horizontal II axis: II stays the same, QQ changes sign, and the angle becomes −150∘-150^\circ (the same as 210∘210^\circ). The end of the vector moves to quadrant 3.

Does the length of the vector change after conjugation?

Explanation

A reflection does not stretch or compress the vector. Formally: ∣z∗∣=I2+(−Q)2=I2+Q2=∣z∣=1|z^*|=\sqrt{I^2+(-Q)^2}=\sqrt{I^2+Q^2}=|z|=1.

For the sample z=0.6+j0.8z=0.6+j0.8, find the magnitude ∣z∣|z|. Which two numbers does this sample store?

Explanation

∣z∣=0.36+0.64=1=1|z|=\sqrt{0.36+0.64}=\sqrt1=1. The sample itself is the pair of coordinates I=0.6I=0.6 and Q=0.8Q=0.8. The magnitude 11 and the angle atan2⁡(0.8,0.6)≈53∘\operatorname{atan2}(0.8,0.6)\approx53^\circ are derived values.

Next lesson: positive and negative frequencies →