//-----------------------各種コンストラクタおよび関数------------------------

//実部虚部
function realimg(re,im){
    if(re == null){ this.re=0;
	}else{ this.re=re; }
    if(im == null){	this.im=0;
	}else{ this.im=im; }
}

//-----------------------------------------------------
//-----------------------複素四則演算---------------------

function comwa(zz1,zz2){
	var zz3=new realimg(zz1.re+zz2.re, zz1.im+zz2.im);
	return zz3;	
}

function comsa(zz1,zz2){
	var zz3=new realimg(zz1.re-zz2.re, zz1.im-zz2.im);
	return zz3;	
}

function comsk(zz1,zz2){
	var zz3=new realimg(zz1.re*zz2.re-zz1.im*zz2.im, zz1.re*zz2.im+zz1.im*zz2.re);
	return zz3;	
}

function comsy(zz1,zz2){
	var bunbo=zz2.re*zz2.re+zz2.im*zz2.im
	var zz3=new realimg((zz1.re*zz2.re+zz1.im*zz2.im)/bunbo, (zz1.im*zz2.re-zz1.re*zz2.im)/bunbo);
	return zz3;	
}

function comabs(zz){
	var zzabs=Math.sqrt(zz.re*zz.re+zz.im*zz.im);
	return zzabs;
}
//-----------------------------------------------------

//-----------------------------------------------------
//-----------------------複素行列積---------------------
function mat4x4(rr,rc,cr,cc){	//row column
    if(rr == null){ this.rr=new realimg(0,0);
	}else{ this.rr=rr; }
    if(rc == null){ this.rc=new realimg(0,0);
	}else{ this.rc=rc; }
    if(cr == null){ this.cr=new realimg(0,0);
	}else{ this.cr=cr; }
    if(cc == null){ this.cc=new realimg(0,0);
	}else{ this.cc=cc; }
}

function comatimes(FF,GG){	//matrix x matrix
	var HHrr=comwa( comsk(FF.rr,GG.rr), comsk(FF.rc,GG.cr) );
	var HHrc=comwa( comsk(FF.rr,GG.rc), comsk(FF.rc,GG.cc) );
	var HHcr=comwa( comsk(FF.cr,GG.rr), comsk(FF.cc,GG.cr) );
	var HHcc=comwa( comsk(FF.cr,GG.rc), comsk(FF.cc,GG.cc) );

	var HH=new mat4x4(HHrr,HHrc,HHcr,HHcc);
	return HH;
}

function FtoS(FF,Z1,Z2,type){
	var bunbo=comwa(comwa(FF.rc,comsk(comsk(FF.cr,Z1),Z2)),comwa(comsk(FF.rr,Z2),comsk(FF.cc,Z1)));
	if(type==1){
		var S11=comsy(comwa( comsa( FF.rc, comsk(comsk(FF.cr,Z1),Z2)) , comsa(comsk(FF.rr,Z2),comsk(FF.cc,Z1))),bunbo);
		var S11dB=20*Math.log(comabs(S11))/Math.LN10;
		return S11dB;
	}else if(type==2){
		var Z1Z2=comsk(Z1,Z2);
		var bunsi=new realimg(Math.sqrt(4*Z1Z2.re),0)
		var S21=comsy(bunsi,bunbo);
		var S21dB=20*Math.log(comabs(S21))/Math.LN10;
		return S21dB;
	}
}
//-----------------------------------------------------

//複素共役を返す関数
function compcon(zz){
	var zzk=new realimg(zz.re,-zz.im);
	return zzk;
}

//UV座標
function positUV(uu,vv){
	this.uu=uu;
	this.vv=vv;
}

//中心位置(x座標のみ)と半径の記述
function positAR(am,ra){
	this.am=am;
	this.ra=ra;
}

//実部の値を中心座標と半径に変換
function ReToAR(RRe){
	var AR = new positAR( RRe/(RRe+1) , 1/(RRe+1) );
	return AR;
}

//実部の値を中心座標と半径に変換　中心座標の符号がマイナスのバージョン
function ReToARG(RRe){
	var AR = new positAR( -RRe/(RRe+1) , 1/(RRe+1) );
	return AR;
}

