My well annotated MATLAB code and plot is attempting to calculate the third order intercept of an amplifier.
- I have raw data of a non linear transfer curve, Voltage in (array)
and the amplified voltage out (array) - I generate two sinusoids and add them together to make a waveform.
- The waveform is normalised so its constrained within the positive
and negative of a single voltage input value from the transfer curve
array. - This is looped for all voltage input values in the array. (A Master
Loop). - Each time the loop progresses through the voltage input values, the
waveform is amplified by the transfer curve (a polynomial fit
equation) - In other words, its a power sweep across the input range of the
amplifier, where the waveform is progressively increasing in power. - A Fourier Transform is calculated each time the input voltage is increased
(giving higher amplification) which reveals the amplitudes of
intermodulation product frequencies. - Finally, a plot is produced of the intermod at each
voltage_in/voltage out_point on the transfer curve and the third
order intercept (TOI) calculated. The intermod gradient is 3:1 ona log-log plot and the linear gain is 1:1 on a log log plot (which is included below and on the code).
I know the Third order intercept of this amplifier is -6.8 dBW. But I get 0.78 dBW.
Please can someone help, I've been at this on and off for over 3 months and its driving me crazy.
The script is annotated well, runs in less than a second and has excellent plots.
clear all
format long
% ==== Section 1 Raw Data ==================
%Raw Data in DB (To start : Power in was given in dBm, Power out was dBW)
p_in_tc = [-53.07 -52.66 -52.25 -51.83 -51.42 -51.01 -50.60 -50.18 -49.77 -49.36 -48.95 -48.53 -48.12 -47.71 -47.30 -46.88 -46.47 -46.06 -45.65 -45.23 -44.82 -44.41 -44.00 -43.58 -43.17 -42.76 -42.35 -41.94 -41.52 -41.11 -40.70 -40.29 -39.87 -39.46 -39.05 -38.64 -38.22 -37.81 -37.40 -36.99 -36.57 -36.16 -35.75 -35.34 -34.92 -34.51 -34.10 -33.69 -33.27 -32.86 -32.45]';
p_in_tc = p_in_tc - 30; % 30dbM = 0dBW Converted to dBw
p_out_tc = [-36.31 -35.91653 -35.53542 -35.08876 -34.68977 -34.24591 -33.87132 -33.41216 -33.03855 -32.63183 -32.21841 -31.79861 -31.40797 -30.98433 -30.58884 -30.16253 -29.77254 -29.35253 -28.9475 -28.53066 -28.13344 -27.73318 -27.32436 -26.91283 -26.51466 -26.09394 -25.69517 -25.2961 -24.8958 -24.49461 -24.10408 -23.69662 -23.29808 -22.91381 -22.51055 -22.11622 -21.73276 -21.33714 -20.94937 -20.56428 -20.19364 -19.80442 -19.44888 -19.06418 -18.71527 -18.34826 -17.99767 -17.65278 -17.29772 -16.97233 -16.65949]';
%Input Data to Volts
p_in_watts = 10.^((p_in_tc)/10);
v_in_rms = (p_in_watts .* 50) .^(1/2);
v_in_peak = v_in_rms' .* sqrt(2); %Use this Input
%Output Data to Volts
p_out_watts = 10.^((p_out_tc)/10);
v_out_rms = (p_out_watts .* 50) .^(1/2);
v_out_peak = v_out_rms' .* sqrt(2) ; %Use this Output
% ===== Section 2 - Generate Waveform ==============
power = 3;
exponent = 1*10^power;
freq_spacing = 1;
freq_range = (3:freq_spacing:4)*exponent;
Fs =10*max(freq_range);
Ts = 1/Fs;
end_time = 10*10^(-power);
n = 0 : Ts : end_time-Ts;
for c=1:length(v_in_peak) %Master Loop (Power sweep across all input voltage values, creating a waveform for each input voltage).
%Make the number of waves in the frequency range
for a = 1:length(freq_range)
random_phase(a) = 0;
y_exp(a,:) = (exp(i*(2*pi .* freq_range(a) .* n + random_phase(a))));
end
waveform = sum(y_exp);
% ==== Section 3 Normalisation (Keep waveform within input voltage ==================
low = -v_in_peak(c); high = v_in_peak(c); mini = min(real(waveform)); maxi = max(real(waveform));
low2 = -v_in_peak(c); high2 = v_in_peak(c); mini2 = min(imag(waveform)); maxi2 = max(imag(waveform));
for a=1:length(waveform)
wave_recon_real(a) = low + ( (real(waveform(a)) - mini) * (high-low) ) / (maxi-mini);
wave_recon_imag(a) = low2 + ( (imag(waveform(a)) - mini2) * (high2-low2) ) / (maxi2-mini2);
wave_recon_normalised(a) = wave_recon_real(a) + (i*wave_recon_imag(a));
waveform(a) = wave_recon_normalised(a);
end
% ==== Section 4 Amplification ==================
p = polyfit(v_in_peak,v_out_peak,3);
for a=1:length(waveform)
%Gives straight line but with a flatness to start with
%waveform_amp(a) = polyval(p,abs(waveform(a))) / abs(waveform(a)); %Amplify the current phasor and divide by the current phasor length to cancel out phasor in waveform in next step
%waveform_amp(a) = waveform_amp(a) * waveform(a) ; %Now multiply original wave so just the amplified summed current phasor is left
%Gives straight line intermods
waveform_amp_real(a) = polyval(p,real(waveform(a))) ;
waveform_amp_imag(a) = polyval(p,imag(waveform(a))) ;
waveform_amp(a) = waveform_amp_real(a) + (i*waveform_amp_imag(a));
end
%Setup Fast Fourier Transform
N=length(n);
freq_domain = (0:N/2); %Show positive frequency only
freq_domain = freq_domain * Fs / N;
%Fast Fourier Transform of Amplified wave
ft2 = fft(waveform_amp)/N;
ft2_spectrum = 2*abs(ft2); % 2* to compensate for negative frequency energy
ft2_spectrum = ft2_spectrum(1:N/2+1); %Show positive Frequency Only
%Bin Spacing
Bins_per_freq= (N/Fs);
%Intermods (third order only)
intermod_1 = 2*freq_range(2) - freq_range(1);
intermod_2 = 2*freq_range(1) - freq_range(2);
freq_range_im3 = [intermod_1 intermod_2];
%Get the bin numbers of the intermods
im_bins = round(Bins_per_freq * (freq_range_im3) +1); %Get the intermod bin Numbers, Domain starts at 0, so add 1
%Intermod amplitudes
im = ft2_spectrum(im_bins);
%Store one intermod for each power sweep, the master loop variable is c
im_sweep = im(1) ;
intermod_power(c) = 10*log10( (((im_sweep* (1/sqrt(2))) .^2 ) /50 ));
%The Frequencies in the waveform
freq_bins = round(Bins_per_freq * (freq_range) +1); %Get the frequency bin Numbers, Domain starts at 0, so add 1
freq_bin_amplitudes = ft2_spectrum(freq_bins);
single_frequency = freq_bin_amplitudes(1);
%Store one frequency power for each power sweep, the master loop variable is c
single_frequency_power(c) = 10*log10( (((single_frequency* (1/sqrt(2))) .^2) /50 ));
% ==== Section 5 Final power sweep, make the plots and caulcate TOI ==================
if c == length(v_in_peak) %Final input voltage value
%Obtain linear line from polynomial
for a=1:length(v_in_peak)
v_out_linear(a) = p(3)*((v_in_peak(a))^1);
p_out_linear(a) = 10*log10(((v_out_linear(a)/sqrt(2))^2)/50);
end
% -- Transfer Curve Linear Line (From linear line equation) --
% Simple y=mx+c Algebra to make a straight line
x1_tc = p_in_tc(1);
x2_tc = p_in_tc(2);
y1_tc = p_out_linear(1);
y2_tc = p_out_linear(2);
m_tc = 1;
c_tc = y1_tc - (m_tc*x1_tc);
eqn_x_tc = p_in_tc;
eqn_y_tc = (m_tc .* p_in_tc) + c_tc;
% -- Intermod Linear Line --
% Simple y=mx+c Algebra to make a straight line
x1_im = p_in_tc(end-10);
x1_im_idx = nearestpoint(x1_im,p_in_tc);
x2_im = p_in_tc(end-5);
x2_im_idx = nearestpoint(x2_im,p_in_tc);
y1_im = intermod_power(x1_im_idx);
y2_im = intermod_power(x2_im_idx);
m_im = 3;
c_im = y1_im - (m_im*x1_im);
eqn_x_im = p_in_tc;
eqn_y_im = (m_im .* p_in_tc) + c_im;
%Find when lines intersect
x_intersect = (c_im - c_tc) / (m_tc - m_im);
y_intersect = m_im * x_intersect + c_im
%Extrapolate past the intersect point for visualisation on plot
eqn_x_tc_int = min(eqn_x_tc):1:x_intersect+4;
eqn_y_tc_int = interp1(eqn_x_tc,eqn_y_tc,eqn_x_tc_int,'linear','extrap');
eqn_x_im_int = p_in_tc(x1_im_idx):1:x_intersect+4;
eqn_y_im_int = interp1(eqn_x_im,eqn_y_im,eqn_x_im_int,'linear','extrap');
figure(1);clf;
bar(freq_domain,ft2_spectrum)
ax=gca; set(gca,'Fontsize',7,'Ticklength',[-0.005 0]); ax.XAxis.Exponent = power;
title('Output Waveform - Frequency','Fontsize',7);
xlabel('Frequency (MHz)','Fontsize',7);ylabel('Actual Amplitude (V)','Fontsize',7);
%xlim([((freq_range(1)-1)*exponent) (freq_range(end)+1)*exponent]);
figure(2);clf;
ax=gca; set(gca,'Fontsize',7)
hold on;grid on; grid minor;
title('RMS Input Power vs RMS Output Power ','Fontsize',7); xlabel('Input Power (dBW) ','Fontsize',7); ylabel('Output Power (dBW) ','Fontsize',7);
plot(p_in_tc,p_out_tc,'--b','DisplayName','Transfer Curve (Raw Data) - RMS');
plot(p_in_tc, single_frequency_power,'-.m*','DisplayName','Single Frequency Power - RMS','MarkerSize',2);
plot(p_in_tc, intermod_power,'r','DisplayName','Intermod Power - RMS');
plot(p_in_tc,p_out_linear,'*g','DisplayName','Poly Order 1 (linear gain)');
plot(eqn_x_tc_int,eqn_y_tc_int,'k','linestyle','--','DisplayName','Linear Gain Extrapolated');
plot(eqn_x_im_int,eqn_y_im_int,'k','linestyle','--','DisplayName','Intermods Extrapolated');
legend('toggle','Location','northwest')
legend('boxoff')
hold off
end
%Final MASTER LOOP
clearvars -except p_in_tc p_out_tc phase_tc v_in_peak v_out_peak power exponent freq_spacing freq_range Fs Ts end_Time n c freq_domain intermod_power single_frequency_power
end
EDIT: Here is the figure, blue dotted line is the measured transfer characteristic, grey dashed lines are the extrapolated linear fits to the data.
Its a log-log plot. The intermod gradient is 3, giving 3:1. The linear extrapolation is from the polynomial using the order 1 term. You can clearly see the TOI is too high.
Best Answer
Run your test points over a 20 or 30 or 40 dB input range, and take log10 of the input and the output values. Take data every 5 or 10 dB. Discard data within 10 dB of the Compression points.
Expect to see exactly!! 1:1 input/output slope for the Vin/Vout of fundamental.
Expect to see exactly!! 3:1 input/output slope for the Vin/Vout of the 3rd order energy.