You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
331 lines
12 KiB
331 lines
12 KiB
7 months ago
|
//VerilogA for ring,neffreso,veriloga
|
||
|
//Xuanqi Chen, Zhifei Wang, Yi-Shing Chang, Jiang Xu, Jun Feng, Peng Yang, Zhehui Wang, Luan H. K. Duong, ”Modeling and Analysis of Optical Modulators Based on Free-Carrier Plasma Dispersion Effect,” IEEE Transactions on Computer-Aided Design of Integrated Circuits and Systems (TCAD), vol. 39, no. 5, pp. 977-990, May 2020.
|
||
|
|
||
|
`include "constants.vams"
|
||
|
`include "disciplines.vams"
|
||
|
|
||
|
`define MAX_TABLE_SIZE 300000
|
||
|
`define MAX_X_NUM 1000
|
||
|
//500*500=250000
|
||
|
|
||
|
module neffreso(Ipow,Iphase,Ilam,Opow,Ophase,Olam,Vbias,Gnd);
|
||
|
//Parameters
|
||
|
parameter real r = 10u from (0:inf);
|
||
|
parameter real phaseshift_ratio = 0.8407 from (0:1);
|
||
|
parameter real nref_coupler = 3.02 from (0:inf);
|
||
|
parameter real kappa_coupler = 2.15e6 from (0:inf);
|
||
|
parameter real l_coupler = 0.1u from (0:inf);
|
||
|
parameter real alpha_phaseshift_ref = 80 from (0:inf);
|
||
|
parameter real alpha_absorp = 1 from (0:inf);
|
||
|
parameter real alpha_wd = 1 from (0:inf);
|
||
|
parameter real rib_width = 0.4u from (0:inf);
|
||
|
parameter real pn_offset = 0 from [0:inf);
|
||
|
parameter real ni = 1e16 from (0:inf);
|
||
|
parameter real N_A = 5e23 from (0:inf);
|
||
|
parameter real N_D = 1e24 from (0:inf);
|
||
|
parameter real Lp = 2u from (0:inf);
|
||
|
parameter real Ln = 1u from (0:inf);
|
||
|
parameter real epsr_Si = 11.7;
|
||
|
parameter real Is = 1e-14 from (0:inf);
|
||
|
parameter real IBV = 1000u from (0:inf);
|
||
|
parameter real BV = 40 from (0:inf);
|
||
|
parameter real V0 = 1 from [0:inf);
|
||
|
parameter real Cj0 = 1.5p from [0:inf);
|
||
|
parameter real tau = 0.5n from (0:inf);
|
||
|
parameter real Rs = 55 from (0:inf);
|
||
|
parameter real emi = 1 from (0:inf);
|
||
|
parameter real Vt = 0.0259 from (0:inf);
|
||
|
parameter string neff_ps_filename = "../../../data/EIM/outputPN1.54-1.56-500.txt";
|
||
|
parameter string neff_wg_filename = "../../../data/EIM/output-wg1.54-1.56-500.txt";
|
||
|
|
||
|
input Ipow,Iphase,Ilam,Vbias;
|
||
|
output Opow,Ophase,Olam;
|
||
|
inout Gnd;
|
||
|
electrical Ipow,Iphase,Ilam,Opow,Ophase,Olam,Vbias,Nint,Gnd;
|
||
|
|
||
|
branch (Gnd,Nint) Iint;
|
||
|
branch (Nint,Gnd) CCj,CCd,Idd,RRs;
|
||
|
|
||
|
//internal variables
|
||
|
real beta_cp;
|
||
|
real k_cp_r,k_cp_i;
|
||
|
real t_cp_r,t_cp_i;
|
||
|
real beta_wg;
|
||
|
real k_wg_r,k_wg_i;
|
||
|
real beta_ps;
|
||
|
real k_ps_r,k_ps_i;
|
||
|
real c1r,c1i,c2r,c2i,cr,ci;
|
||
|
real er,ei;
|
||
|
real p_mr_r,p_mr_i;
|
||
|
real E_in_R,E_in_I,E_out_R,E_out_I;
|
||
|
real alpha_phaseshift;
|
||
|
real W,Wdp,Wdn;
|
||
|
real eps,phi_bi,phi;
|
||
|
real N_avr;
|
||
|
real gd,Id,Cj,Cd;
|
||
|
real pn00,np00;
|
||
|
real lam;
|
||
|
real neff_waveguide,neff_phaseshift_ref,neff_phaseshift;
|
||
|
|
||
|
//1550nm
|
||
|
real sigma_ne=-8.8E-22;
|
||
|
real sigma_nh=-8.5E-18;
|
||
|
real sigma_ae=8.5E-18;
|
||
|
real sigma_ah=6.0E-18;
|
||
|
|
||
|
real xlength;//=0.6u;
|
||
|
integer xnum=`MAX_X_NUM+1;
|
||
|
integer xnum2=2*`MAX_X_NUM+1;
|
||
|
real x[0:`MAX_X_NUM];
|
||
|
real np[0:`MAX_X_NUM];
|
||
|
real pp[0:`MAX_X_NUM];
|
||
|
real pn[0:`MAX_X_NUM];
|
||
|
real nn[0:`MAX_X_NUM];
|
||
|
real xx[0:2*`MAX_X_NUM+1];
|
||
|
real n[0:2*`MAX_X_NUM+1];
|
||
|
real p[0:2*`MAX_X_NUM+1];
|
||
|
integer wi,wf;
|
||
|
real dalpha_e[0:2*`MAX_X_NUM+1];
|
||
|
real dalpha_h[0:2*`MAX_X_NUM+1];
|
||
|
real dalpha[0:2*`MAX_X_NUM+1];
|
||
|
real sum_dalpha,dalpha_avr;
|
||
|
|
||
|
integer ps_file, wg_file;
|
||
|
real width_start, width_end, width_step;
|
||
|
integer width_num;
|
||
|
real lam_start, lam_end, lam_step;
|
||
|
integer lam_num;
|
||
|
integer lam_near, width_near;
|
||
|
real tmp;
|
||
|
real lam_old=0;
|
||
|
real width_old=0;
|
||
|
real neff_table_ps[0:`MAX_TABLE_SIZE] = {0};
|
||
|
real neff_lamtable_ps[0:`MAX_TABLE_SIZE] = {0};
|
||
|
real neff_widthtable_ps[0:`MAX_TABLE_SIZE] = {0};
|
||
|
real neff_table_wg[0:`MAX_TABLE_SIZE] = {0};
|
||
|
real neff_lamtable_wg[0:`MAX_TABLE_SIZE] = {0};
|
||
|
integer read_table_ps=1;
|
||
|
integer read_table_wg=1;
|
||
|
|
||
|
integer i, j;
|
||
|
|
||
|
analog initial begin
|
||
|
pn00=pow(ni,2)/N_D;
|
||
|
np00=pow(ni,2)/N_A;
|
||
|
|
||
|
eps=epsr_Si*`P_EPS0;
|
||
|
phi_bi=`P_K*$temperature/`P_Q*ln(N_A*N_D/pow(ni,2));
|
||
|
|
||
|
N_avr=N_A*N_D/(N_A+N_D);
|
||
|
end
|
||
|
|
||
|
analog begin
|
||
|
lam=V(Ilam);
|
||
|
gd=(-Is*(exp(5)-1)+IBV)/(-5*emi*Vt + BV);
|
||
|
Id=Is*(limexp(V(Nint)/(emi*Vt))-1)+V(Nint)*gd;
|
||
|
if (V(Nint) >= V0)
|
||
|
Cj=0;
|
||
|
else
|
||
|
Cj=Cj0/sqrt(1-V(Nint)/V0);
|
||
|
//Cd=Id*tau/(emi*Vt);
|
||
|
Cd=Is*(exp(V(Nint)/(emi*Vt))-1)*tau/(emi*Vt);
|
||
|
|
||
|
I(Iint) <+ V(Vbias)/Rs;
|
||
|
I(CCj) <+ Cj*ddt(V(CCj));
|
||
|
I(CCd) <+ Cd*ddt(V(CCd));
|
||
|
I(Idd) <+ Id;
|
||
|
V(RRs) <+ I(RRs)*Rs;
|
||
|
|
||
|
E_in_R=sqrt(V(Ipow))*cos(V(Iphase)/360.0*2*`M_PI);
|
||
|
E_in_I=sqrt(V(Ipow))*sin(V(Iphase)/360.0*2*`M_PI);
|
||
|
|
||
|
beta_cp = 2.0*`M_PI*nref_coupler/lam;
|
||
|
|
||
|
//k_cp = 1j*sin(kappa_coupler*l_coupler) * limexp(1j*l_coupler*beta_cp)
|
||
|
k_cp_r=-sin(kappa_coupler*l_coupler) * sin(l_coupler*beta_cp);
|
||
|
k_cp_i=sin(kappa_coupler*l_coupler) * cos(l_coupler*beta_cp);
|
||
|
//t_cp = cos(kappa_coupler*l_coupler) * limexp(1j*l_coupler*beta_cp)
|
||
|
t_cp_r=cos(kappa_coupler*l_coupler) * cos(l_coupler*beta_cp);
|
||
|
t_cp_i=cos(kappa_coupler*l_coupler) * sin(l_coupler*beta_cp);
|
||
|
|
||
|
phi=phi_bi-V(Nint);
|
||
|
if (phi<0)
|
||
|
phi=0;
|
||
|
|
||
|
W=alpha_wd * sqrt(2.0*eps*phi/(`P_Q*N_avr));
|
||
|
Wdp=N_D * W/(N_A+N_D);
|
||
|
Wdn=N_A * W/(N_A+N_D);
|
||
|
|
||
|
xlength=rib_width/2;
|
||
|
|
||
|
for (i=0; i<xnum; i=i+1) begin
|
||
|
x[i]=i*xlength/(xnum-1);
|
||
|
np[i]=np00*(exp(`P_Q*V(Nint)/(`P_K*$temperature))-1)*exp(-(x[i]-Wdp)/Ln)+np00;
|
||
|
if (x[i]>Wdp) begin
|
||
|
pp[i]=N_A;
|
||
|
end
|
||
|
else begin
|
||
|
pp[i]=0;
|
||
|
end
|
||
|
pn[i]=pn00*(exp(`P_Q*V(Nint)/(`P_K*$temperature))-1)*exp(-(x[i]-Wdn)/Lp)+pn00;
|
||
|
if (x[i]>Wdn) begin
|
||
|
nn[i]=N_D;
|
||
|
end
|
||
|
else begin
|
||
|
nn[i]=0;
|
||
|
end
|
||
|
if (np[i]<0) np[i]=0;
|
||
|
if (pn[i]<0) pn[i]=0;
|
||
|
end
|
||
|
|
||
|
for (i=0; i<2*xnum; i=i+1) begin
|
||
|
if (i<xnum) begin
|
||
|
xx[i]=-x[xnum-1-i];
|
||
|
n[i]=np[xnum-1-i];
|
||
|
p[i]=pp[xnum-1-i];
|
||
|
end
|
||
|
else begin
|
||
|
xx[i]=x[i-xnum];
|
||
|
n[i]=nn[i-xnum];
|
||
|
p[i]=pn[i-xnum];
|
||
|
end
|
||
|
// if (abs(xx[i]+rib_width/2) < 0.001u) begin
|
||
|
// wi=i;
|
||
|
// $display("wi=%d",wi);
|
||
|
// end
|
||
|
// if (abs(xx[i]-rib_width/2) < 0.001u) begin
|
||
|
// wf=i;
|
||
|
// $display("wf=%d",wf);
|
||
|
// end
|
||
|
end
|
||
|
for (i=0; i<xnum2; i=i+1) begin
|
||
|
dalpha_e[i]=n[i]*sigma_ae*1e-4;
|
||
|
dalpha_h[i]=p[i]*sigma_ah*1e-4;
|
||
|
dalpha[i]=dalpha_e[i] + dalpha_h[i];
|
||
|
end
|
||
|
|
||
|
sum_dalpha=0;
|
||
|
for (i=0; i<xnum2; i=i+1) begin
|
||
|
sum_dalpha=sum_dalpha+dalpha[i];
|
||
|
end
|
||
|
dalpha_avr=sum_dalpha/(xnum2);
|
||
|
alpha_phaseshift = alpha_phaseshift_ref + dalpha_avr;
|
||
|
|
||
|
if (read_table_ps==0 || lam_old==0 || width_old==0) begin
|
||
|
read_table_ps=1;
|
||
|
end
|
||
|
|
||
|
if (read_table_ps == 1) begin
|
||
|
ps_file=$fopen(neff_ps_filename,"r");
|
||
|
if (ps_file==0) begin
|
||
|
$display("Error: cannot open ps_file %s",neff_ps_filename);
|
||
|
$finish;
|
||
|
end
|
||
|
// else
|
||
|
// $display("ps_file %s opened successfully",neff_ps_filename);
|
||
|
$fscanf(ps_file,"%f",width_start);
|
||
|
$fscanf(ps_file,"%f",width_end);
|
||
|
$fscanf(ps_file,"%d",width_num);
|
||
|
width_step = (width_end-width_start)/(width_num-1);
|
||
|
// $display("width_start=%f, width_end=%f, width_num=%f, width_step=%f",width_start,width_end,width_num,width_step);
|
||
|
$fscanf(ps_file,"%f",lam_start);
|
||
|
$fscanf(ps_file,"%f",lam_end);
|
||
|
$fscanf(ps_file,"%d",lam_num);
|
||
|
lam_step = (lam_end-lam_start)/(lam_num-1);
|
||
|
// for (i=0; i<width_num; i=i+1) begin
|
||
|
// $fscanf(ps_file,"%f",tmp);
|
||
|
// end
|
||
|
for (i=0; i<width_num; i=i+1) begin
|
||
|
for (j=0; j<lam_num; j=j+1) begin
|
||
|
$fscanf(ps_file,"%f",tmp);
|
||
|
neff_widthtable_ps[i*lam_num+j] = width_start+i*width_step;
|
||
|
neff_lamtable_ps[i*lam_num+j] = lam_start+j*lam_step;
|
||
|
neff_table_ps[i*lam_num+j] = tmp;
|
||
|
//$display("neff_widthtable_ps[%d]=%f, neff_lamtable_ps[%d]=%f, neff_table_ps[%d]=%f",i*lam_num+j,neff_widthtable_ps[i*lam_num+j],i*lam_num+j,neff_lamtable_ps[i*lam_num+j],i*lam_num+j,neff_table_ps[i*lam_num+j]);
|
||
|
end
|
||
|
end
|
||
|
$fclose(ps_file);
|
||
|
neff_widthtable_ps[width_num*lam_num+1] = 0;
|
||
|
neff_lamtable_ps[width_num*lam_num+1] = 0;
|
||
|
neff_table_ps[width_num*lam_num+1] = 0;
|
||
|
neff_widthtable_ps[width_num*lam_num+2] = 0;
|
||
|
neff_lamtable_ps[width_num*lam_num+2] = -1;
|
||
|
neff_table_ps[width_num*lam_num+2] = 0;
|
||
|
read_table_ps=2;
|
||
|
end
|
||
|
|
||
|
if (read_table_ps == 2) begin
|
||
|
if (lam*1e6<lam_start || lam*1e6>lam_end) begin
|
||
|
$display("Warning: lam=%f is out of range [%f,%f]",lam*1e6,lam_start,lam_end);
|
||
|
end
|
||
|
if (Wdp*1e6<width_start || Wdp*1e6>width_end) begin
|
||
|
$display("Warning: Wdp=%f is out of range [%f,%f]",Wdp*1e6,width_start,width_end);
|
||
|
end
|
||
|
neff_phaseshift = $table_model(Wdp*1e6, lam*1e6, neff_widthtable_ps, neff_lamtable_ps, neff_table_ps, "3L,3L");
|
||
|
end
|
||
|
|
||
|
if (read_table_wg == 0|| lam_old==0 ) begin
|
||
|
read_table_wg=1;
|
||
|
end
|
||
|
|
||
|
if (read_table_wg == 1) begin
|
||
|
wg_file=$fopen(neff_wg_filename,"r");
|
||
|
if (wg_file==0) begin
|
||
|
$display("Error: cannot open wg_file %s",neff_wg_filename);
|
||
|
$finish;
|
||
|
end
|
||
|
$fscanf(wg_file,"%f",lam_start);
|
||
|
$fscanf(wg_file,"%f",lam_end);
|
||
|
$fscanf(wg_file,"%d",lam_num);
|
||
|
for (i=0; i<lam_num; i=i+1) begin
|
||
|
neff_lamtable_wg[i] = lam_start+i*lam_step;
|
||
|
end
|
||
|
for (j=0; j<lam_num; j=j+1) begin
|
||
|
$fscanf(wg_file,"%f",tmp);
|
||
|
neff_table_wg[j] = tmp;
|
||
|
end
|
||
|
read_table_wg=2;
|
||
|
$fclose(wg_file);
|
||
|
end
|
||
|
|
||
|
if (read_table_wg == 2) begin
|
||
|
if (lam*1e6<lam_start || lam*1e6>lam_end) begin
|
||
|
$display("Warning: lam=%f is out of range [%f,%f]",lam*1e6,lam_start,lam_end);
|
||
|
end
|
||
|
neff_waveguide = $table_model(lam*1e6, neff_lamtable_wg, neff_table_wg, "3E");
|
||
|
end
|
||
|
|
||
|
beta_wg = 2.0*`M_PI*neff_waveguide/lam;
|
||
|
beta_ps = 2.0*`M_PI*neff_phaseshift/lam;
|
||
|
|
||
|
k_wg_r=-alpha_phaseshift_ref;
|
||
|
k_wg_i=beta_wg;
|
||
|
|
||
|
k_ps_r=-alpha_phaseshift*alpha_absorp;
|
||
|
k_ps_i=beta_ps;
|
||
|
|
||
|
er = phaseshift_ratio*2.0*`M_PI*r*k_ps_r+(1.0-phaseshift_ratio)*2.0*`M_PI*r*k_wg_r;
|
||
|
ei = phaseshift_ratio*2.0*`M_PI*r*k_ps_i+(1.0-phaseshift_ratio)*2.0*`M_PI*r*k_wg_i;
|
||
|
p_mr_r = limexp(er)*cos(ei);
|
||
|
p_mr_i = limexp(er)*sin(ei);
|
||
|
|
||
|
c1r = t_cp_r + p_mr_r*((k_cp_r*k_cp_r-k_cp_i*k_cp_i)-(t_cp_r*t_cp_r-t_cp_i*t_cp_i))-p_mr_i*(2.0*k_cp_r*k_cp_i-2.0*t_cp_r*t_cp_i);
|
||
|
c1i = t_cp_i + p_mr_i*((k_cp_r*k_cp_r-k_cp_i*k_cp_i)-(t_cp_r*t_cp_r-t_cp_i*t_cp_i))+p_mr_r*(2.0*k_cp_r*k_cp_i-2.0*t_cp_r*t_cp_i);
|
||
|
c2r = 1.0-p_mr_r*t_cp_r+p_mr_i*t_cp_i;
|
||
|
c2i = p_mr_r*t_cp_i+p_mr_i*t_cp_r;
|
||
|
cr=(c1r*c2r-c1i*c2i)/(c2r*c2r+c2i*c2i);
|
||
|
ci=(c1i*c2r+c1r*c2i)/(c2r*c2r+c2i*c2i);
|
||
|
E_out_R = cr*E_in_R-ci*E_in_I;
|
||
|
E_out_I = ci*E_in_R+cr*E_in_I;
|
||
|
|
||
|
V(Opow) <+ E_out_R*E_out_R+E_out_I*E_out_I;
|
||
|
V(Ophase) <+ atan2(E_out_I,E_out_R)*360.0/(2*`M_PI);
|
||
|
V(Olam) <+ V(Ilam);
|
||
|
|
||
|
lam_old=lam;
|
||
|
width_old=Wdp;
|
||
|
end
|
||
|
|
||
|
|
||
|
endmodule
|