EPFL Logo

École Polytechnique Fédérale de Lausanne
EE-426: Radio Frequency Circuits Design Techniques


Lab 2: Low-Noise Amplifier Design¶

Filippo Quadri, David Ruffieux
filippo.quadri@epfl.ch


Welcome to the second lab of the EE-426 course!¶

After completing the first lab—where you designed a full transmitter–receiver architecture—we will now explore how to physically implement the components you previously modeled in Python.

In this lab session, you will:

  1. Design a simple Low-Noise Amplifier (LNA) that meets given specifications.
  2. Size a matching network to match the $50\Omega$ impedance of the following stage, which could be a filter or directly an antenna.

Part 1: LNA Design¶

Before diving into the implementation, let’s take a moment to understand what we are about to build.

LNA Basics¶

A Low-Noise Amplifier (LNA) is an electronic circuit designed to amplify very weak signals while preserving their Signal-to-Noise Ratio (SNR) as much as possible.

Most amplifiers increase both the signal and the noise present at their input; however, they also introduce their own internal noise, which can degrade the overall SNR. LNAs are specifically engineered to minimize the additional noise contributed by the amplifier itself—through careful selection of components, biasing conditions, and circuit topology.

In practice, minimizing added noise must be carefully balanced with other key design objectives such as power gain and impedance matching.

In real-life designs, some active elements (such as transistors) are present inside the schematic. For now, however, we will only use an ideal transconductor :)

The schematic of what you are going to size is given below.

No description has been provided for this image

Figure 1: LNA simplified schematic

Understanding Transconductance and the Simplified LNA Model¶

Transconductance describes how the AC output current of a device changes in response to variations in its input voltage. It is defined as:

$$ dI = g_m \cdot dV $$

where $g_m$ is the transconductance (in siemens).

In our simplified LNA model:

  • The input voltage $V_{I,RF}$ is applied to the amplifier’s input terminal.
  • The resulting output current flows into a resonant network, producing the output voltage $V_{O,RF}$.
  • The transconductance element $g_m$ is modeled using a Voltage-Controlled Current Source (VCCS) (as in Cadence or G in LTspice).

In this abstraction, we don’t need to apply a DC bias to the RF input, since $g_m$ is directly set by the gain of the VCCS. For a real transistor, however, $g_m$ is approximately:

$$ g_m \approx \frac{I_B}{U_T} $$

where:

  • $I_B$ is the bias current,
  • $U_T = \frac{kT}{q} \approx 25\text{mV at } 25^\circ\text{C}$ is the thermal voltage.

This relation allows you to estimate the bias current required to achieve a given transconductance.

Simulation Setup¶

For the LNA we typically apply a small AC signal at the input. Furthermore, we can remove the DC biasing to simplify comparison between plots ($V_{DD}=0V$).

Of course, this would not be valid in a real transistor implementation, since correct operation requires proper DC bias points — but we’ll build up to that step-by-step.

In you Cadence/LTspice simulation put

  • AC voltage source: $6\mu V_{p-p}\approx-100$ dBm, which corresponds to the sensitivity limit
  • $V_{DD} = 0V$
Question 1.1: Create the schematic on your favorite circuit simulator (e.g. Cadence Virtuoso or LTspice) and put a screenshot of the schematic in the submission. Show the parameters of the AC voltage source.

Ok, now it is time to define the LNA specifications.

Our LNA is centered at $f_0 = 2.44$ GHz and has a voltage gain of 20dB and a 3dB-bandwidth ($B_{-3dB0}$) of around $240$ MHz

Question 1.2: Compute the Q of the system (approximate it to the closest integer)

Your Answer:

$$ Q = \frac{f_0}{B_{-3dB}} \approx 10 $$

The voltage gain of the LNA is given by $$ A = \frac{V_{O,RF}}{V_{I,RF}} = g_m \frac{R}{1+jQ\left( \frac{\omega}{\omega_0}-\frac{\omega_0}{\omega} \right)} $$

Question 1.3: Show that this is the case.

Your Answer:

See Lecture Notes - Chapter 2, page 6

In [ ]:
%pip install numpy quantiphy --quiet

