PLL Design

You might also like

Download as txt, pdf, or txt
Download as txt, pdf, or txt
You are on page 1of 7

% Use for integer-N PLL

clear
clc
close all
%% Settings for computation
fig_on = 1; % Set to 1 for plots
comp_variation = 0; % Set based on the following
% comp_variation = 0 : no variation
% comp_variation = 10 : all components variation
% comp_variation = 1 : R variation
% comp_variation = 11 : all except R variation
% comp_variation = 2 : kvco variation
% comp_variation = 12 : all except kvco variation
% comp_variation = 3 : C variation
% comp_variation = 13 : all except C variation
% comp_variation = 4 : Icp variation
% comp_variation = 14 : all except Icp variation
% comp_variation = 5 : alacarte

if(comp_variation == 0)
R_var_min = 3;
kvco_var_min = 3;
C_var_min = 3;
Icp_var_min = 3;
elseif(comp_variation == 10)
R_var_min = 1;
kvco_var_min = 1;
C_var_min = 1;
Icp_var_min = 1;
elseif(comp_variation == 1)
R_var_min = 1;
kvco_var_min = 3;
C_var_min = 3;
Icp_var_min = 3;
elseif(comp_variation == 11)
R_var_min = 3;
kvco_var_min = 1;
C_var_min = 1;
Icp_var_min = 1;
elseif(comp_variation == 2)
R_var_min = 3;
kvco_var_min = 1;
C_var_min = 3;
Icp_var_min = 3;
elseif(comp_variation == 12)
R_var_min = 1;
kvco_var_min = 3;
C_var_min = 1;
Icp_var_min = 1;
elseif(comp_variation == 3)
R_var_min = 3;
kvco_var_min = 3;
C_var_min = 1;
Icp_var_min = 3;
elseif(comp_variation == 13)
R_var_min = 1;
kvco_var_min = 1;
C_var_min = 3;
Icp_var_min = 1;
elseif(comp_variation == 4)
R_var_min = 3;
kvco_var_min = 3;
C_var_min = 3;
Icp_var_min = 1;
elseif(comp_variation == 14)
R_var_min = 1;
kvco_var_min = 1;
C_var_min = 1;
Icp_var_min = 3;
elseif(comp_variation == 5)
R_var_min = 1;
kvco_var_min = 3;
C_var_min = 1;
Icp_var_min = 1;
end

VCO_noise_sw = 1;
div_noise_sw = 1;
pfd_cp_noise_sw = 1;
ref_noise_sw = 0;

%% Constants and file locations


kb = 1.3806503e-23;
T=273+27;

% VCO
VCO_noise_file = 'C:\Users\Bhavin\Desktop\share\vcodbc.csv';
VCO_noise_data = dlmread(VCO_noise_file,',');
% VCO_noise = VCO_noise_data(:,2)';
VCO_noise_freq = VCO_noise_data(:,1)';

% Crystal oscillator
crys_osc_noise_file = 'C:\Users\Bhavin\Desktop\share\null.csv';
crys_osc_noise_data = dlmread(crys_osc_noise_file,',');
crys_osc_noise_freq = crys_osc_noise_data(:,1)';

% Divider
div_pnoise_file = 'C:\Users\Bhavin\Desktop\share\null.csv';
div_pnoise_data = dlmread(div_pnoise_file,',');
div_noise_freq = div_pnoise_data(:,1)';

% PFD+CP noise
pfd_cp_noise_file = 'C:\Users\Bhavin\Desktop\share\cpnoise.csv';
pfd_cp_noise_data = dlmread(pfd_cp_noise_file,',');

max_div_noise_freq = max(div_noise_freq);
max_VCO_noise_freq = max(VCO_noise_freq);
max_crys_osc_noise_freq = max(crys_osc_noise_freq);

