//VerilogA for modulator,neffmz,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_MODES 200 `define MAX_ITER 10000 `define IDX_NUM 10000 `define TOLERANCE 0.0000000001 `define MAX_TABLE_SIZE 300000 module neffmz(Ipow,Iphase,Ilam,Opow,Ophase,Olam,Vbias,Gnd); parameter real design_lam = 1.55e-6 from (0:inf); parameter real n_ps = 3.45 from (0:inf); parameter real n_sub = 1.45 from (0:inf); parameter real width_MMI = 3e-6 from (0:inf); parameter real width_port = 0.45e-6 from (0:inf); parameter real port_offset = 0.75e-6 from (0:inf); parameter real thickness = 0.22e-6 from (0:inf); parameter real alpha_mmi = 80 from (0:inf); parameter real l_ps = 0.1e-6 from (0:inf); parameter real l_arm = 40e-6 from (0:inf); parameter real alpha_phaseshift_ref = 80 from [0:inf); parameter real alpha_waveguide = 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.4e-6 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 = 2e-6 from (0:inf); parameter real Ln = 1e-6 from (0:inf); parameter real epsr_Si = 11.7 from (0:inf); 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"; input Ipow,Iphase,Ilam,Vbias; output Opow,Ophase,Olam; inout Gnd; electrical Ipow,Iphase,Ilam,Vbias,Opow,Ophase,Olam,Nint,Gnd; branch (Gnd,Nint) Iint; branch (Nint,Gnd) CCj,CCd,Idd,RRs; real ulam, ulam0, uwidth_in, uwidth_MMI, uoffset, uthickness, alpha0; real k1_ref, kc_ref; integer mode_num, mode_num_ref; real beta_x_MMI, beta_in, beta_x_in; real neff_MMI[0:`MAX_MODES]; real beta_MMI[0:`MAX_MODES]; real length_MMI; real ky_in, gamma_in; real ky_MMI[0:`MAX_MODES]; real gamma_MMI[0:`MAX_MODES]; real c0; real c0_dis[0:`MAX_MODES]; real icoff[0:`MAX_MODES]; real delta_beta; real ocoff_r[0:`MAX_MODES]; real ocoff_i[0:`MAX_MODES]; real c1r, c1i, c2r, c2i; real inr, ini, out1r, out1i, out2r, out2i; real sum_outfield1, sum_outfield2, sum_outfield3, sum_outfield4; real sum_singlemode1,sum_singlemode2,sum_singlemode3,sum_singlemode4; real border; integer i, j; real p0=1; real h; real beta_ps; real k_ps_r,k_ps_i; real p_ps_r,p_ps_i,p_wg_r,p_wg_i; real E_in1_r,E_in1_i,E_in2_r,E_in2_i; real E_out1_r,E_out1_i,E_out2_r,E_out2_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_phaseshift_ref,neff_phaseshift; real cp_tr11_r,cp_tr11_i,cp_tr12_r,cp_tr12_i,cp_tr21_r,cp_tr21_i,cp_tr22_r,cp_tr22_i; real ar_tr11_r,ar_tr11_i,ar_tr12_r,ar_tr12_i,ar_tr21_r,ar_tr21_i,ar_tr22_r,ar_tr22_i; real t1_11_r,t1_11_i,t1_12_r,t1_12_i,t1_21_r,t1_21_i,t1_22_r,t1_22_i; real t2_11_r,t2_11_i,t2_12_r,t2_12_i,t2_21_r,t2_21_i,t2_22_r,t2_22_i; //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=10001; real x[0:10000]; real np[0:10000]; real pp[0:10000]; real pn[0:10000]; real nn[0:10000]; real xx[0:20001]; real n[0:20001]; real p[0:20001]; real wi,wf; real dalpha_e[0:20001]; real dalpha_h[0:20001]; real dalpha[0:20001]; real sum_dalpha; real dalpha_avr; integer ps_file; real width_start, width_end, width_step; real lam_start, lam_end, lam_step; integer width_num, lam_num; 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}; integer read_table_ps=1; analog function real findzeropoint_rect_x; input x_lower_input, x_upper_input, Vx; real x_lower_input, x_upper_input, Vx; real iter_count; real x_lower, x_upper; real y_mid; real y_lower, x_mid; begin findzeropoint_rect_x = -1; x_lower = x_lower_input; x_upper = x_upper_input; iter_count = 0; y_mid = 1; while (iter_count<`MAX_ITER && abs(y_mid) > `TOLERANCE) begin x_mid = (x_lower + x_upper) / 2; y_lower = tan(x_lower / 2) - sqrt(pow(Vx,2) - pow(x_lower,2)) / x_lower; y_mid = tan(x_mid / 2) - sqrt(pow(Vx,2) - pow(x_mid,2)) / x_mid; if (abs(y_mid) < `TOLERANCE) begin findzeropoint_rect_x = x_mid; end if (y_mid * y_lower < 0) x_upper = x_mid; else x_lower = x_mid; iter_count = iter_count + 1; end if (findzeropoint_rect_x == -1) $display("No zero point found in the given range. Please try again with different range."); end endfunction analog function real findzeropoint_rect_y; input x_lower_input, x_upper_input, Vy, m; real x_lower_input, x_upper_input, Vy, m; real iter_count; real x_lower, x_upper; real y_mid; real y_lower, x_mid; begin x_lower = x_lower_input; x_upper = x_upper_input; iter_count = 0; y_mid = 1; findzeropoint_rect_y = -1; while (iter_count<`MAX_ITER && abs(y_mid) > `TOLERANCE) begin x_mid = (x_lower + x_upper) / 2; y_lower = tan(x_lower / 2 - m * `M_PI / 2) - sqrt((pow(Vy,2) - pow(x_lower,2))) / x_lower; y_mid = tan(x_mid / 2 - m * `M_PI / 2) - sqrt((pow(Vy,2) - pow(x_mid,2))) / x_mid; if (abs(y_mid) < `TOLERANCE) findzeropoint_rect_y = x_mid; if (y_mid * y_lower < 0) x_upper = x_mid; else x_lower = x_mid; iter_count = iter_count + 1; end if (findzeropoint_rect_y == -1) $display("No zero point found in the given range. Please try again with different range."); end endfunction analog function real eim_rect; input lam, width, thickness, n_ps, n_sub, numflag, mode_index; real lam, width, thickness, n_ps, n_sub; integer numflag, mode_index; real k1, Vx, yx, hx, beta_x, neff_x_MMI, Vy, yy, hxy; real beta_xy[0:`MAX_MODES]; real neff_xy[0:`MAX_MODES]; real beta_xy_out[0:`MAX_MODES]; real neff_xy_out[0:`MAX_MODES]; integer i, m, mode_num; begin k1=2*`M_PI*n_ps/lam; Vx=2*`M_PI/lam*thickness*sqrt((pow(n_ps,2)-pow(n_sub,2))); yx=findzeropoint_rect_x(1e-6,min(`M_PI,Vx),Vx); hx=yx/thickness; beta_x=sqrt(pow(k1,2)-pow(hx,2)); neff_x_MMI=lam*beta_x/(2*`M_PI); Vy=2*`M_PI/lam*width*sqrt((pow(neff_x_MMI,2)-pow(n_sub,2))); i=0; m=0; while (m*`M_PI=Vy // break hxy=yy/width; beta_xy[i]=sqrt(pow(beta_x,2)-pow(hxy,2)); neff_xy[i]=lam*beta_xy[i]/(2*`M_PI); i=i+1; end mode_num=m-1; if (numflag==1 || numflag==2) begin for (i=0;i width / 2) fieldfunc=c0 * cos(ky * width / 2 - fai) * exp(-gamma * ((y - offset) - width / 2)); else fieldfunc=c0 * cos(ky * width / 2 + fai) * exp(gamma * ((y - offset) + width / 2)); end endfunction analog function real normpower_fieldfunc_quad; input width,offset,ky,gamma,m,c0,width_MMI,border; real width,offset,ky,gamma,m,c0,width_MMI,border; real n,h; // real border=width_MMI/2; integer i; real sum; begin n=`IDX_NUM; h=border*2/n; sum=0.5*(pow(abs(fieldfunc(-1*border,width,offset,ky,gamma,m,c0)),2)+pow(abs(fieldfunc(border,width,offset,ky,gamma,m,c0)),2)); for (i=1;i= 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; phi=phi_bi-V(Nint); // $display("V(Nint)=%e",V(Nint)); if (phi<0) phi=0; // $display("phi=%e",phi); 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); for (i=0; iWdp) 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 (ilam_end) begin $display("Warning: lam=%f is out of range [%f,%f]",lam*1e6,lam_start,lam_end); end if (Wdp*1e6width_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); // $display("neff=%f",neff_phaseshift); end beta_ps = 2.0*`M_PI*neff_phaseshift/lam; k_ps_r=-alpha_phaseshift*alpha_absorp; k_ps_i=beta_ps; p_ps_r=exp(k_ps_r*l_ps)*cos(k_ps_i*l_ps); p_ps_i=exp(k_ps_r*l_ps)*sin(k_ps_i*l_ps); p_wg_r=exp((k_ps_r+alpha_waveguide-alpha_phaseshift_ref)*(l_ps+l_arm))*cos((k_ps_i)*(l_ps+l_arm)); p_wg_i=exp((k_ps_r+alpha_waveguide-alpha_phaseshift_ref)*(l_ps+l_arm))*sin((k_ps_i)*(l_ps+l_arm)); // $display("p_ps_r=%g, p_ps_i=%g, p_wg_r=%g, p_wg_i=%g",p_ps_r,p_ps_i,p_wg_r,p_wg_i); ar_tr11_r=p_ps_r; ar_tr11_i=p_ps_i; ar_tr12_r=0; ar_tr12_i=0; ar_tr21_r=0; ar_tr21_i=0; ar_tr22_r=p_wg_r; ar_tr22_i=p_wg_i; // $display("p_ps_r=%f, p_ps_i=%f, p_wg_r=%f, p_wg_i=%f",p_ps_r,p_ps_i,p_wg_r,p_wg_i); t1_11_r=c1r*ar_tr11_r-c1i*ar_tr11_i+c2r*ar_tr21_r-c2i*ar_tr21_i; t1_11_i=c1r*ar_tr11_i+c1i*ar_tr11_r+c2r*ar_tr21_i+c2i*ar_tr21_r; t1_12_r=c1r*ar_tr12_r-c1i*ar_tr12_i+c2r*ar_tr22_r-c2i*ar_tr22_i; t1_12_i=c1r*ar_tr12_i+c1i*ar_tr12_r+c2r*ar_tr22_i+c2i*ar_tr22_r; t1_21_r=c2r*ar_tr11_r-c2i*ar_tr11_i-c1r*ar_tr21_r+c1i*ar_tr21_i; t1_21_i=c2r*ar_tr11_i+c2i*ar_tr11_r-c1r*ar_tr21_i-c1i*ar_tr21_r; t1_22_r=c2r*ar_tr12_r-c2i*ar_tr12_i-c1r*ar_tr22_r+c1i*ar_tr22_i; t1_22_i=c2r*ar_tr12_i+c2i*ar_tr12_r-c1r*ar_tr22_i-c1i*ar_tr22_r; t2_11_r=t1_11_r*c1r-t1_11_i*c1i+t1_12_r*c2r-t1_12_i*c2i; t2_11_i=t1_11_r*c1i+t1_11_i*c1r+t1_12_r*c2i+t1_12_i*c2r; t2_12_r=t1_11_r*c2r-t1_11_i*c2i+t1_12_r*c1r-t1_12_i*c1i; t2_12_i=t1_11_r*c2i+t1_11_i*c2r+t1_12_r*c1i+t1_12_i*c1r; t2_21_r=t1_21_r*c1r-t1_21_i*c1i+t1_22_r*c2r-t1_22_i*c2i; t2_21_i=t1_21_r*c1i+t1_21_i*c1r+t1_22_r*c2i+t1_22_i*c2r; t2_22_r=t1_21_r*c2r-t1_21_i*c2i+t1_22_r*c1r-t1_22_i*c1i; t2_22_i=t1_21_r*c2i+t1_21_i*c2r+t1_22_r*c1i+t1_22_i*c1r; // $display("t2_11_r=%f, t2_11_i=%f, t2_12_r=%f, t2_12_i=%f, t2_21_r=%f, t2_21_i=%f, t2_22_r=%f, t2_22_i=%f",t2_11_r,t2_11_i,t2_12_r,t2_12_i,t2_21_r,t2_21_i,t2_22_r,t2_22_i); inr=sqrt(V(Ipow))*cos(V(Iphase)/360.0*2*`M_PI); ini=sqrt(V(Ipow))*sin(V(Iphase)/360.0*2*`M_PI); out1r=t2_11_r*inr-t2_11_i*ini; out1i=t2_11_r*ini+t2_11_i*inr; out2r=t2_21_r*inr-t2_21_i*ini; out2i=t2_21_r*ini+t2_21_i*inr; V(Olam) <+ lam; V(Opow) <+ pow(out1r,2)+pow(out1i,2); V(Ophase) <+ atan2(out1i,out1r)*360.0/(2*`M_PI); end endmodule