import numpy as np
from quantiphy import Quantity
In [2]:
def compute_gain(Q: float, R: float, gm: float, f: float, f0: float) -> complex:
    """
    Compute the voltage gain of the LNA at a given frequency.

    Parameters:
    Q (float): Quality factor of the circuit.
    R (float): Resistance in ohms.
    gm (float): Transconductance in siemens.
    f (float): Frequency at which to compute the gain in Hz.
    f0 (float): Resonant frequency in Hz.

    Returns:
    complex: Voltage gain at frequency f.
    """
    omega = 2 * np.pi * f
    omega0 = 2 * np.pi * f0
    gain = gm * R / (1 + 1j * Q * (omega / omega0 - omega0 / omega))
    module = np.abs(gain)
    module_dB = 20 * np.log10(module) if module > 0 else -np.inf
    phase = np.angle(gain, deg=True)
    
    print("┌────────── Results ──────────┐")
    print(f"│ Frequency   {Quantity(f, 'Hz'):>15} │")
    print(f"│ Gain        {Quantity(module_dB, 'dB'):>15} │")
    print(f"│ Phase       {Quantity(phase, 'degrees'):>15} │")
    print("└─────────────────────────────┘")

    return gain

Let's say that the current budget for the circuit (bias current, $I_B$) is of maximum 2mA and that your project manager want you to use an inductor with $L=1nH$.

Question 1.4: Size gm (so Ib), R and C and verify your calculations with a simulation. How much the third harmonic is attenuated? Use the provided python function as help

Hint: start by sizing R and C.. then check the gain constraint to compute the correct value for $g_m$ and $I_B$

Your Answer:

We have $$ \begin{align} Q &= \frac{R}{\omega_0 L}\\ \omega_0^2 &= \frac{1}{LC}\\\\ C &= \frac{1}{L\omega_0^2} \approx 4.25pF\\ R &= Q\omega_0L \approx 153\Omega\\\\ \text{Max gain } &= 20\log{\left( g_mR \right)} = 20dB\\ &\Rightarrow g_m = \frac{10}{R} \approx 65mS\\ &\Rightarrow I_B = g_m U_T = 1.625mA \end{align} $$

For the third harmonic $\omega = 3\omega_0 = 3 \cdot 2.44GHz\cdot 2\pi$ we have

In [3]:
Q = 10
R = 153
gm = 0.065
f0 = 2.44e9
f = 3 * f0

print("Gain at f = f0:")
gain0 = compute_gain(Q, R, gm, f0, f0)

print("\nGain at f = 3 * f0:")
gain = compute_gain(Q, R, gm, f, f0)

attenuation = 20 * np.log10(np.abs(gain0) / np.abs(gain))
print(f"\nAttenuation from f0 to 3*f0: {Quantity(attenuation, 'dB')}")
Gain at f = f0:
┌────────── Results ──────────┐
│ Frequency          2.44 GHz │
│ Gain              19.952 dB │
│ Phase             0 degrees │
└─────────────────────────────┘

Gain at f = 3 * f0:
┌────────── Results ──────────┐
│ Frequency          7.32 GHz │
│ Gain             -8.5734 dB │
│ Phase       -87.852 degrees │
└─────────────────────────────┘

Attenuation from f0 to 3*f0: 28.525 dB

The actual application bandwidth is much smaller than the one calculated above, as an attenuation of -3 dB at the band edges is not acceptable—the limit is -1 dB. The following two questions help illustrate the importance of choosing the correct Q factor (related to the 3 dB bandwidth) when designing filters and amplifiers.

Question 1.5: Is the selected Q value sufficient to ensure less than 1 dB attenuation at the band edges, i.e., ±40 MHz from the center frequency?

Your Answer:

In this case the upper limit is $\omega = \omega_0 + 2\pi\cdot 40MHz$

In [4]:
Q = 10
R = 153
gm = 0.065
f0 = 2.44e9
f = f0 + 40e6

print("Gain at f = f0:")
gain0 = compute_gain(Q, R, gm, f0, f0)

print("\nGain at f = f0 + 40MHz:")
gain = compute_gain(Q, R, gm, f, f0)

attenuation = 20 * np.log10(np.abs(gain0) / np.abs(gain))
print(f"\nAttenuation from f0 to f: {Quantity(attenuation, 'dB')}")
Gain at f = f0:
┌────────── Results ──────────┐
│ Frequency          2.44 GHz │
│ Gain              19.952 dB │
│ Phase             0 degrees │
└─────────────────────────────┘

Gain at f = f0 + 40MHz:
┌────────── Results ──────────┐
│ Frequency          2.48 GHz │
│ Gain              19.515 dB │
│ Phase       -18.016 degrees │
└─────────────────────────────┘