//アングルを４つ記録しておけるコンストラクタ
function angleFour(a1,a2,a3,a4){
	this.a1=a1;
	this.a2=a2;
	this.a3=a3;
	this.a4=a4;
}

//アングルを2つ記録しておけるコンストラクタ
function angleTwo(a1,a2){
	this.start=a1;
	this.finish=a2;
}

//二乗する関数
function pow2(num){
	return Math.pow(num,2);
}

//少数点第1位まで四捨五入
function round1(num){
	return Math.round(num*1e1)/1e1;
}

//少数点第2位まで四捨五入
function round2(num){
	return Math.round(num*1e2)/1e2;
}

//10を底とする対数関数
function log10(num) { 
	return Math.log(num)/Math.log(10)
}

//インピーダンスをチャート上のUV座標に変換する関数
function RXtoUV(ZZ){
	var uu=( pow2(ZZ.re)+pow2(ZZ.im)-1 )/( pow2(ZZ.re+1)+pow2(ZZ.im) );
	var vv=(2*ZZ.im)/( pow2(ZZ.re+1)+pow2(ZZ.im) );
	var UV = new positUV(uu , vv);
	return UV;
}

//UV座標をRXに変換
function UVtoRX(UV){
	var RR=(1-pow2(UV.uu)-pow2(UV.vv) ) / (1-2*UV.uu+pow2(UV.uu)+pow2(UV.vv));
	var XX=2*UV.vv / (1-2*UV.uu+pow2(UV.uu)+pow2(UV.vv) );
	var RX=new realimg(RR,XX);
	return RX;
}


//インピーダンスをアドミタンスに変換する関数
function RXtoGB(ZZ){
	var GB;
	if(ZZ.re==0 && ZZ.im==0){
		GB=new realimg(1/0,1/0);
	}else{
		GB=new realimg( ZZ.re/(pow2(ZZ.re)+pow2(ZZ.im) ) , -ZZ.im/( pow2(ZZ.re)+pow2(ZZ.im) )  );
	}
	return GB;
}

function ThreePtoCurv(p1,p3){	//3点から円の中心位置と半径をもとめる
	var amp=(pow2(p3.uu)+pow2(p3.vv)-pow2(p1.uu)-pow2(p1.vv))/(2*(p3.uu-p1.uu));
	var radias=Math.sqrt(pow2(p1.uu)+pow2(p1.vv)-2*p1.uu*amp +pow2(amp));
	if(radias<0) radias=-radias;
	var Curv=new positAR(amp,radias);
	return Curv;
}

//２円の交点(x,y座標およびそれぞれの角度)を求める関数  fugoによって交点y座標の符号を選べる
function crossp(curv1,curv2,fugo){
	var CXY;
	var CX=(pow2(curv1.am)-pow2(curv2.am)-pow2(curv1.ra)+pow2(curv2.ra))/(2*(curv1.am-curv2.am));
	var CY=pow2(curv1.ra)-pow2(CX-curv1.am);
	
	if(pow2(curv1.ra)<pow2(CX-curv1.am)){
		CXY= new positUV(-10,-10);
		return CXY;					//sqrt(負)を回避し，交点が無いことをCXY=(-10,-10)で知らせる
	}

	CY=Math.sqrt(pow2(curv1.ra)-pow2(CX-curv1.am));
	if(fugo){
		CXY = new positUV(CX,CY);
	}else{
		CXY = new positUV(CX,-CY);
	}
	return CXY;
}

  
 //マッチングカーブに必要な4つの角度を求める関数
function ANG4(UV1,UV2,Curv1,Curv2,crop){
	var Ag1=Math.atan2(-UV1.vv,UV1.uu - Curv1.am);	  //Zsの角度を計算
    var Ag2=Math.atan2(-crop.vv , crop.uu - Curv1.am);	  //Crossの角度1を計算
    var Ag3=Math.atan2(-UV2.vv , UV2.uu - Curv2.am);	  //ZLの角度を計算
    var Ag4=Math.atan2(-crop.vv,crop.uu - Curv2.am);	  //Crossの角度2を計算
	var angel=new angleFour(Ag1,Ag2,Ag3,Ag4);
	return angel;
}

