This file was generated from a Matlab Live editor. The code snippets should work without modification in Octave, which is a free Matlab clone.
There's nothing novel in this analysis (see the references), but I do feel that the consequences are never satisfactorily brought out.
The fundamental quantity in the modelling of a BJT is the thermal voltage, Vt. At room temperature it is approximately 26mV (some people round this to 25mV). This is one of those constants that should be etched in your mind.
k = 1.38064852e-23; % Boltzmann's constant [m^2 kg s^-2 K^-1]
T = 300; % Temp [Kelvin]
q = 1.60217662e-19; % Electron charge [coulombs]
VT = k*T/q
Let's consider a common-emitter amplifier operating in the active region. If we assume Ic = Ie (which is approximately the case and is a constant for a device anyway), the collector current is approximately related to Vbe according to:
Where Is is the reverse bias saturation current, typically in the 1e-13 range.
Let's take a look at a typical characteristic...
Vbe = 0:1e-3:1;
Is = 1e-13;
Ic = Is*exp(Vbe/VT);
figure;
plot(Vbe, Ic);
grid;
xlim([0.5 0.7]);
xlabel('Vbe [V]');
ylabel('Ic [A]');
title('BJT transfer characteristic');
We traditionally think of the BJT as only being 'off' below 0.7V. However, if we plot it on a log y-scale we see that every 6mV increase in Vbe causes a decade increase in Ic.
figure;
semilogy(Vbe, Ic);
grid;
xlim([0.5 0.7]);
xlabel('Vbe [V]');
ylabel('Ic [A]');
title('BJT transfer characteristic');
For Class A operation, we would pick a quiescent bias voltage, about which our AC signal swings. Normally, we would pick a quiescent collecor current, rather than a Vbe voltage, because a large range of currents exist in a small Vbe voltage range. In this case we have:
The exponential is usefully approximated by a (Maclaurin) power series expansion:
So we have:
Note that this is only an accurate approximation near x=0, hence our motivation to remove the quiescent current from the equation.
Vin_ac = -0.5:1e-3:0.5; % AC input voltage swings about bias voltage.
Iq = 10e-3;
Ic_ac = Iq*exp(Vin_ac/VT);
Ic_ac_approx_a0 = Iq;
Ic_ac_approx_a1 = Iq/VT;
Ic_ac_approx_a2 = Iq*(1/2)/(VT).^2;
Ic_ac_approx_a3 = Iq*(1/6)/(VT).^3;
Ic_ac_approx = Ic_ac_approx_a0 + Ic_ac_approx_a1*Vin_ac + Ic_ac_approx_a2*Vin_ac.^2 + Ic_ac_approx_a3*Vin_ac.^3;
figure;
plot(Vin_ac, Ic_ac);
hold all;
plot(Vin_ac, Ic_ac_approx);
plot(Vin_ac, Ic_ac_approx_a0*ones(1,length(Vin_ac)), '--');
plot(Vin_ac, Ic_ac_approx_a1*Vin_ac, '--');
plot(Vin_ac, Ic_ac_approx_a2*Vin_ac.^2, '--');
plot(Vin_ac, Ic_ac_approx_a3*Vin_ac.^3, '--');
grid;
xlim([-0.05 0.05]);
xlabel('Vin [V]');
ylabel('Ic [A]');
legend('exp', 'MacLaurin series', 'a0', 'a1*Vin', 'a2*Vin^2', 'a3*Vin^3');
title('BJT transfer characteristic');
As you can see, the MacLaurin series is accurate within +/-20mV of the bias point. Accuracy beyind this range requires more terms in the series, but these represent distortion orders higher than 3rds, which we're less interested in here.
Let's look more closely at the MacLaurin series. Multiplying through, the first term (a0) is simply the quiescent bias current. The second term (a1) is the linear approximation at the bias point, i.e. it is the slope of the transfer characteristic at the bias point. Namely:
Modern parlance uses units of Siemens for conductance, but you might hear people talk about mhos (ohms backwards) or simply mA/V.
This is an important result because it tells us that the transconductance is linearly related to the bias current.
The third term is the coefficient of 2nd order distortion:
And the fourth term is the coefficient of 3rd order distortion:
When the 2nd order 2-tone intermodulation product at the output equals the wanted signal level we have:
And for the 3rd order 2-tone distortion we have:
Note that all of these equations refer to the peak input voltage.
The scaling terms are a result of the trigonometric expansion that gives rise to the 2nd or 3rd order product frequency terms (see the references for this proof).
Solving for Vin provides the input referred IP3:
For our exponential function, we can substitute in the expressions of a1, a2, a3. This yields:
The corresponding values at the output are easily obtained by multiplying by gm (i.e. a1):
Another often used metric is the -1dB compression point. This occurs provided a3/a1<1, which typically is the case. It occurs because 3rd order distortion also generates a product at the fundamental that subtracts from the wanted signal. This term may be used to find the point where the gain has dropped by 1dB:
Solving for Vin:
Referring to the output instead, and substituting for OIP3:
There are several useful nuggets of information here:
It might com as a bit of a surprise that the input referred IP2/3 is constant, but remember we're talking about voltage here, not power. As we increase Iq, the input impedance is also reducing in proportion, so the input referred IP2/3 as a power is actually increasing.
We started out considering this to be a model of a common-emitter amplifier, but actually common-base and common-collector configurations also rely on changes in Vbe causing a change in Ic. Again, it's all the same, but modified by the apparent impedance. For example, a common-base amplifier has a low input impedance (1/gm), so the IP2/3 voltage yields a higher IP2/3 power.
In case of any scepticism, let's check how accurate the calculated values of IP2 & IP3 by applying a 2-tone signal to the exponential characteristic ...
t_step = 100e-9;
fftLength = 500;
t_stop = (fftLength-1)*t_step;
t = 0:t_step:t_stop;
f = 0:1/t_stop:1/t_step;
f1 = 900e3;
f2 = 1100e3;
Vin_pk = 1e-3;
v_in = Vin_pk*(cos(2*pi*f1*t) + cos(2*pi*f2*t));
% Don't use the approximation, and subtract the bias current.
i_out_ac = Iq*exp(v_in/VT) - Iq;
figure;
plot(t, v_in);
hold all;
plot(t, i_out_ac);
grid;
legend('Vin', 'Iout');
xlabel('time [s]');
ylabel('V, A');
% Spectrum of input voltage.
spec_in_2sided = abs(fft(v_in)/length(v_in));
spec_in_1sided = spec_in_2sided(1:fftLength/2+1);
spec_in_1sided(2:end-1) = 2*spec_in_1sided(2:end-1);
f_1sided = f(1:fftLength/2+1);
% Spectrum of output current.
spec_out_2sided = abs(fft(i_out_ac)/length(i_out_ac));
spec_out_1sided = spec_out_2sided(1:fftLength/2+1);
spec_out_1sided(2:end-1) = 2*spec_out_1sided(2:end-1);
figure;
plot(f_1sided, 20*log10(spec_in_1sided/1e-3));
hold all;
plot(f_1sided, 20*log10(spec_out_1sided/1e-3));
grid;
legend('Vin', 'Iout');
xlim([0 2.1e6]);
xlabel('freq [Hz]');
ylabel('amplitude [dBmV, dBmA]');
We can calculate the 2-tone intercepts from a single measurement by assuming that the slope is 2 for 2nd order IMD and 3 for 3rd order IMD.
% Get the level of the two wanted tones at the output from the fft.
s_out_f1_idx = find(f >= f1, 1);
s_out_f2_idx = find(f >= f2, 1);
s_out_f1_dBmA = 20*log10(spec_out_1sided(s_out_f1_idx)/1e-3);
s_out_f2_dBmA = 20*log10(spec_out_1sided(s_out_f2_idx)/1e-3);
% Get the level of the two unwanted 2nd order intermodulation products from the fft.
IM2_L_idx = find(f >= (f2 - f1), 1);
IM2_H_idx = find(f >= (f2 + f1), 1);
IM2_L_dBmA = 20*log10(spec_out_1sided(IM2_L_idx)/1e-3);
IM2_H_dBmA = 20*log10(spec_out_1sided(IM2_H_idx)/1e-3);
% Get the level of the two unwanted 2nd order intermodulation products from the fft.
IM3_L_idx = find(f >= (2*f1 - f2), 1);
IM3_H_idx = find(f >= (2*f2 - f1), 1);
IM3_L_dBmA = 20*log10(spec_out_1sided(IM3_L_idx)/1e-3);
IM3_H_dBmA = 20*log10(spec_out_1sided(IM3_H_idx)/1e-3);
% Calculate the intercepts from the fft data. We'll just use f1 and the lower IMP because there is no frequency colouring.
% Calculate the dB difference between the wanted and IMD2 product at the output.
IM2_dBc = s_out_f1_dBmA - IM2_L_dBmA;
% The 2nd order IMD grows at twice the rate of the wanted signal, so the output intercept is given by:
OIP2_dBmA = s_out_f1_dBmA + IM2_dBc;
% The input intercept is may be calculated by reference to the input level:
IIP2_dBmV = Vin_pk + IM2_dBc;
% The same process is used to obtain the IP3.
IM3_dBc = s_out_f1_dBmA - IM3_L_dBmA;
% This time the IMD grows at three times the rate of the wanted signal.
OIP3_dBmA = s_out_f1_dBmA + IM3_dBc/2;
IIP3_dBmV = Vin_pk + IM3_dBc/2;
% We can compare these results with the calculated estimates.
IIP2_dBmV_est = 20*log10( 2*VT /1e-3 );
IIP3_dBmV_est = 20*log10( sqrt(8)*VT / 1e-3 );
OIP2_dBmA_est = 20*log10( 2*Iq /1e-3 );
OIP3_dBmA_est = 20*log10( sqrt(8)*Iq / 1e-3 );
fprintf('measured IIP2 = %gdBmV, calculated IIP2 = %gdBmV', IIP2_dBmV, IIP2_dBmV_est);
fprintf('measured IIP3 = %gdBmV, calculated IIP3 = %gdBmV', IIP3_dBmV, IIP3_dBmV_est);
fprintf('measured OIP2 = %gdBmA, calculated OIP2 = %gdBmA', OIP2_dBmA, OIP2_dBmA_est);
fprintf('measured OIP3 = %gdBmA, calculated OIP3 = %gdBmA', OIP3_dBmA, OIP3_dBmA_est);
As you can see, these results are remakably similar!
http://rfic.eecs.berkeley.edu/~niknejad/ee142_fa05lects/pdf/lect8.pdf
http://rfic.eecs.berkeley.edu/~niknejad/ee142_fa05lects/pdf/lect9.pdf