Attenuation from f0 to f: 436.65 mdB

The attenuation is less than 1dB, so $Q=10$ is a good choice!

Question 1.6: Same as Q-1.5 if the output resonance frequency is detuned by -5% due to components mismatch (search for the worst case)

Your Answer:

The new $\omega_0=2\pi\cdot 2.44GHz\cdot 1.05$

In [5]:
Q = 10
R = 153
gm = 0.065
f0 = 2.44e9
new_f0 = f0 * 0.95
f = f0 + 40e6

print("Gain at f = new_f0 (max gain):")
gain0 = compute_gain(Q, R, gm, new_f0, new_f0)

print("\nGain at f = f0 + 40MHz:")
gain = compute_gain(Q, R, gm, f, new_f0)

attenuation = 20 * np.log10(np.abs(gain0) / np.abs(gain))
print(f"\nAttenuation from f0 to f: {Quantity(attenuation, 'dB')}")
Gain at f = new_f0 (max gain):
┌────────── Results ──────────┐
│ Frequency         2.318 GHz │
│ Gain              19.952 dB │
│ Phase             0 degrees │
└─────────────────────────────┘

Gain at f = f0 + 40MHz:
┌────────── Results ──────────┐
│ Frequency          2.48 GHz │
│ Gain              15.437 dB │
│ Phase       -53.514 degrees │
└─────────────────────────────┘

Attenuation from f0 to f: 4.5151 dB

The attenuation is more the 1dB, so $Q=10$ is not a good choice!

Let's become pro RF designers :)

We want now to design the output resonant load that maximize the voltage gain so that within the 2.4 to 2.48GHz band, the attenuation is limited to 1dB while taking into account a ±3% variation for each of the LC tank components.

Question 1.7: Size again the LNA by taking into account these new specifications. Verify your results with the simulation.

Hint 1: if $\Delta\omega << \omega_0$ you can do the following approximation $$ \frac{1}{1+jQ\left( \frac{\omega}{\omega_0}-\frac{\omega_0}{\omega} \right)} \approx \frac{1}{1+jQx} $$ where $x = \frac{2\Delta\omega}{\omega_0}$

Hint 2: you can try to fix the capacitor, e.g. $C=1pF$

Your Answer:

Considering 3% mismatch on both L and C, we simply increase $\Delta\omega=2\pi(2.48-2.4GHz)/2$ by $3\%·2\pi·2.44GHz$. We thus get $x = 2·4.5\% = 9\%$.

We want 1dB attenuation, hence $$ 10\log{\left( \frac{1}{1+Q^2x^2} \right)} = -1dB $$

Note that we are using 10 log because the denominator is already the squared magnitude of the complex value. Solving for $Q$, one gets $Q = 5.65$.

We can thus write the gain of the LNA $$ G_{LNA} = \frac{g_m}{g_{P,TANK}} = g_m \cdot Q \cdot \sqrt{\frac{L}{C}} $$

We maximize the gain by choosing a high inductor value but limiting the tank Q to 5.65 with a physical resistor in parallel.

Choosing $C=1pF$ to get a reasonable value including the LNA loading, we get $L=4.2nH$ and find $R=370\Omega$. $g_m$ may be freely adjusted to further increase our gain.

Part 2: Impedance Matching Network Design¶

Now our LNA is properly sized and should work amazingly.. But we have a problem. Your collegue, that has designed the filter with input impedance of $50\Omega$, gives you his design. When you connect everything together, the specification you hardly tried to satisfy are no longer fullfilled. So you have two options

  1. You kill your collegue (but HR will probably not approve)
  2. You find the problem and try to solve it
No description has been provided for this image

Figure 2: Simplified representation of LNA + Filter
Question 2.1: Why are the specifications no longer met? How are the Q, BW and gain affected (motivate with some calculations)? What could you do to preserve the outcomes of Q-1.7?

Your Answer:

The new impedance is degenerating the R inside the resonant load. Let's check the effect of this with python

In [6]:
def parallel(R1: float, R2: float) -> float:
    return 1 / (1 / R1 + 1 / R2)

gm = 0.027 # new gm to match the 20 dB gain at f0
R = parallel(370, 50)
L = 4.2e-9
C = 1e-12

f0 = 2.44e9
omega_0 = 2 * np.pi * f0