if((max_div_noise_freq>=max_VCO_noise_freq)&&(max_crys_osc_noise_freq>=max_VCO_nois
e_freq))
eval_freq = VCO_noise_freq;
elseif((max_div_noise_freq<=max_VCO_noise_freq)&&(max_crys_osc_noise_freq>=max_div_
noise_freq))
eval_freq = div_noise_freq;
else
eval_freq = crys_osc_noise_freq;
end

%pfd_cp_noise_data(end+1,1) = eval_freq(end);
%pfd_cp_noise_data(end,2) = pfd_cp_noise_data(end-1,2);
pfd_cp_noise_freq = pfd_cp_noise_data(:,1)';

%% Loop initial design parameters


fref = 20e6;
fbw = fref/200;
Icp_nom = 50e-6;
Icp_mismatch = Icp_nom*0.15;
Trst = 200e-12;
b = 13;
N = 180; % N for determining the component values
kvco_nom = (100e6)*2*pi;
R_nom = (b/(b-1))*(power(2*pi,2)*N*fbw)/(kvco_nom*Icp_nom);
C1_nom = sqrt(b)/(2*pi*fbw*R_nom);
C2_nom = C1_nom/(b-1);
% C2_nom = (C1_nom/(b-1))*2;
C1pC2_nom = (C1_nom*C2_nom)/(C1_nom+C2_nom);