function ANG2(UV1,UV2,Curv){
	var Ag1=Math.atan2(UV1.vv,Curv.am-UV1.uu)+Math.PI;	  //Zsの角度を計算
	var Ag2=Math.atan2(UV2.vv,Curv.am-UV2.uu)+Math.PI;	  //Zsの角度を計算

	var angel=new angleTwo(Ag1,Ag2);
	return angel;
}

function ANG2msl(UV1,sita,Curv){
	var Ag1=Math.atan2(UV1.vv,Curv.am-UV1.uu)+Math.PI;	  //Zsの角度を計算
	var Ag2=Ag1+sita;

	var angel=new angleTwo(Ag1,Ag2);
	return angel;
}

//SWRとリターンロスを表示する
function param(uv){
//  var gama=Math.abs(Math.sqrt(pow2(uv.uu)+pow2(uv.vv)));	//反射係数ガンマの導出
//  document.formResult.SWR.value=round2((1+gama)/(1-gama));		//SWR値の算出
//  document.formResult.RL.value=round2(-20*log10(gama));				//リターンロスの算出
}

function CalcSWR(z,z0){
	var re=((z.re-z0)*(z.re+z0)+pow2(z.im))/(pow2(z.re+z0)+pow2(z.im));
	var im=(2*z.im*z0)/(pow2(z.re+z0)+pow2(z.im))
	var SWR=new realimg(re.im);
	return SWR;
}

//角度を正規化する関数
function StdPI(ang){
	if(ang<0){
		return ang+2*Math.PI;
	}else if(ang>(2*Math.PI)){
		return ang-2*Math.PI;
	}else{
		return ang;
	}
}

function StdPI2(ang){
	if(ang<0){
		return ang+Math.PI;
	}else{
		return ang+Math.PI;
	}
}

function StdAng(ang){
	ang.a1=StdPI(ang.a1);
	ang.a2=StdPI(ang.a2);
	ang.a3=StdPI(ang.a3);
	ang.a4=StdPI(ang.a4);
	return ang;
}
	

function CalcZMSL(n,zL,betas){		//MSLのインピーダンスを計算
//nは線路の特性インピーダンスとスミスの特性インピーダンスの比
//zLはスミスの特性インピーダンスで規格化されたインピーダンス
//betasは2πnのnのこと
	var beta=2*Math.PI*betas;
	var Zmother=pow2(n-zL.im*Math.tan(beta))+pow2(zL.re*Math.tan(beta));
	var Rmsl=n*(zL.re*(n-zL.im*Math.tan(beta))+zL.re*Math.tan(beta)*(zL.im+n*Math.tan(beta)))/Zmother;
	var Xmsl=n*((zL.im+n*Math.tan(beta))*(n-zL.im*Math.tan(beta))-pow2(zL.re)*Math.tan(beta))/Zmother;
	var Zmsl=new realimg(Rmsl,Xmsl);
	return Zmsl;  //スミスの特性インピーダンスで規格化されたインピーダンスを返す
}

function FindZero(n,r,x){			//伝送線路円の虚部がゼロとなる点を2つ求める
	var B;
	var tansita1;
	var tansita2
	if(x==0){			
		B=0;			//虚部がゼロのときBを無理矢理ゼロにする
		var tansita1=Math.PI/2;			//無理矢理0とπにする
		var tansita2=0;
	}else{
		B=(pow2(x)+pow2(r)-pow2(n))/(n*x);
		var tansita1=Math.atan((-B+Math.sqrt(pow2(B)+4))/2);
		var tansita2=Math.atan((-B-Math.sqrt(pow2(B)+4))/2);
	}
	var tansita = new realimg(tansita1,tansita2);
	return tansita;
}

function mslUVout(UV,curv,sita){	//初期位置、円、回転角より出力位置を求める
	var s=(UV.uu-curv.am)*Math.cos(-sita)-UV.vv*Math.sin(-sita)+curv.am;
	var t=(UV.uu-curv.am)*Math.sin(-sita)+UV.vv*Math.cos(-sita);
	var UVout=new positUV(s,t);
	return UVout;
}