Q = R / (omega_0 * L)
gain = 20 * np.log10(gm * R)
BW = f0 / Q


print(f"New Q factor: {Quantity(Q)}")
print(f"New gain at f0: {Quantity(gain, 'dB')}")
print(f"New bandwidth: {Quantity(BW, 'Hz')}")
New Q factor: 684.07m
New gain at f0: 1.5057 dB
New bandwidth: 3.5669 GHz

L and C, in principle, can be the same.. but we can merge them with the new values from the impedance matching network to reduce the number of components inside the architecture!

To match the resistances, we should design an impedances matching network!

Let’s explore how to design an impedance matching network by examining two different topologies: one that’s quite straightforward, and another that’s a bit more complex.

First Impedance Matching Network Design¶

The network we’ll be working with is illustrated in Figure 3:

No description has been provided for this image

Figure 3: LNA with a Simple Impedance Matching Network

A key observation here is that the two inductors in the circuit can be combined into a single equivalent inductor. This equivalent inductor would have a value equal to the parallel combination of the original two, simplifying the overall design.

Now, let’s proceed step-by-step.

At the resonant frequency, this network results in the matched impedance appearing in parallel with the resonant resistor. To maintain the same quality factor (Q), gain, and bandwidth, we can double the value of the resonant resistor and then match the load to this new value. When placed in parallel, the resulting resistance will be the desired one.

Question 2.2: Size Lm and Cm in order to not degrade the LNA performances

Your Answer:

The new $R_{res}$ value is $$ R_{res} = 370 \cdot 2 = 740\Omega $$

We have $$ \begin{align} Q_{M} &= \sqrt{\frac{R_{res}}{R_L}-1} = 3.71\\ R_P &= R_L(1+Q^2) = R_{res}\\\\ X_{L_M} = X_{C_{M_P}} &= \frac{R_P}{Q} \approx 200\Omega\\ X_{C_M} &= Q \cdot R_L \approx 185.5 \Omega\\\\ L_M &= \frac{X_{L_M}}{2\pi f} \approx 13nH\\ C_M &= \frac{1}{2\pi f X_{C_M}} \approx 0.35pF \end{align} $$

It is a good idea to merge the inductors. The equivalent inductor is just the parallel of the two $$ L_{eq} = L_{res} // L_M $$

Second Impedance Matching Network Design¶

Now let’s consider a clever variation. The idea is to eliminate the resonant resistor entirely and rely solely on the matched impedance. The updated schematic is shown in Figure 4.

No description has been provided for this image

Figure 4: LNA with Modified Impedance Matching Network (No Resonant Resistor)

If the inductors in this configuration are merged into a single equivalent inductor, an interesting benefit emerges: the overall noise performance improves compared to the previous design. This makes the second topology not only more elegant but also potentially more efficient in terms of noise reduction.

Question 2.3: Size Lm and Cm of this new architecture without degrading the performances

Your Answer: $$ \begin{align} R_{res} &= 370\\ Q_{M} &= \sqrt{\frac{R_{res}}{R_L}-1} = 2.53\\ R_P &= R_L(1+Q^2) = R_{res}\\\\ X_{L_M} = X_{C_{M_P}} &= \frac{R_P}{Q} \approx 146.2\Omega\\ X_{C_M} &= Q \cdot R_L \approx 126.5 \Omega\\\\ L_M &= \frac{X_{L_M}}{2\pi f} \approx 9.5nH\\ C_M &= \frac{1}{2\pi f X_{C_M}} \approx 0.5pF \end{align} $$

It is a good idea to merge the inductors. The equivalent inductor is just the parallel of the two $$ L_{eq} = L_{res} // L_M $$

Part 3: Bonus - Filter Design¶

Question 3.1: Without considering component variations, design a Butterworth bandpass filter with 50-Ω input output resistance; the passband ripple should be < 1dB and the attenuation at 2.52GHz is 20dB

Your Answer:

Following the procedure described in the file Chapter 4 - Lecture Notes, we can derive all the elements we need to synthesize the required filter.

Below a code is provided to automatically compute those quantities, based on the requirements.

In [7]:
wp1 = 2.4e9 * 2 * np.pi
wp2 = 2.48e9 * 2 * np.pi

w1 = 2.36e9 * 2 * np.pi
w2 = 2.52e9 * 2 * np.pi

Ap = 1 	# 1dB
As = 20 # 20dB

w0 = np.sqrt(wp1 * wp2)

B = wp2 - wp1