VCO_noise = interp1(VCO_noise_freq,VCO_noise_data(:,2)',eval_freq);
div_noise = interp1(div_noise_freq,div_pnoise_data(:,2)',eval_freq);
pfd_cp_noise = interp1(pfd_cp_noise_freq,pfd_cp_noise_data(:,2)',eval_freq);
crys_osc_noise = interp1(crys_osc_noise_freq,crys_osc_noise_data(:,2)',eval_freq);

%% Variation in component values


R_var = [R_nom*0.85 R_nom*1.15 R_nom];
kvco_var = 2*pi*[50e6 150e6 kvco_nom/(2*pi)];
C1_var = [C1_nom*0.85 C1_nom*1.15 C1_nom];
C2_var = [C2_nom*0.85 C2_nom*1.15 C2_nom];
C1pC2_var = (C1_var.*C2_var)./(C1_var+C2_var);
Icp_var = [Icp_nom*0.75 Icp_nom*1.25 Icp_nom];

loop_count = 0;
no_of_comp = (length(R_var)-R_var_min+1)*(length(kvco_var)-kvco_var_min+1);
fig_legend = cell(no_of_comp,1);

%% Computations
for(var_R=R_var_min:length(R_var))
for(var_kvco=kvco_var_min:length(kvco_var))
for(var_C=C_var_min:length(C1_var))
for(var_Icp=Icp_var_min:length(Icp_var))

% Loop gain and closed loop transfer function


loop_count = loop_count+1;
R = R_var(1,var_R);
kvco = kvco_var(1,var_kvco);
C1 = C1_var(1,var_C);
C2 = C2_var(1,var_C);
C1pC2 = (C1*C2)/(C1+C2);
Icp = Icp_var(1,var_Icp);
k = (Icp*kvco/(2*pi*N*(C1+C2)));
tau_z = R*C1;
tau_p = R*C1pC2;
Loop_gain = tf(k*[tau_z 1],[tau_p 1 0 0]);
% figure(var_R*100+var_kvco*10+1)
% bode(Loop_gain)
[Gm,Pm,Wgm,Wpm] = margin(Loop_gain);
Phase_margin(1,loop_count) = Pm;
Bandwidth(1,loop_count) = Wpm/(2*pi*1e3);
phi_mismatch = 2*pi*Trst*Icp_mismatch*fref/Icp;
spur(1,loop_count) =
20*log10((Wpm*N*phi_mismatch)/(2*pi*sqrt(2)*fref))-20*log10(fref*tau_p*2*pi);
str = sprintf('%d : R = %.2f K, kvco = %.2f MHz/V, C1 = %.2f pF, C2
= %.2f pF, Icp = %.2f uA \n Phase margin : %.1f, Bandwidth : %.2f kHz, Ref.
spur : %.2f dB',loop_count,R/1e3,kvco/(2*pi*1e6),C1/1e-12,C2/1e-12,Icp/1e-
6,Pm,Wpm/(2*pi*1e3),spur(1,loop_count));
disp(str);
Closed_loop_gain = feedback(Loop_gain*N,1/N);
% figure(var_R*100+var_kvco*10+2)
% bode(Closed_loop_gain)

%% Noise transfer functions

% Loop filter
Z = tf((1/(C1+C2))*[tau_z 1],[tau_p 1 0]);
R_noise = 2*kb*T*R;
vlpn_by_vn = tf([C1/(C1+C2)],[tau_p 1]);
NTF_lp = Closed_loop_gain*(2*pi/Icp)*(vlpn_by_vn/Z);
Out_noise_R_comp =
power(abs(freqresp(NTF_lp,2*pi*eval_freq)),2)*R_noise;
% figure(var_R*100+var_kvco*10+4)
% bode(NTF_lp)
% figure(var_R*100+var_kvco*10+3)
for i=1:length(Out_noise_R_comp)
Out_noise_R(1,i) = Out_noise_R_comp(:,:,i);
end
Out_noise_R = 10*log10(Out_noise_R);
if(fig_on == 1)
figure(3)
semilogx(eval_freq,Out_noise_R);
hold on
end

% VCO
NTF_VCO = 1/(1+Loop_gain);
NTF_VCO_amp_sq = power(abs(freqresp(NTF_VCO,2*pi*eval_freq)),2);
% figure(var_R*100+var_kvco*10+5)
% bode(NTF_VCO)
% figure(var_R*100+var_kvco*10+6)
for i=1:length(NTF_VCO_amp_sq)
Out_noise_VCO(1,i) = 10*log10(NTF_VCO_amp_sq(:,:,i))
+VCO_noise(1,i);
end
if(VCO_noise_sw<1)
Out_noise_VCO = ones(1,length(Out_noise_VCO))*(-200);
end
if(fig_on == 1)
figure(6)
semilogx(eval_freq,Out_noise_VCO);
hold on
end

% Divider
NTF_div = Closed_loop_gain;
NTF_div_amp_sq = power(abs(freqresp(NTF_div,2*pi*eval_freq)),2);
for i=1:length(NTF_div_amp_sq)
Out_noise_div(1,i) = 10*log10(NTF_div_amp_sq(:,:,i))
+div_noise(1,i);
end
if(div_noise_sw<1)
Out_noise_div = ones(1,length(Out_noise_div))*(-200);
end
if(fig_on == 1)
figure(7)
semilogx(eval_freq,Out_noise_div);
hold on
end

% Reference clock
NTF_ref = Closed_loop_gain;
NTF_ref_amp_sq = power(abs(freqresp(NTF_ref,2*pi*eval_freq)),2);
for i=1:length(NTF_ref_amp_sq)
Out_noise_ref(1,i) = 10*log10(NTF_ref_amp_sq(:,:,i))
+crys_osc_noise(1,i);
end
if(ref_noise_sw<1)
Out_noise_ref = ones(1,length(Out_noise_ref))*(-200);
end
if(fig_on == 1)
figure(10)
semilogx(eval_freq,Out_noise_ref);
hold on
end

% PFD+CP
NTF_pfd_cp = Closed_loop_gain*(2*pi/Icp);
NTF_pfd_cp_amp_sq =
power(abs(freqresp(NTF_pfd_cp,2*pi*eval_freq)),2);
for i=1:length(NTF_pfd_cp_amp_sq)
Out_noise_pfd_cp(1,i) =
10*log10(NTF_pfd_cp_amp_sq(:,:,i)*pfd_cp_noise(1,i));
end
if(pfd_cp_noise_sw<1)
Out_noise_pfd_cp = ones(1,length(Out_noise_pfd_cp))*(-200);
end
if(fig_on == 1)
figure(8)
semilogx(eval_freq,Out_noise_pfd_cp);
hold on
end

% VCO + Loop filter + Divider noise


% figure(var_R*100+var_kvco*10+7)
total_noise =
10*log10(power(10,Out_noise_R./10)+power(10,Out_noise_VCO./10)+power(10,Out_noise_d
iv./10)+power(10,Out_noise_pfd_cp./10)+power(10,Out_noise_ref./10));
% semilogx(eval_freq,Out_noise_R);
% hold on
% semilogx(eval_freq,Out_noise_VCO);
% semilogx(eval_freq,VCO_lp_noise);
% legend('Loop filter','VCO','VCO + Loop filter');
% hold off
noise_at_2M(1,loop_count) = interp1(eval_freq,total_noise,2e6);
if(fig_on == 1)
figure(9)
semilogx(eval_freq,total_noise,'linewidth',2);
grid on
hold on
fig_legend{loop_count} = sprintf('R = %.2f K, kvco = %.2f
MHz/V, C1 = %.2f pF, C2 = %.2f pF, Icp = %.2f uA',R/1e3,kvco/(2*pi*1e6),C1/1e-
12,C2/1e-12,Icp/1e-6);
figure(20)

semilogx(eval_freq,10*log10(power(10,Out_noise_R./10)),'linewidth',2);
grid on
hold on

semilogx(eval_freq,10*log10(power(10,Out_noise_VCO./10)),'linewidth',2);

semilogx(eval_freq,10*log10(power(10,Out_noise_div./10)),'linewidth',2);

semilogx(eval_freq,10*log10(power(10,Out_noise_pfd_cp./10)),'linewidth',2);

semilogx(eval_freq,10*log10(power(10,Out_noise_ref./10)),'linewidth',2);
semilogx(eval_freq,total_noise,'linewidth',2);
end
end
end
end
end
if(fig_on == 1)
figure(3)
title('Loop filter noise');
hold off
legend(fig_legend);
figure(6)
title('VCO noise');
hold off
legend(fig_legend);
figure(7)
title('Divider noise');
hold off
legend(fig_legend);
figure(8)
title('PFD+CP noise');
hold off
legend(fig_legend);
figure(9)
title('VCO + Loop filter + Divider noise + PFD + CP');
hold off
figure(10)
title('Reference noise');
hold off
legend(fig_legend);
figure(20)
title('Phase noise at PLL output');
hold off
legend('Loop filter resistor noise','VCO noise','Divider noise','PFD + Charge
pump noise','Reference noise','Total noise');
end
%max_noise_at_2M = max(noise_at_2M);
%index_max_noise = find(noise_at_2M == max(noise_at_2M));
%str = sprintf('\n\nMax. noise at 2MHz : %f in run
%d',max_noise_at_2M,index_max_noise);
%disp(str);
%min_phase_margin = min(Phase_margin);
%index_min_pm = find(Phase_margin == min_phase_margin);
%str = sprintf('Min. phase margin : %f in run %d',min_phase_margin,index_min_pm);
%disp(str);
%min_Bandwidth = min(Bandwidth);
%index_min_bw = find(Bandwidth == min_Bandwidth);
%str = sprintf('Min. bandwidth(kHz) : %f in run %d',min_Bandwidth,index_min_bw);
%disp(str);
%max_Bandwidth = max(Bandwidth);
%index_max_bw = find(Bandwidth == max_Bandwidth);
%str = sprintf('Max. bandwidth(kHz) : %f in run %d',max_Bandwidth,index_max_bw);
%disp(str);
%max_ref_spur = max(spur);
%index_max_ref_spur = find(spur == max_ref_spur);
%str = sprintf('Max. ref spur : %f in run %d',max_ref_spur,index_max_ref_spur);
%disp(str);
str = sprintf('R = %.2fk, C1 = %.2fp, C2 = %.2fp, Icp = %.2fu',R_nom/1e3,C1_nom/1e-
12,C2_nom/1e-12,Icp_nom/1e-6);
disp(str);

You might also like