function FindMSLcurv(n,zL){			//伝送線路円を求める関数
	var Fzero=FindZero(n,zL.re,zL.im);			//伝送線路円の虚部がゼロとなる点を2つ求める
	
	var boss=Fzero.re/(2*Math.PI);		//ひとつめのゼロ点の位相(boss=2*PI*n)
	var Zzero1=CalcZMSL(n,zL,boss);		//ひとつめのゼロ点のインピーダンス
	var UVzero1=RXtoUV(Zzero1);			//ひとつめのゼロ点のUV座標
	
	boss=Fzero.im/(2*Math.PI);		//ふたつめのゼロ点の位相(boss=2*PI*n)
	var Zzero2=CalcZMSL(n,zL,boss);		//ふたつめのゼロ点のインピーダンス
	var UVzero2=RXtoUV(Zzero2);			//ふたつめのゼロ点のUV座標

	var UVcenter=new positUV((UVzero1.uu+UVzero2.uu)/2,(UVzero1.vv+UVzero2.vv)/2);
	var Rcenter=Math.abs(UVzero1.uu-UVcenter.uu);	//虚部ゼロ点と中心点から半径を求める
	var MSLcurv=new positAR(UVcenter.uu,Rcenter);		//伝送線路によるインピーダンスの円　(中心位置、半径)の形式
	return MSLcurv;
}

function CalcLstubS(b1,b2,nstb,freq){	//ショートスタブの長さを求める
	//スタブの波長短縮率を求める
// 	var mini=CalcLamdaE(true);	//波長短縮率
	var mini=ministb;
	
	//	スタブ長を求める部分	
	var xstb = 1/(b1-b2);
	var StubL = round2(3E8/(2*Math.PI*freq)*Math.atan(xstb/nstb)*mini*1E3);
	if(StubL<0){	//λ/4のポイントを超えて回ったときは，負の値を半波長から引く．
		var LamdaE=LamdaStb;
		StubL=round2(LamdaE/2+StubL);
	}
	return StubL;
}

function CalcLstubO(b1,b2,nstb,freq){
	//スタブの波長短縮率を求める
// 	var mini=CalcLamdaE(true);	//波長短縮率
 	var mini=ministb;
 	var xstb = 1/(b1-b2);
 	var StubL = round2(3E8*mini/(2*Math.PI*freq)*Math.atan(-nstb/xstb)*1E3);
	if(StubL<0){
		var LamdaE=LamdaStb;
		StubL=round2(LamdaE/2+StubL);
	}
 	return StubL;
}

//伝送線路が左側にある回路の場合
function CalcLmsl1(z1,z2,Y,nmsl,freq,whichC){	//	伝送線路長を求める
// 	var mini=CalcLamdaE(false);	//波長短縮率
 	var mini=minimsl;

	var z1nmsl=new realimg(z1.re/nmsl,z1.im/nmsl);	//zsを伝送線路の特性インピーダンスで規格化
	var z2nmsl=new realimg(z2.re/nmsl,z2.im/nmsl);	//zLを伝送線路の特性インピーダンスで規格化
	var UVz1nmsl=RXtoUV(z1nmsl);
	var UVz2nmsl=RXtoUV(z2nmsl);
	var Ynmsl=new realimg(Y.re*nmsl,Y.im*nmsl);
	var MSLcurv2=FindMSLcurv2(nmsl,z1);	//
	var Gcurv2 = ReToARG(Ynmsl.re);	  //YLのコンダクタンス円の中心点と半径取得
	var crop2= crossp(Gcurv2,MSLcurv2,whichC);	  //交点の座標を取得
	var Zc2=UVtoRX(crop2);		//交点のインピーダンスを求める
	var Yc2=RXtoGB(Zc2);		//交点のアドミタンスを求める
	var angel2=ANG4(UVz1nmsl,UVz2nmsl,MSLcurv2,Gcurv2,crop2);		//マッチングカーブの4角度を取得
	angel2=StdAng(angel2);
	if(angel2.a1 > angel2.a2){		//角度を正しく表記させとく(一周したら2π足す)
		angel2.a2=angel2.a2+2*Math.PI
	}
	//伝送線路長　スミスチャートの一周が0.5λであることを考慮し、L=0.5*sita/2PI*Lamdaで求まる
	var Lmsl=round2(0.5*(angel2.a2-angel2.a1)/(2*Math.PI)*3E8/freq*mini*1E3);	
	
	return Lmsl;
}