ws1_temp = w0**2 / w2
ws2_temp = w0**2 / w1

if ws1_temp > w1:
	ws1 = ws1_temp
	ws2 = w2
else:
	ws1 = w1
	ws2 = ws2_temp

OMEGA_S = (ws2 - ws1) / B

epsilon = np.sqrt(10**(Ap/10) - 1)
N = np.ceil(np.log10((10**(As/10) - 1) / (epsilon**2)) / (2 * np.log10(OMEGA_S)))

print("┌──────── Results (Hz) ───────┐")
print(f"│ wp1         {Quantity(wp1/(2*np.pi), 'Hz'):>15} │")
print(f"│ wp2         {Quantity(wp2/(2*np.pi), 'Hz'):>15} │")
print(f"│ BW          {Quantity((B)/(2*np.pi), 'Hz'):>15} │")
print(f"│ ws1         {Quantity(ws1/(2*np.pi), 'Hz'):>15} │")
print(f"│ ws2         {Quantity(ws2/(2*np.pi), 'Hz'):>15} │")
print("├─────────────────────────────┤")
print(f"│ OMEGA_S     {Quantity(OMEGA_S):>15} │")
print(f"│ Filter Order N {Quantity(N):>12} │")
print(f"│ epsilon     {Quantity(epsilon):>15} │")
print("└─────────────────────────────┘")
┌──────── Results (Hz) ───────┐
│ wp1                 2.4 GHz │
│ wp2                2.48 GHz │
│ BW                   80 MHz │
│ ws1              2.3619 GHz │
│ ws2                2.52 GHz │
├─────────────────────────────┤
│ OMEGA_S              1.9762 │
│ Filter Order N            5 │
│ epsilon             508.85m │
└─────────────────────────────┘

Now we can compute the Low-Pass components using the formula 4.24 of the lecture notes (reported below) $$ C_k,L_k = 2\varepsilon^{1/N} \sin \left( \frac{2k-1}{2N}\pi \right) \qquad k = 1, 2, ..., N $$

In [8]:
components = []
for i in range(1, int(N+1)):
	Ck_Lk = 2 * epsilon**(1/N) * np.sin((2*i - 1) * np.pi / (2 * N))
	components.append(Ck_Lk)

print("┌─────── Low-Pass Components ───────┐")
for idx, comp in enumerate(components):
	print(f"│ Component {idx + 1:>2}: {Quantity(comp):>19} │")
print("└───────────────────────────────────┘")
┌─────── Low-Pass Components ───────┐
│ Component  1:             539.92m │
│ Component  2:              1.4135 │
│ Component  3:              1.7472 │
│ Component  4:              1.4135 │
│ Component  5:             539.92m │
└───────────────────────────────────┘

We can apply the bandpass transformation and obtain the values for C and L (we start with series L)

In [13]:
def bandpass_transform(Ck_Lk: float, R_S: float, w0: float, B: float, type: str) -> tuple:
	if type == 'L':
		L = Ck_Lk / B
		C = 1 / (w0**2 * L)
	else:
		C = Ck_Lk / B
		L = 1 / (w0**2 * C)
	
	C = C / R_S
	L = L * R_S
	return C, L

R_S = 50
print("┌──────────── Band-Pass Components ────────────┐")
for idx, comp in enumerate(components):
	if idx % 2 == 0:
		type = 'L'
	else:
		type = 'C'
	C, L = bandpass_transform(comp, R_S, w0, B, type)
	if type == 'L':
		print(f"│ Component {idx + 1:>2}: L{idx + 1} = {Quantity(L, 'H'):>9}, C{idx + 1} = {Quantity(C, 'F'):>9} │")
	else:
		print(f"│ Component {idx + 1:>2}: C{idx + 1} = {Quantity(C, 'F'):>9}, L{idx + 1} = {Quantity(L, 'H'):>9} │")
print("└──────────────────────────────────────────────┘")
┌──────────── Band-Pass Components ────────────┐
│ Component  1: L1 = 53.707 nH, C1 = 79.241 fF │
│ Component  2: C2 = 56.243 pF, L2 = 75.668 pH │
│ Component  3: L3 =  173.8 nH, C3 = 24.487 fF │
│ Component  4: C4 = 56.243 pF, L4 = 75.668 pH │
│ Component  5: L5 = 53.707 nH, C5 = 79.241 fF │
└──────────────────────────────────────────────┘