//VerilogA for ring,basicfilter,veriloga
//port position:
//12
//34
`include "constants.vams"
`include "disciplines.vams"

module basicfilter(Ipow1,Iphase1,Ilam1,Ipow2,Iphase2,Ilam2,Opow1,Ophase1,Olam1,Opow2,Ophase2,Olam2);
    parameter integer modespec = 1 from [1:2];
    parameter integer alpha_use_dBm = 1 from [0:1];
    parameter real l_bus = 1e-3 from [0:inf);
    parameter real r_ring = 7.5e-6 from [0:inf);
    parameter real attenu_bus_te = 0 from [0:inf);
    parameter real attenu_bus_tm = 0 from [0:inf);
    parameter real attenu_ring_te = 0 from [0:inf);
    parameter real attenu_ring_tm = 0 from [0:inf);
    parameter real phasedelay_bus_te = 0;
    parameter real phasedelay_bus_tm = 0;
    parameter real phasedelay_ring_te = 0;
    parameter real phasedelay_ring_tm = 0;
    parameter real neff_te = 2.6 from (0:inf);
    parameter real neff_tm = 2.6 from (0:inf);
    parameter real coupling_ring_te_up = 0.145 from [0:1];
    parameter real coupling_ring_tm_up = 0.145 from [0:1];
    parameter real coupling_ring_te_down = 0.145 from [0:1];
    parameter real coupling_ring_tm_down = 0.145 from [0:1];
    parameter real reffreq = 193.1T from (0:inf);
    parameter real n_gv_te = 4.2 from (0:inf);
    parameter real n_gv_tm = 4.2 from (0:inf);
    parameter real disper_te = 0;
    parameter real disper_tm = 0;
    //parameter real coupling_tem = 0;

    input Ipow1,Iphase1,Ilam1,Ipow2,Iphase2,Ilam2;
    output Opow1,Ophase1,Olam1,Opow2,Ophase2,Olam2;
    electrical Ipow1,Iphase1,Ilam1,Ipow2,Iphase2,Ilam2,Opow1,Ophase1,Olam1,Opow2,Ophase2,Olam2;

    real eeir2,eeii2,emir2,emii2,eeir3,eeii3,emir3,emii3;
    real eeor1,eeoi1,emor1,emoi1,eeor4,eeoi4,emor4,emoi4;
    real t11r,t11i,t12r,t12i,t13r,t13i,t14r,t14i,t21r,t21i,t22r,t22i,t23r,t23i,t24r,t24i,t31r,t31i,t32r,t32i,t33r,t33i,t34r,t34i,t41r,t41i,t42r,t42i,t43r,t43i,t44r,t44i;
    real beta_te,beta_tm;
    real alpha_bus_te,alpha_bus_tm,alpha_ring_te,alpha_ring_tm;
    real beta_bus_ter,beta_bus_tei,beta_bus_tmr,beta_bus_tmi,beta_ring_ter,beta_ring_tei,beta_ring_tmr,beta_ring_tmi;
    real t_te_up,t_tm_up,t_te_down,t_tm_down;
    real theta_ter,theta_tei,theta_tmr,theta_tmi;
    real kappa_te_up,kappa_tm_up,kappa_te_down,kappa_tm_down;
    real c1er,c1ei,c1em,c1mr,c1mi,c1mm,c2er,c2ei,c2em,c2mr,c2mi,c2mm,c3er,c3ei,c3em,c3mr,c3mi,c3mm;
    real c1e1r,c1e1i,c1e2r,c1e2i,c1m1r,c1m1i,c1m2r,c1m2i;
    real c2e1r,c2e1i,c2e2r,c2e2i,c2m1r,c2m1i,c2m2r,c2m2i;
    real c3e1r,c3e1i,c3e2r,c3e2i,c3m1r,c3m1i,c3m2r,c3m2i;
    real cber,cbei,cbmr,cbmi;
    real l_ring=2*`M_PI*r_ring;
    real phasedelay_bus_te_u=phasedelay_bus_te/360.0*2*`M_PI;
    real phasedelay_bus_tm_u=phasedelay_bus_tm/360.0*2*`M_PI;
    real phasedelay_ring_te_u=phasedelay_ring_te/360.0*2*`M_PI;
    real phasedelay_ring_tm_u=phasedelay_ring_tm/360.0*2*`M_PI;
    real lam,freq;
    real iph2,iph3;

    analog begin
        if (V(Ilam1) == 0) begin
            lam=V(Ilam2);
        end
        else if (V(Ilam2) == 0) begin
            lam=V(Ilam1);
        end
        else begin
            lam=V(Ilam1);
        end
        freq=`P_C/lam;
        iph2=V(Iphase2)/360.0*2*`M_PI;
        iph3=V(Iphase1)/360.0*2*`M_PI;
        if (modespec == 1) begin
            eeir2=sqrt(V(Ipow2))*cos(iph2);
            eeii2=sqrt(V(Ipow2))*sin(iph2);
            emir2=0;
            emii2=0;
            eeir3=sqrt(V(Ipow1))*cos(iph3);
            eeii3=sqrt(V(Ipow1))*sin(iph3);
            emir3=0;
            emii3=0;
        end
        else if (modespec == 2) begin
            eeir2=0;
            eeii2=0;
            emir2=sqrt(V(Ipow2))*cos(iph2);
            emii2=sqrt(V(Ipow2))*sin(iph2);
            eeir3=0;
            eeii3=0;
            emir3=sqrt(V(Ipow1))*cos(iph3);
            emii3=sqrt(V(Ipow1))*sin(iph3);
        end

        beta_te=2*`M_PI*reffreq/`P_C*neff_te+2*`M_PI/`P_C*n_gv_te*(freq-reffreq)-`M_PI*`P_C*disper_te/pow(reffreq,2)*pow(freq-reffreq,2);
        beta_tm=2*`M_PI*reffreq/`P_C*neff_tm+2*`M_PI/`P_C*n_gv_tm*(freq-reffreq)-`M_PI*`P_C*disper_tm/pow(reffreq,2)*pow(freq-reffreq,2);
        if (alpha_use_dBm == 0) begin
            alpha_bus_te=attenu_bus_te;
            alpha_bus_tm=attenu_bus_tm;
            alpha_ring_te=attenu_ring_te;
            alpha_ring_tm=attenu_ring_tm;
        end
        else if (alpha_use_dBm == 1) begin
            alpha_bus_te=attenu_bus_te/10.0*ln(10);
            alpha_bus_tm=attenu_bus_tm/10.0*ln(10);
            alpha_ring_te=attenu_ring_te/10.0*ln(10);
            alpha_ring_tm=attenu_ring_tm/10.0*ln(10);
        end


        beta_bus_ter=beta_te;
        beta_bus_tei=-0.5*alpha_bus_te;
        beta_bus_tmr=beta_tm;
        beta_bus_tmi=-0.5*alpha_bus_tm;
        beta_ring_ter=beta_te;
        beta_ring_tei=-0.5*alpha_ring_te;
        beta_ring_tmr=beta_tm;
        beta_ring_tmi=-0.5*alpha_ring_tm;

        t_te_up=sqrt(1-coupling_ring_te_up);
        t_tm_up=sqrt(1-coupling_ring_tm_up);
        t_te_down=sqrt(1-coupling_ring_te_down);
        t_tm_down=sqrt(1-coupling_ring_tm_down);
        kappa_te_up=sqrt(coupling_ring_te_up);
        kappa_tm_up=sqrt(coupling_ring_tm_up);
        kappa_te_down=sqrt(coupling_ring_te_down);
        kappa_tm_down=sqrt(coupling_ring_tm_down);
        theta_ter=beta_ring_ter*l_ring-phasedelay_ring_te_u;
        theta_tei=beta_ring_tei*l_ring;
        theta_tmr=beta_ring_tmr*l_ring-phasedelay_ring_tm_u;
        theta_tmi=beta_ring_tmi*l_ring;

        c1e1r=kappa_te_up*kappa_te_down*exp(-theta_tei*0.5)*cos(theta_ter*0.5);
        c1e1i=kappa_te_up*kappa_te_down*exp(-theta_tei*0.5)*sin(theta_ter*0.5);
        c1e2r=t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter);
        c1e2i=exp(-theta_tei)*sin(theta_ter);
        c1em=pow(t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter),2)+pow(exp(-theta_tei)*sin(theta_ter),2);
        c1er=(c1e1r*c1e2r-c1e1i*c1e2i)/c1em;
        c1ei=(c1e1r*c1e2i+c1e1i*c1e2r)/c1em;

        c1m1r=kappa_tm_up*kappa_tm_down*exp(-theta_tmi*0.5)*cos(theta_tmr*0.5);
        c1m1i=kappa_tm_up*kappa_tm_down*exp(-theta_tmi*0.5)*sin(theta_tmr*0.5);
        c1m2r=t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr);
        c1m2i=exp(-theta_tmi)*sin(theta_tmr);
        c1mm=pow(t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr),2)+pow(exp(-theta_tmi)*sin(theta_tmr),2);
        c1mr=(c1m1r*c1m2r-c1m1i*c1m2i)/c1mm;
        c1mi=(c1m1r*c1m2i+c1m1i*c1m2r)/c1mm;

        c2e1r=t_te_up-t_te_down*exp(-theta_tei)*cos(theta_ter);
        c2e1i=-t_te_down*exp(-theta_tei)*sin(theta_ter);
        c2e2r=t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter);
        c2e2i=exp(-theta_tei)*sin(theta_ter);
        c2em=pow(t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter),2)+pow(exp(-theta_tei)*sin(theta_ter),2);
        c2er=(c2e1r*c2e2r-c2e1i*c2e2i)/c2em;
        c2ei=(c2e1r*c2e2i+c2e1i*c2e2r)/c2em;

        c2m1r=t_tm_up-t_tm_down*exp(-theta_tmi)*cos(theta_tmr);
        c2m1i=-t_tm_down*exp(-theta_tmi)*sin(theta_tmr);
        c2m2r=t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr);
        c2m2i=exp(-theta_tmi)*sin(theta_tmr);
        c2mm=pow(t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr),2)+pow(exp(-theta_tmi)*sin(theta_tmr),2);
        c2mr=(c2m1r*c2m2r-c2m1i*c2m2i)/c2mm;
        c2mi=(c2m1r*c2m2i+c2m1i*c2m2r)/c2mm;

        c3e1r=t_te_down-t_te_up*exp(-theta_tei)*cos(theta_ter);
        c3e1i=-t_te_up*exp(-theta_tei)*sin(theta_ter);
        c3e2r=t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter);
        c3e2i=exp(-theta_tei)*sin(theta_ter);
        c3em=pow(t_te_up*t_te_down-exp(-theta_tei)*cos(theta_ter),2)+pow(exp(-theta_tei)*sin(theta_ter),2);
        c3er=(c3e1r*c3e2r-c3e1i*c3e2i)/c3em;
        c3ei=(c3e1r*c3e2i+c3e1i*c3e2r)/c3em;

        c3m1r=t_tm_down-t_tm_up*exp(-theta_tmi)*cos(theta_tmr);
        c3m1i=-t_tm_up*exp(-theta_tmi)*sin(theta_tmr);
        c3m2r=t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr);
        c3m2i=exp(-theta_tmi)*sin(theta_tmr);
        c3mm=pow(t_tm_up*t_tm_down-exp(-theta_tmi)*cos(theta_tmr),2)+pow(exp(-theta_tmi)*sin(theta_tmr),2);
        c3mr=(c3m1r*c3m2r-c3m1i*c3m2i)/c3mm;
        c3mi=(c3m1r*c3m2i+c3m1i*c3m2r)/c3mm;

        cber=exp(beta_bus_tei*l_bus)*cos(-beta_bus_ter*l_bus-phasedelay_bus_te_u);
        cbei=exp(beta_bus_tei*l_bus)*sin(-beta_bus_ter*l_bus-phasedelay_bus_te_u);
        cbmr=exp(beta_bus_tmi*l_bus)*cos(-beta_bus_tmr*l_bus-phasedelay_bus_tm_u);
        cbmi=exp(beta_bus_tmi*l_bus)*sin(-beta_bus_tmr*l_bus-phasedelay_bus_tm_u);

        t11r=c1er*cber-c1ei*cbei;
        t11i=c1er*cbei+c1ei*cber;
        t12r=0;
        t12i=0;
        t13r=c3er*cber-c3ei*cbei;
        t13i=c3er*cbei+c3ei*cber;
        t14r=0;
        t14i=0;
        t21r=0;
        t21i=0;
        t22r=c1mr*cbmr-c1mi*cbmi;
        t22i=c1mr*cbmi+c1mi*cbmr;
        t23r=0;
        t23i=0;
        t24r=c3mr*cbmr-c3mi*cbmi;
        t24i=c3mr*cbmi+c3mi*cbmr;
        t31r=c2er*cber-c2ei*cbei;
        t31i=c2er*cbei+c2ei*cber;
        t32r=0;
        t32i=0;
        t33r=c1er*cber-c1ei*cbei;
        t33i=c1er*cbei+c1ei*cber;
        t34r=0;
        t34i=0;
        t41r=0;
        t41i=0;
        t42r=c2mr*cbmr-c2mi*cbmi;
        t42i=c2mr*cbmi+c2mi*cbmr;
        t43r=0;
        t43i=0;
        t44r=c1mr*cbmr-c1mi*cbmi;
        t44i=c1mr*cbmi+c1mi*cbmr;

        eeor1=t11r*eeir2+t12r*emir2+t13r*eeir3+t14r*emir3-t11i*eeii2-t12i*emii2-t13i*eeii3-t14i*emii3;
        eeoi1=t11r*eeii2+t12r*emii2+t13r*eeii3+t14r*emii3+t11i*eeir2+t12i*emir2+t13i*eeir3+t14i*emir3;
        emor1=t21r*eeir2+t22r*emir2+t23r*eeir3+t24r*emir3-t21i*eeii2-t22i*emii2-t23i*eeii3-t24i*emii3;
        emoi1=t21r*eeii2+t22r*emii2+t23r*eeii3+t24r*emii3+t21i*eeir2+t22i*emir2+t23i*eeir3+t24i*emir3;
        eeor4=t31r*eeir2+t32r*emir2+t33r*eeir3+t34r*emir3-t31i*eeii2-t32i*emii2-t33i*eeii3-t34i*emii3;
        eeoi4=t31r*eeii2+t32r*emii2+t33r*eeii3+t34r*emii3+t31i*eeir2+t32i*emir2+t33i*eeir3+t34i*emir3;
        emor4=t41r*eeir2+t42r*emir2+t43r*eeir3+t44r*emir3-t41i*eeii2-t42i*emii2-t43i*eeii3-t44i*emii3;
        emoi4=t41r*eeii2+t42r*emii2+t43r*eeii3+t44r*emii3+t41i*eeir2+t42i*emir2+t43i*eeir3+t44i*emir3;

        if (modespec == 1) begin
            V(Opow1) <+ pow(eeor1,2)+pow(eeoi1,2);
            V(Ophase1) <+ atan2(eeoi1,eeor1)*360.0/(2*`M_PI);
            V(Opow2) <+ pow(eeor4,2)+pow(eeoi4,2);
            V(Ophase2) <+ atan2(eeoi4,eeor4)*360.0/(2*`M_PI);
        end
        else if (modespec == 2) begin
            V(Opow1) <+ pow(emor1,2)+pow(emoi1,2);
            V(Ophase1) <+ atan2(emoi1,emor1)*360.0/(2*`M_PI);
            V(Opow2) <+ pow(emor4,2)+pow(emoi4,2);
            V(Ophase2) <+ atan2(emoi4,emor4)*360.0/(2*`M_PI);
        end
        V(Olam1) <+ lam;
        V(Olam2) <+ lam;
    end

endmodule