//伝送線路が右側にある回路の場合
function CalcLmsl2(z1,z2,Y,nmsl,freq,whichC){	//	伝送線路長を求める
// 	var mini=CalcLamdaE(false);	//波長短縮率
	var mini=minimsl;
	
	var z1n2=new realimg(z1.re/nmsl,z1.im/nmsl);	//zsを伝送線路の特性インピーダンスで規格化
	var z2n2=new realimg(z2.re/nmsl,z2.im/nmsl);	//zLを伝送線路の特性インピーダンスで規格化
	var UVz1n2=RXtoUV(z1n2);
	var UVz2n2=RXtoUV(z2n2);
	var Yn2=new realimg(Y.re*nmsl,Y.im*nmsl);
	var MSLcurv2=FindMSLcurv2(nmsl,z2);
	var Gcurv2 = ReToARG(Yn2.re);	  //YLのコンダクタンス円の中心点と半径取得
	var crop2= crossp(Gcurv2,MSLcurv2,whichC);	  //交点の座標を取得
	var Zc2=UVtoRX(crop2);		//交点のインピーダンスを求める(伝送線路の特性インピーダンスで規格化されている)
	var Yc2=RXtoGB(Zc2);		//交点のアドミタンスを求める
	var angel2=ANG4(UVz1n2,UVz2n2,Gcurv2,MSLcurv2,crop2);		//マッチングカーブの4角度を取得
	angel2=StdAng(angel2);
	if(angel2.a4 > angel2.a3){		//角度を正しく表記させとく(一周したら2π足す)
		angel2.a3=angel2.a3+2*Math.PI
	}
	//伝送線路長　スミスチャートの一周が0.5λであることを考慮し、L=0.5*sita/2PI*Lamdaで求まる
	var Lmsl=round2(0.5*(angel2.a3-angel2.a4)/(2*Math.PI)*3E8/freq*mini*1E3);
	
	return Lmsl;
}

function CalcLamdaE(Z0w){	//波長短縮率miniを返す関数
	var Lamda=3E8/freq;			//freqから波長を求める

	var er=parseFloat(document.formSub.er.value);
	var h=parseFloat(document.formSub.subH.value);
	var t=parseFloat(document.formSub.subT.value)/1E3;

	//Z0などから線路幅を求める
	var W=8*h*Math.sqrt((7+4/er)/11*(Math.exp(Z0w*Math.sqrt(er+1)/42.4)-1)+(1+1/er)/0.81);
	W=W/(Math.exp(Z0w*Math.sqrt(er+1)/42.4)-1);
	var DW;
	if(t==0){
		DW=0;
	}else{
		DW=t/Math.PI*Math.log(4*Math.E/Math.sqrt(pow2(t/h)+1/pow2(Math.PI*(W/t-0.26))));
	}
	W=W-DW;
	var ere;
	if(W/h <= 1){
		ere=(er+1)/2+(er-1)/2*(1/Math.sqrt(1+12*h/W)+0.04*pow2(1-W/h));
		Z0w=60/Math.sqrt(ere)*Math.log(8*h/W+0.25*W/h);

	}else{
		ere=(er+1)/2+(er-1)/2/(Math.sqrt(1+12*h/W));
	}
	var mini=1/Math.sqrt(ere);
	
	return mini;
}


function CalcQ(uvpoint){
	return round2(2*uvpoint.vv/(pow2(uvpoint.uu)+pow2(uvpoint.vv)-1));		//Q値　絶対値
}


function ZseriZ(Z1,Z2){		//Z1とZ2が直列のときの合成インピーダンス
	var Zout=new realimg(Z1.re+Z2.re, Z1.im+Z2.im);
	return Zout;
}

function ZparaZ(Z1,Z2){		//Z1とZ2が並列のときの合成インピーダンス
	var Zmother=pow2(Z1.re)+2*Z1.re*Z2.re+pow2(Z2.re)+pow2(Z1.im+Z2.im);
	var Zre=pow2(Z1.re)*Z2.re+Z2.re*pow2(Z1.im)+Z1.re*(pow2(Z2.re)+pow2(Z2.im));
	var Zim=pow2(Z2.re)*Z1.im+Z2.im*(pow2(Z1.re)+Z1.im*(Z1.im+Z2.im));
	var Zout=new realimg(Zre/Zmother,Zim/Zmother);
	return Zout;
}
//---------------------------------------------------------------------------