// Heston Integrand
        public double HestonProb(double phi, HParam param, double S, double K, double r, double q, double T, int Pnum, int Trap)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  kappa = param.kappa;
            double  theta = param.theta;
            double  sigma = param.sigma;
            double  v0 = param.v0;
            double  rho = param.rho;
            double  lambda = 0.0;
            double  x = Math.Log(S);
            double  a = kappa * theta;
            Complex b, u, d, g, c, D, G, C, f, integrand = new Complex();

            // Parameters "u" and "b" are different for P1 and P2
            if (Pnum == 1)
            {
                u = 0.5;
                b = kappa + lambda - rho * sigma;
            }
            else
            {
                u = -0.5;
                b = kappa + lambda;
            }
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            f = Complex.Exp(C + D * v0 + i * phi * x);

            // The integrand.
            integrand = Complex.Exp(-i * phi * Complex.Log(K)) * f / i / phi;

            // Return the real part of the integrand.
            return(integrand.Real);
        }
Example #2
0
        // Mikhailov and Nogel (2003) Time dependent D function
        public Complex Dt(double phi, HParam param, double r, double q, double T, OpSet settings, int Pnum, Complex C0, Complex D0)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  kappa = param.kappa;
            double  theta = param.theta;
            double  sigma = param.sigma;
            double  v0 = param.v0;
            double  rho = param.rho;
            int     Trap = settings.trap;
            Complex b, u, d, g, G, D = new Complex();

            // Parameters "u" and "b" are different for P1 and P2
            if (Pnum == 1)
            {
                u = 0.5;
                b = kappa - rho * sigma;
            }
            else
            {
                u = -0.5;
                b = kappa;
            }
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d - D0 * sigma * sigma) / (b - rho * sigma * i * phi - d - D0 * sigma * sigma);
            G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
            D = ((b - rho * sigma * i * phi) * (1 - g * Complex.Exp(d * T)) + d * (1 + g * Complex.Exp(d * T))) / (sigma * sigma * (1 - g * Complex.Exp(d * T)));

            return(D);
        }
        static void Main(string[] args)
        {
            //
            // "SiO2 1000nm_on_Si.dat" 파일 로딩 후
            // 측정 스펙트럼 데이터를 alpha, beta 로 변환한다.
            //
            // 2021.03.24 이지원.
            //
            #region psi, delta -> alpha, beta

            List <string> MeasurementSpectrumData = new List <string>(); // 측정 스펙트럼 데이터 저장할 배열. (한 줄씩 저장)
            string[]      SingleLineData;                                // 한 줄의 스펙트럼 데이터를 임시로 저장할 배열.

            // "SiO2 2nm_on_Si.dat" 파일 읽기. (한 줄씩)
            MeasurementSpectrumData.AddRange(File.ReadAllLines("SiO2 1000nm_on_Si.dat"));

            // 무의미한 공백 행을 제거한다.
            int    lenSpectrumData = MeasurementSpectrumData.Count;
            string Blank           = "";
            for (int i = 0; i < lenSpectrumData; i++)
            {
                if (MeasurementSpectrumData[0] == Blank)
                {
                    MeasurementSpectrumData.RemoveAt(0);
                }
                else
                {
                    break;
                }
            }

            // wavelength : 350 ~ 980(nm)인 측정 스펙트럼 데이터를 담을 리스트 선언.
            List <double> wavelength_exp = new List <double>(); // 파장 데이터 리스트.
            List <double> AOI_exp        = new List <double>(); // 입사각 데이터 리스트.
            List <double> alpha_exp      = new List <double>(); // Psi 데이터 리스트.
            List <double> beta_exp       = new List <double>(); // Delta 데이터 리스트.

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하기 위해 반복문을 1부터 시작한다.
            int StartIndex = 1;
            int LenData    = MeasurementSpectrumData.Count;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = MeasurementSpectrumData[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 파장이 350 ~ 980(nm) 이내인 데이터만 저장한다.
                if (Convert.ToDouble(SingleLineData[0]) >= 350.0 &&
                    Convert.ToDouble(SingleLineData[0]) <= 980.0)
                {
                    // 각 컬럼에 해당하는 데이터를 저장한다.
                    wavelength_exp.Add(Double.Parse(SingleLineData[0]));
                    AOI_exp.Add(Double.Parse(SingleLineData[1]));
                    alpha_exp.Add(Double.Parse(SingleLineData[2]));
                    beta_exp.Add(Double.Parse(SingleLineData[3]));
                }
            }

            // psi, delta -> alpha, beta 변환.

            // degree, radian 변환 인라인 함수 정의.
            double degree2radian(double angle) => ((angle * (PI)) / 180.0);

            // double radian2degree(double angle) => (angle * (180.0 / PI));

            // Polarizer offset 각도. (45도)
            double PolarizerRadian = degree2radian(45.0);

            // psi, delta 데이터를 alpha, beta 로 변환한다.
            LenData = wavelength_exp.Count;
            for (int i = 0; i < LenData; i++)
            {
                // psi, delta 값을 radian 으로 변환한다.
                double PsiRadian   = degree2radian(alpha_exp[i]);
                double DeltaRadian = degree2radian(beta_exp[i]);

                // psi, delta 데이터를 alpha, beta 로 갱신한다.
                alpha_exp[i] = (
                    (Pow(Tan(PsiRadian), 2.0) - Pow(Tan(PolarizerRadian), 2.0))
                    / (Pow(Tan(PsiRadian), 2.0) + Pow(Tan(PolarizerRadian), 2.0)));
                beta_exp[i] = (
                    (2.0 * Tan(PsiRadian) * Tan(PolarizerRadian) * Cos(DeltaRadian))
                    / (Pow(Tan(PsiRadian), 2.0) + Pow(Tan(PolarizerRadian), 2.0)));
            }

            #endregion

            //
            // "Si_new.txt", "SiO2_new.txt" 파일 물성값 로딩.
            //
            // 2021.03.24 이지원.
            //
            #region MyRegion

            // "Si_new.txt" 파일 읽기.
            string[] Si_new = File.ReadAllLines("Si_new.txt");  // Si 기판 물성값 저장.(한 줄씩)

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하고 데이터를 받기 위해 LenData 변수를 선언한다.
            LenData = Si_new.Length - 1;
            double[] wavelength_Si = new double[LenData];
            double[] n_Si          = new double[LenData];
            double[] k_Si          = new double[LenData];

            // Si_new 에 받은 데이터를 각 컬럼별로 저장한다.
            LenData = Si_new.Length;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = Si_new[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 각 컬럼에 해당하는 데이터를 저장한다.
                wavelength_Si[i - 1] = Double.Parse(SingleLineData[0]);
                n_Si[i - 1]          = Double.Parse(SingleLineData[1]);
                k_Si[i - 1]          = Double.Parse(SingleLineData[2]);
            }


            // "SiO2_new.txt" 파일 읽기.
            string[] SiO2_new = File.ReadAllLines("SiO2_new.txt");  // Si 기판 물성값 저장.(한 줄씩)

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하고 데이터를 받기 위해 LenData 변수를 선언한다.
            LenData = SiO2_new.Length - 1;
            double[] wavelength_SiO2 = new double[LenData];
            double[] n_SiO2          = new double[LenData];
            double[] k_SiO2          = new double[LenData];

            // SiO2_new 에 받은 데이터를 각 컬럼별로 저장한다.
            LenData = SiO2_new.Length;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = SiO2_new[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 각 컬럼에 해당하는 데이터를 저장한다.
                wavelength_SiO2[i - 1] = Double.Parse(SingleLineData[0]);
                n_SiO2[i - 1]          = Double.Parse(SingleLineData[1]);
                k_SiO2[i - 1]          = Double.Parse(SingleLineData[2]);
            }

            #region Si_new, SiO2_new 데이터 출력 (Test)

            /*LenData = wavelength_Si.Length;
             * for (int i = 0; i < LenData; i++)
             *  WriteLine(wavelength_Si[i] + "\t" + n_Si[i] + "\t" + k_Si[i]);
             * WriteLine("============================================");
             * for (int i = 0; i < LenData; i++)
             *  WriteLine(wavelength_SiO2[i] + "\t" + n_SiO2[i] + "\t" + k_SiO2[i]);*/
            #endregion
            #endregion

            //
            // "Si_new.txt", "SiO2_new.txt" 의 n, k 를 사용하여
            // 각 계면에서의 반사, 투과계수를 계산한다.
            //
            // 2021.03.24 이지원.
            //
            #region 각 계면에서의 반사, 투과계수 계산

            LenData = wavelength_Si.Length;

            // 반사계수를 담을 배열.
            Complex[] r12p = new Complex[LenData],
            r12s = new Complex[LenData],
            r01p = new Complex[LenData],
            r01s = new Complex[LenData];
            // 투과계수를 담을 배열.
            Complex[] t12p = new Complex[LenData],
            t12s = new Complex[LenData],
            t01p = new Complex[LenData],
            t01s = new Complex[LenData];

            double  AOI_air = degree2radian(65.0); // 입사각. (라디안)
            Complex N_air   = new Complex(1.0, 0); // 공기의 굴절률.

            // 반사, 투과계수를 계산한다.
            for (int i = 0; i < LenData; i++)
            {
                // 파장에 대한 물질의 복소굴절률을 구한다.
                Complex N_SiO2 = new Complex(n_SiO2[i], -k_SiO2[i]);
                Complex N_Si   = new Complex(n_Si[i], -k_Si[i]);

                // air, SiO2 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                Complex Sintheta_j = new Complex(Sin(AOI_air), 0);
                Complex Costheta_j = new Complex(Cos(AOI_air), 0);
                Complex Sintheta_k = (N_air / N_SiO2) * Sintheta_j;
                Complex theta_k    = Complex.Asin(Sintheta_k);
                // air, SiO2 경계면에서의 굴절각.
                Complex Costheta_k = Complex.Cos(theta_k);

                // air, SiO2 경계면에서의 반사계수를 구한다.
                r01p[i] = ((N_SiO2 * Costheta_j) - (N_air * Costheta_k)) /
                          ((N_SiO2 * Costheta_j) + (N_air * Costheta_k));

                r01s[i] = ((N_air * Costheta_j) - (N_SiO2 * Costheta_k)) /
                          ((N_air * Costheta_j) + (N_SiO2 * Costheta_k));

                // air, SiO2 경계면에서의 투과계수를 구한다.
                t01p[i] = (N_air * Costheta_j * 2.0) /
                          ((N_SiO2 * Costheta_j) + (N_air * Costheta_k));

                t01s[i] = (N_air * Costheta_j * 2.0) /
                          ((N_air * Costheta_j) + (N_SiO2 * Costheta_k));

                // SiO2, Si 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                Sintheta_j = Complex.Sin(theta_k);
                Costheta_j = Complex.Cos(theta_k);
                Sintheta_k = (N_SiO2 / N_Si) * Sintheta_j;
                theta_k    = Complex.Asin(Sintheta_k);
                Costheta_k = Complex.Cos(theta_k);

                // SiO2, Si 경계면에서의 반사계수를 구한다.
                r12p[i] = ((N_Si * Costheta_j) - (N_SiO2 * Costheta_k)) /
                          ((N_Si * Costheta_j) + (N_SiO2 * Costheta_k));

                r12s[i] = ((N_SiO2 * Costheta_j) - (N_Si * Costheta_k)) /
                          ((N_SiO2 * Costheta_j) + (N_Si * Costheta_k));

                // SiO2, Si 경계면에서의 투과계수를 구한다.
                t12p[i] = (N_SiO2 * Costheta_j * 2.0) /
                          ((N_Si * Costheta_j) + (N_SiO2 * Costheta_k));

                t12s[i] = (N_SiO2 * Costheta_j * 2.0) /
                          ((N_SiO2 * Costheta_j) + (N_Si * Costheta_k));
            }

            #region 위에서 구한 반사, 투과계수 출력 (Test)

            /*WriteLine("====== air, SiO2 경계 ======");
             * for (int i = 0; i < LenData; i++)
             * {
             *  WriteLine(
             *      r01p[i] + " " +
             *      r01s[i] + " " +
             *      t01p[i] + " " +
             *      t01s[i]);
             * }
             * WriteLine("====== SiO2, Si 경계 ======");
             * for (int i = 0; i < LenData; i++)
             * {
             *  WriteLine(
             *      r12p[i] + " " +
             *      r12s[i] + " " +
             *      t12p[i] + " " +
             *      t12s[i]);
             * }*/
            #endregion

            #endregion

            //
            // 위상 두께를 구하고 위에서 구한 반사계수를 통해
            // 무한등비급수 수렴식을 계산한다. => 총 반사계수를 구한다.
            //
            // 2021.03.24 이지원.
            //
            #region 총 반사계수를 구한다.

            // 두께 범위와 두께 간격을 설정한다.
            double StartThickness = 700.0;
            double EndThickness   = 1300.0;
            double gap            = 6.0;

            // MSE 와 두께를 담을 배열을 선언, 초기화한다.
            double   numMSE      = (EndThickness - StartThickness) / gap + 1;
            double[] MSEs        = new double[(int)numMSE];
            double[] thicknesses = new double[(int)numMSE];

            // 두께별 MSE 를 계산해서 MSEs 배열에 저장한다.
            int idx = 0;
            for (double thickness = StartThickness; thickness <= EndThickness; thickness += gap)
            {
                // 총 반사계수를 저장할 배열 선언.
                Complex[] Rp = new Complex[LenData],
                Rs = new Complex[LenData];

                for (int i = 0; i < LenData; i++)
                {
                    // SiO2의 복소 굴절률.
                    Complex N_SiO2 = new Complex(n_SiO2[i], -k_SiO2[i]);

                    // air, SiO2 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                    Complex Sintheta_j = new Complex(Sin((double)AOI_air), 0);
                    Complex Sintheta_k = (N_air / N_SiO2) * Sintheta_j;
                    Complex theta_k    = Complex.Asin(Sintheta_k);      // air, SiO2 경계면에서의 굴절각.
                    Complex Costheta_k = Complex.Cos(theta_k);

                    // 위상 두께를 구한다.
                    Complex PhaseThickness = ((double)thickness * Math.PI * 2.0 / wavelength_SiO2[i]) * N_SiO2 * Costheta_k;

                    //WriteLine(PhaseThickness);

                    // 총 반사계수를 구한다.
                    Complex E = Complex.Exp(PhaseThickness * new Complex(0, -2.0));

                    Rp[i] = (r01p[i] + r12p[i] * E) /
                            (1 + r01p[i] * r12p[i] * E);

                    Rs[i] = (r01s[i] + r12s[i] * E) /
                            (1 + r01s[i] * r12s[i] * E);
                }

                #region 총 반사계수 출력 (Test)

                /*for (int i = 0; i < LenData; i++)
                 *  WriteLine(Rp[i] + "\t" + Rs[i]);*/

                #endregion

                #endregion

                //
                // 위에서 구한 총 반사계수로부터 alpha, beta 를 구한다.
                //
                // 2021.03.24 이지원.
                //
                #region 총 반사계수로부터 alpha, beta 도출.

                // alpha, beta 이론값을 담을 배열 선언.
                double[] alpha_cal = new double[LenData],
                beta_cal = new double[LenData];

                // Polarizer 오프셋 각.
                double polarizerAngle = degree2radian(45.0);

                for (int i = 0; i < LenData; i++)
                {
                    // 총 반사계수비. (복소반사계수비)
                    Complex rho = Rp[i] / Rs[i];

                    // Psi, Delta.
                    double Psi   = Atan(rho.Magnitude);
                    double Delta = rho.Phase;


                    alpha_cal[i] = (Pow(Tan(Psi), 2.0) - Pow(Tan(polarizerAngle), 2.0)) /
                                   (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));

                    beta_cal[i] = (2.0 * Tan(Psi) * Cos(Delta) * Tan(polarizerAngle)) /
                                  (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));
                }

                #region alpha, beta 이론값 출력 (Test)

                /*for (int i = 0; i < LenData; i++)
                 *  WriteLine(alpha_cal[i] + " "
                 + beta_cal[i]);*/

                #endregion

                #endregion

                //
                // 측정값과 이론값의 MSE 를 계산한다.
                //
                // 2021.03.24 이지원.
                //
                #region 측정값과 이론값의 MSE 계산.

                double sum = 0;
                for (int i = 0; i < LenData; i++)
                {
                    double difference_MSE =
                        Pow((alpha_exp[i] - alpha_cal[i]), 2.0) +
                        Pow((beta_exp[i] - beta_cal[i]), 2.0);
                    sum += difference_MSE;
                }

                MSEs[idx]        = sum / LenData;
                thicknesses[idx] = thickness;
                ++idx;

                #endregion
            }
            #region MSE 배열 출력

            /*foreach (var item in MSEs)
             *  WriteLine(item);
             * WriteLine("==========================");
             * foreach (var item in thicknesses)
             *  WriteLine(item);*/

            #endregion

            //
            // 두께별로 계산된 MSE 를 통해
            // global minimum 일 때의 두께, MSE 값을 찾는다.
            //
            // 2021.03.26 이지원.
            //
            #region global minimum 탐색.

            // MSEs 에서 global minimum 에서의 MSE, 두께값을 구한다.
            int    idxGlobalMinimum = 0;          // global minimum 에서의 index.
            double GlobalMinimum    = MSEs.Min(); // global minimum 값.

            // global minimum 에서의 index 를 찾는다.
            LenData = MSEs.Length;
            for (int i = 0; i < LenData; i++)
            {
                if (MSEs[i] == GlobalMinimum)
                {
                    idxGlobalMinimum = i;
                    break;
                }
            }
            // WriteLine($"{MSEs[idxGlobalMinimum]}  {idxGlobalMinimum}");

            // global minimum 에서의 두께 값.
            double d0 = thicknesses[idxGlobalMinimum];

            #endregion

            //
            // d0 근처에 있는 "실제" global minimum 이 되는 두께 d_sol 을 찾는다.
            // MSE 값의 변화가 10^-5 이하가 되면, 최적화 수행을 멈춘다.
            //
            // 2021.03.29 이지원.
            //
            #region 두께 범위를 재설정하고 MSE를 구한다.

            double d_sol = 0.0; // "실제" global minimum 이 되는 두께.
            int    cnt   = 0;   // global minimum 을 찾기 위한 연산 반복 횟수.
            //double beforeGM = GlobalMinimum;
            while (true)
            {
                ++cnt;
                WriteLine($"==== {cnt} 회차 ====");

                // 두께 범위와 두께 간격을 정한다.
                StartThickness = d0 - gap;
                EndThickness   = d0 + gap;
                gap            = gap * 0.7;

                // MSEs 배열을 초기화한다.
                // double minus = EndThickness - StartThickness;
                numMSE      = (EndThickness - StartThickness) / gap + 1;
                MSEs        = new double[(int)numMSE];
                thicknesses = new double[(int)numMSE];

                // 새로 지정된 두께 범위에서 MSE 값들을 계산한다.
                idx = 0;
                for (double thickness = StartThickness; thickness <= EndThickness; thickness += gap)
                {
                    #region 총 반사계수를 구한다.
                    // 총 반사계수를 저장할 배열 선언.
                    Complex[] Rp = new Complex[LenData],
                    Rs = new Complex[LenData];

                    for (int i = 0; i < LenData; i++)
                    {
                        // SiO2의 복소 굴절률.
                        Complex N_SiO2 = new Complex(n_SiO2[i], -k_SiO2[i]);

                        // air, SiO2 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                        Complex Sintheta_j = new Complex(Sin((double)AOI_air), 0);
                        Complex Sintheta_k = (N_air / N_SiO2) * Sintheta_j;
                        Complex theta_k    = Complex.Asin(Sintheta_k);
                        // air, SiO2 경계면에서의 굴절각.
                        Complex Costheta_k = Complex.Cos(theta_k);

                        // 위상 두께를 구한다.
                        Complex PhaseThickness = ((double)thickness * Math.PI * 2.0 / wavelength_SiO2[i]) * N_SiO2 * Costheta_k;

                        //WriteLine(PhaseThickness);

                        // 총 반사계수를 구한다.
                        Complex E = Complex.Exp(PhaseThickness * new Complex(0, -2.0));

                        Rp[i] = (r01p[i] + r12p[i] * E) /
                                (1 + r01p[i] * r12p[i] * E);

                        Rs[i] = (r01s[i] + r12s[i] * E) /
                                (1 + r01s[i] * r12s[i] * E);
                    }
                    #endregion
                    #region 총 반사계수로부터 alpha, beta 를 계산한다.
                    // alpha, beta 이론값을 담을 배열 선언.
                    double[] alpha_cal = new double[LenData],
                    beta_cal = new double[LenData];

                    // Polarizer 오프셋 각.
                    double polarizerAngle = degree2radian(45.0);

                    for (int i = 0; i < LenData; i++)
                    {
                        // 총 반사계수비. (복소반사계수비)
                        Complex rho = Rp[i] / Rs[i];

                        // Psi, Delta.
                        double Psi   = Atan(rho.Magnitude);
                        double Delta = rho.Phase;


                        alpha_cal[i] = (Pow(Tan(Psi), 2.0) - Pow(Tan(polarizerAngle), 2.0)) /
                                       (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));

                        beta_cal[i] = (2.0 * Tan(Psi) * Cos(Delta) * Tan(polarizerAngle)) /
                                      (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));
                    }
                    #endregion
                    #region MSE 를 계산한다.

                    double sum = 0;
                    for (int i = 0; i < LenData; i++)
                    {
                        double difference_MSE =
                            Pow((alpha_exp[i] - alpha_cal[i]), 2.0) +
                            Pow((beta_exp[i] - beta_cal[i]), 2.0);
                        sum += difference_MSE;
                    }

                    MSEs[idx]        = sum / LenData;
                    thicknesses[idx] = thickness;
                    ++idx;

                    #endregion
                }
                // MSEs 출력.
                foreach (var item in MSEs)
                {
                    WriteLine(item);
                }

                // global minimum 에서의 MSE, 두께 값을 구한다.
                idxGlobalMinimum = 0;            // global minimum 에서의 index.
                GlobalMinimum    = MSEs.Min();   // global minimum 값.

                // global minimum 에서의 index 를 찾는다.
                LenData = MSEs.Length;
                for (int i = 0; i < LenData; i++)
                {
                    if (MSEs[i] == GlobalMinimum)
                    {
                        idxGlobalMinimum = i;
                        break;
                    }
                }

                d0 = thicknesses[idxGlobalMinimum]; // global minimum 에서의 두께 값.


                // MSE 값의 간격을 확인한다.
                // 1. 양 옆.
                for (int i = 1; i < LenData; i++)
                {
                    // MSE 의 변화율이 10^-5 이하이면 while 문을 탈출한다.
                    if (Math.Abs((MSEs[i] - MSEs[i - 1])) <= 0.00001)
                    {
                        d_sol = d0;
                        goto Find_d_sol;
                    }
                }

                // 2. global minimum 끼리 비교.

                /*for (int i = 1; i < LenData; i++)
                 * {
                 *  // MSE 의 변화율이 10^-5 이하이면 while 문을 탈출한다.
                 *  if (Math.Abs((beforeGM - GlobalMinimum)) <= 0.00001)
                 *  {
                 *      d_sol = d0;
                 *      goto Find_d_sol;
                 *  }
                 * }
                 * beforeGM = GlobalMinimum;*/
            }
            Find_d_sol : WriteLine($"d_sol: {d_sol}    MSE: {MSEs[idxGlobalMinimum]}    idxGlobalMinimum: {idxGlobalMinimum}");

            #endregion
        }
Example #4
0
            public double value(double phi)
            {
                // avoid numeric overflow for phi->0.
                // todo: use l'Hospital's rule use to get lim_{phi->0}
                phi = Math.Max(Double.Epsilon, phi);

                Complex D = 0.0;
                Complex C = 0.0;

                for (int i = timeGrid_.size() - 1; i > 0; --i)
                {
                    double begin = timeGrid_[i - 1];
                    if (begin < term_)
                    {
                        double end = Math.Min(term_, timeGrid_[i]);
                        double tau = end - begin;
                        double t   = 0.5 * (end + begin);

                        double rho   = model_.link.rho(t);
                        double sigma = model_.link.sigma(t);
                        double kappa = model_.link.kappa(t);
                        double theta = model_.link.theta(t);

                        double sigma2 = sigma * sigma;
                        double t0     = kappa - ((j_ == 1) ? rho * sigma : 0);
                        double rpsig  = rho * sigma * phi;

                        Complex t1 = t0 + new Complex(0, -rpsig);
                        Complex d  = Complex.Sqrt(t1 * t1 - sigma2 * phi * new Complex(-phi, (j_ == 1) ? 1 : -1));
                        Complex g  = (t1 - d) / (t1 + d);
                        Complex gt = (t1 - d - D * sigma2) / (t1 + d - D * sigma2);

                        D = (t1 + d) / sigma2 * (g - gt * Complex.Exp(-d * tau)) / (1.0 - gt * Complex.Exp(-d * tau));

                        Complex lng = Complex.Log((1.0 - gt * Complex.Exp(-d * tau)) / (1.0 - gt));

                        C = (kappa * theta) / sigma2 * ((t1 - d) * tau - 2.0 * lng)
                            + new Complex(0.0, phi * (r_[i - 1] - q_[i - 1]) * tau) + C;
                    }
                }
                return(Complex.Exp(v0_ * D + C + new Complex(0.0, phi * (x_ - sx_))).Imaginary / phi);
            }
 private Complex CalculateReverseFactor(int m, int n, int N)
 {
     return(Complex.Exp(new Complex(0, 2 * Math.PI * m * n / N)));
 }
        public void LambertW_ComplexPrincipalBranch_RealArgument_FunctionalEquation(
            [Values(1.0, 1.63, 2.831231313, -0.23441312, 7.9817231123, -0.1234567891011, 24.6152441235, 65.9823477234, 126.716265123, 1023.928242474247, -0.36787944117144)] double x)
        {
            var specialFunctions = GetTestObject();

            var w = specialFunctions.LambertW(x + 0 * Complex.ImaginaryOne, branch: 0);

            var actual   = w * Complex.Exp(w);
            var expected = x;

            Assert.That(actual.Real, Is.EqualTo(expected).Within(1E-12).Percent, String.Format("x={0}; w ={1}; w * exp(w) = {2} is not equal to x!", x, w, w * Complex.Exp(w)));
            Assert.That(actual.Imaginary, Is.EqualTo(0.0).Within(1E-12));

            if (x < 0) // check whether in Principal branch, i.e. >= -1.0
            {
                Assert.That(w.Real, Is.GreaterThanOrEqualTo(-1.0), "Not in Principal branch!");
            }
        }
        public List <List <Complex> > Evaluate(List <Complex> C, List <List <Complex> > phi, int Nz,
                                               List <double> receiverRanges, int Nr, List <double> rr, List <Complex> k, int modesCount,
                                               string option)
        {
            var p = new List <List <Complex> >(Nz + 1);

            for (var i = 0; i <= Nz; i++)
            {
                p.Add(Enumerable.Repeat(new Complex(), Nr + 1).ToList());
            }

            if (modesCount <= 0)
            {
                return(p);
            }

            var ic     = new Complex(0, 1);
            var factor = ic * Math.Sqrt(2 * Math.PI) * Complex.Exp(ic * Math.PI / 4);

            var cnst = new List <Complex>();

            cnst.Add(new Complex());

            if (option[0] == 'X')
            {
                for (var i = 1; i <= modesCount; i++)
                {
                    cnst.Add(factor * C[i] / k[i]);
                }
            }
            else
            {
                for (var i = 1; i <= modesCount; i++)
                {
                    cnst.Add(factor * C[i] / Complex.Sqrt(k[i]));
                }
            }

            var cMat = new List <List <Complex> >(modesCount + 1);

            for (var i = 0; i <= modesCount; i++)
            {
                cMat.Add(Enumerable.Repeat(new Complex(), Nz + 1).ToList());
            }

            var ik = k.Select(x => x * (-ic)).ToList();

            if (option.Length >= 3)
            {
                if (option[3] == 'I')
                {
                    for (var i = 1; i < ik.Count; i++)
                    {
                        ik[i] = new Complex(ik[i].Real, 0);
                    }
                }
            }

            for (var iz = 1; iz <= Nz; iz++)
            {
                for (var i = 1; i <= modesCount; i++)
                {
                    cMat[i][iz] = cnst[i] * phi[i][iz] * Complex.Exp(ik[i] * rr[iz]);
                }
            }

            for (var ir = 1; ir <= Nr; ir++)
            {
                //problem in exp
                var hank = ik.Select(x => Complex.Exp(x * receiverRanges[ir])).ToList();

                if (option.Length <= 3 || option[3] != 'I')
                {
                    for (var iz = 1; iz <= Nz; iz++)
                    {
                        var sum = new Complex(0, 0);
                        for (var i = 1; i <= modesCount; i++)
                        {
                            sum += cMat[i][iz] * hank[i];
                        }

                        p[iz][ir] = sum;
                    }
                }
                else
                {
                    for (var iz = 1; iz <= Nz; iz++)
                    {
                        var sum = new Complex(0, 0);
                        for (var i = 1; i <= modesCount; i++)
                        {
                            sum += Complex.Pow(cMat[i][iz] * hank[i], 2);
                        }

                        p[iz][ir] = Complex.Sqrt(sum);
                    }
                }

                if (option[0] == 'R')
                {
                    for (var i = 1; i <= Nz; i++)
                    {
                        if (Math.Abs(receiverRanges[ir] + rr[i]) > 1.17549435E-38)
                        {
                            p[i][ir] = p[i][ir] / Complex.Sqrt(receiverRanges[ir] + rr[i]);
                        }
                    }
                }
            }

            return(p);
        }
 private static Complex Exp(Complex[] args) => Complex.Exp(args.Check(1)[0]);
        public static void Cal_01(List <SiO2_new_Data> SiO2records, List <Si_new_Data> Sirecords, List <SiO2_1000nm_Data> SiO2_1000_records, int linenum1, int linenum2, int linenum3)
        {
            StreamWriter streamWriter = new StreamWriter(new FileStream("SiO2_1000nm_on_Si_new.dat", FileMode.Create));

            streamWriter.WriteLine("wave(nm)\t\t AOI\t alpha\t\t\t beta");

            double sio2_nm = 0.0;
            double sio2_n  = 0.0;
            double sio2_k  = 0.0;
            double si_nm   = 0.0;
            double si_n    = 0.0;
            double si_k    = 0.0;

            //무한등비가 아닌 등비급수 계산하기 위해
            //새로운 파일쓰기 위한 배열
            string[] Array_new_NM    = new string[linenum1 - 1];
            string[] Array_new_Alpha = new string[linenum1 - 1];
            string[] Array_new_Beta  = new string[linenum1 - 1];
            //------------------------

            int AOI = 65;

            //int AOI = 65;

            // Complex형 라디안
            Complex Rad2deg(Complex radian)
            {
                return(Math.PI * (radian / 180.0f));
            }

            // double형 라디안
            double dou_Rad2deg(double radian)
            {
                return(Math.PI * (radian / 180.0f));
            }

            // 반사계수
            for (int i = 1; i < linenum1; i++)
            {
                sio2_nm = Convert.ToSingle(SiO2records[i].nm);
                sio2_n  = Convert.ToSingle(SiO2records[i].n);
                sio2_k  = Convert.ToSingle(SiO2records[i].k);

                si_nm = Convert.ToSingle(Sirecords[i].nm);
                si_n  = Convert.ToSingle(Sirecords[i].n);
                si_k  = Convert.ToSingle(Sirecords[i].k);
                //공비에 따로 마이너스해준 Rp Rs를 만들어 비교
                //R,S
                if (si_nm > 350 && si_nm < 980)
                {
                    Complex N0 = new Complex(1, 0); // 공기 = 1

                    // 반사율 (P, S)
                    double P_val = 0.0;
                    double S_Val = 0.0;
                    //double sin_AOI = Math.Sin(dou_Rad2deg(AOI));
                    //double cos_AOI = Math.Cos(dou_Rad2deg(AOI));
                    Complex sin_AOI = Complex.Sin(Rad2deg(AOI)); // 입사각
                    Complex cos_AOI = Complex.Cos(Rad2deg(AOI));

                    Complex N1 = new Complex(sio2_n, -sio2_k); // 매질 = 복소수
                    Complex N2 = new Complex(si_n, -si_k);

                    Complex sintheta1 = (N0 * sin_AOI) / N1;
                    Complex theta1    = Complex.Asin(sintheta1); // 굴절각 세타1
                    Complex costheta1 = Complex.Cos(theta1);

                    Complex sintheta2 = sin_AOI / N2;
                    Complex theta2    = Complex.Asin(sintheta2);
                    Complex costheta2 = Complex.Cos(theta2);
                    //WriteLine("{0} {1}", theta1, theta2);
                    Complex reflect_P_01 = (N1 * cos_AOI - N0 * costheta1) / (N1 * cos_AOI + N0 * costheta1);   //Rp
                    Complex reflect_s_01 = (N0 * cos_AOI - N1 * costheta1) / (N0 * cos_AOI + N1 * costheta1);   //Rs
                    Complex trans_P_01   = (2 * cos_AOI) / (N1 * cos_AOI + costheta1);
                    Complex trans_s_01   = (2 * cos_AOI) / (cos_AOI + N1 * costheta1);

                    Complex reflect_P_12 = (N2 * costheta1 - N1 * costheta2) / (N2 * costheta1 + N1 * costheta2);
                    Complex reflect_s_12 = (N1 * costheta1 - N2 * costheta2) / (N1 * costheta1 + N2 * costheta2);

                    Complex reflect_P_21 = (N1 * costheta2 - N2 * costheta1) / (N1 * costheta2 + N2 * costheta1);
                    Complex reflect_s_21 = (N2 * costheta2 - N1 * costheta1) / (N2 * costheta2 + N1 * costheta1);


                    Complex trans_P_12 = (2 * N1 * costheta1) / (N2 * costheta1 + N1 * costheta2);
                    Complex trans_s_12 = (2 * N1 * costheta1) / (N1 * costheta1 + N2 * costheta2);

                    Complex trans_P_21 = (2 * N2 * costheta2) / (N1 * costheta2 + N2 * costheta1);
                    Complex trans_s_21 = (2 * N2 * costheta2) / (N2 * costheta2 + N1 * costheta1);



                    //WriteLine("{0} {1} {2} {3}", reflect_P_01, reflect_s_01, reflect_P_12, reflect_s_12);

                    // Beta -> 위상 두께
                    Complex Beta_thick = (2 * Math.PI * 1000 * N1 * costheta1) / sio2_nm;

                    // 반사율(크기)
                    P_val = Math.Pow(reflect_P_01.Magnitude, 2);
                    S_Val = Math.Pow(reflect_s_01.Magnitude, 2);

                    //
                    Complex A = new Complex(0, -1) * (2 * Beta_thick);

                    // 통합반사계수(P,S)

                    Complex Total_reflect_P = (reflect_P_01 + (reflect_P_12 * Complex.Exp(A)))
                                              / (1 + reflect_P_01 * (reflect_P_12 * Complex.Exp(A)));
                    Complex Total_reflect_S =
                        (reflect_s_01 + (reflect_s_12 * Complex.Exp(A)))
                        / (1 + reflect_s_01 * (reflect_s_12 * Complex.Exp(A)));


                    //Complex Rp = reflect_P_01 + (trans_P_01 * reflect_P_12 * trans_P_12 * Complex.Exp(A)) * Sigma_P(200);
                    //Complex Rs = reflect_s_01 + (trans_s_01 * reflect_s_12 * trans_s_12 * Complex.Exp(A)) * Sigma_S(200);

                    //Console.WriteLine("{0} {1}", Total_reflect_P, Total_reflect_S);
                    Complex New_sigma_Pa = (reflect_P_01 + (reflect_P_12 * Complex.Exp(A)));
                    Complex New_sigma_Sa = (reflect_s_01 + (reflect_s_12 * Complex.Exp(A)));

                    Complex New_sigma_Pr = -(reflect_P_01 * (reflect_P_12 * Complex.Exp(A)));
                    Complex New_sigma_Sr = -(reflect_s_01 * (reflect_s_12 * Complex.Exp(A)));

                    Complex New_Rp = New_Sigma_P(1);
                    Complex New_Rs = New_Sigma_S(1);

                    Complex rho = (Total_reflect_P / Total_reflect_S);
                    //Complex rho_new = (Rp / Rs);
                    Complex rho_new = (New_Rp / New_Rs);

                    double rho_size     = rho.Magnitude; // tan(psi)
                    double rho_new_size = rho_new.Magnitude;

                    double Psi     = Math.Atan(rho_size);
                    double Psi_new = Math.Atan(rho_new_size);

                    double Delta     = rho.Phase;
                    double Delta_new = rho_new.Phase;

                    double tan_pow = 0.0;
                    double a_numeator = 0.0, a_denominator = 0.0;
                    double b_numeator = 0.0, b_denominator = 0.0;
                    double alpha = 0.0, beta = 0.0;

                    //등비급수의 "항의 개수(n)"
                    double new_alpha = 0.0, new_beta = 0.0;


                    Complex Sigma_P(int n)
                    {
                        Complex Sigma_Value = 0;

                        for (int K = 0; K < n; K++)
                        {
                            Sigma_Value += Complex.Pow((reflect_P_12 * reflect_P_21 * Complex.Exp(A)), K);
                        }

                        return(Sigma_Value);
                    }

                    Complex Sigma_S(int n)
                    {
                        Complex Sigma_Value = 0;

                        for (int K = 0; K < n; K++)
                        {
                            Sigma_Value += Complex.Pow((reflect_s_12 * reflect_s_21 * Complex.Exp(A)), K);
                        }
                        return(Sigma_Value);
                    }

                    Complex New_Sigma_P(int n)
                    {
                        Complex Sigma_Value = 0;

                        for (int K = 1; K <= n; K++)
                        {
                            Sigma_Value += New_sigma_Pa * Complex.Pow(New_sigma_Pr, K - 1);
                        }

                        return(Sigma_Value);
                    }

                    Complex New_Sigma_S(int n)
                    {
                        Complex Sigma_Value = 0;

                        for (int K = 1; K <= n; K++)
                        {
                            Sigma_Value += New_sigma_Sa * Complex.Pow(New_sigma_Sr, K - 1);
                        }
                        return(Sigma_Value);
                    }

                    // WriteLine("{0} {1} {2} {3}", Sigma_P(8000), Total_reflect_P, Sigma_S(8000), Total_reflect_S);

                    tan_pow       = Math.Pow(Math.Tan((Psi)), 2);
                    a_numeator    = tan_pow - Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    a_denominator = tan_pow + Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    alpha         = a_numeator / a_denominator;

                    b_numeator    = 2 * Math.Tan((Psi)) * Math.Cos((Delta)) * Math.Tan(dou_Rad2deg(45));
                    b_denominator = tan_pow + Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    beta          = b_numeator / b_denominator;

                    streamWriter.WriteLine("{0}\t{1}\t{2}\t{3}", sio2_nm, AOI, alpha, beta);

                    //값 초기화 후
                    //새로 변경한 값 적용
                    tan_pow       = Math.Pow(Math.Tan((Psi_new)), 2);
                    a_numeator    = tan_pow - Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    a_denominator = tan_pow + Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    new_alpha     = a_numeator / a_denominator;

                    b_numeator    = 2 * Math.Tan((Psi_new)) * Math.Cos((Delta_new)) * Math.Tan(dou_Rad2deg(45));
                    b_denominator = tan_pow + Math.Pow(Math.Tan(dou_Rad2deg(45)), 2);
                    new_beta      = b_numeator / b_denominator;

                    //배열에 저장 -> 추가로 뽑아내기
                    //streamWriter.WriteLine("{0} {1} {2} {3}", sio2_nm, AOI, alpha, beta);

                    //Rp 등비수열 구하기
                    Array_new_NM[i - 1]    = Convert.ToString(sio2_nm);
                    Array_new_Alpha[i - 1] = Convert.ToString(new_alpha);
                    Array_new_Beta[i - 1]  = Convert.ToString(new_beta);
                }
            }
            streamWriter.Close();
            WriteLine("SiO2_1000nm_on_Si_new.dat 생성 완료");

            //2-1)등비수열 "항의 개수" 파일 생성
            StreamWriter streamWriter_new = new StreamWriter(new FileStream("SiO2_1000nm_on_Si_new_dolarge.dat", FileMode.Create));

            streamWriter_new.WriteLine("wave(nm)\t\t AOI\t alpha_new\t\t beta_new");
            List <SiO2_1000nm_Data> SiO2_1000nm_NEW_Data = new List <SiO2_1000nm_Data>();

            for (int a = 0; a < Array_new_NM.Length; a++)
            {
                SiO2_1000nm_NEW_Data.Add(new SiO2_1000nm_Data
                {
                    nm    = Array_new_NM[a],
                    AOI   = "65",
                    Psi   = Array_new_Alpha[a],
                    Delta = Array_new_Beta[a]
                });
                streamWriter_new.WriteLine("{0}\t{1}\t{2}\t{3}", SiO2_1000nm_NEW_Data[a].nm, SiO2_1000nm_NEW_Data[a].AOI, SiO2_1000nm_NEW_Data[a].Psi, SiO2_1000nm_NEW_Data[a].Delta);
            }
            streamWriter_new.Close();

            WriteLine("SiO2_1000nm_on_Si_new_dolarge.dat 생성 완료");
        }
Example #10
0
        static void Main(string[] args)
        {
            //
            // "SiO2_new2.txt", "SiN_new2.txt", "Si_new2.txt" 파일로부터
            // 파장별 복소굴절률(n, k)을 읽어온다.
            //
            // 2021.03.29 이지원.
            //
            #region SiO2, SiN, Si 물성을 읽어온다.

            // "SiO2_new.txt" 파일 읽기.
            string[] SiO2_new2 = File.ReadAllLines("SiO2_new2.txt"); // SiO2 물성값 저장.(한 줄씩)
            string[] SingleLineData;                                 // 한 줄의 스펙트럼 데이터를 임시로 저장할 배열.

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하고 데이터를 받기 위해 LenData 변수를 선언한다.
            int      LenData         = SiO2_new2.Length - 1;
            double[] wavelength_SiO2 = new double[LenData];
            double[] n_SiO2          = new double[LenData];
            double[] k_SiO2          = new double[LenData];

            // SiO2_new 에 받은 데이터를 각 컬럼별로 저장한다.
            int StartIndex = 1;
            LenData = SiO2_new2.Length;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = SiO2_new2[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 각 컬럼에 해당하는 데이터를 저장한다.
                wavelength_SiO2[i - 1] = Double.Parse(SingleLineData[0]);
                n_SiO2[i - 1]          = Double.Parse(SingleLineData[1]);
                k_SiO2[i - 1]          = Double.Parse(SingleLineData[2]);
            }


            // "SiN_new.txt" 파일 읽기.
            string[] SiN_new2 = File.ReadAllLines("SiN_new2.txt");  // SiN 물성값 저장.(한 줄씩)

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하고 데이터를 받기 위해 LenData 변수를 선언한다.
            LenData = SiN_new2.Length - 1;
            double[] wavelength_SiN = new double[LenData];
            double[] n_SiN          = new double[LenData];
            double[] k_SiN          = new double[LenData];

            // SiN_new 에 받은 데이터를 각 컬럼별로 저장한다.
            LenData = SiN_new2.Length;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = SiN_new2[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 각 컬럼에 해당하는 데이터를 저장한다.
                wavelength_SiN[i - 1] = Double.Parse(SingleLineData[0]);
                n_SiN[i - 1]          = Double.Parse(SingleLineData[1]);
                k_SiN[i - 1]          = Double.Parse(SingleLineData[2]);
            }


            // "Si_new.txt" 파일 읽기.
            string[] Si_new2 = File.ReadAllLines("Si_new2.txt");  // Si 기판 물성값 저장.(한 줄씩)

            // 데이터의 첫번째 줄은 column 명이다.
            // 이를 제외하고 데이터를 받기 위해 LenData 변수를 선언한다.
            LenData = Si_new2.Length - 1;
            double[] wavelength_Si = new double[LenData];
            double[] n_Si          = new double[LenData];
            double[] k_Si          = new double[LenData];

            // Si_new 에 받은 데이터를 각 컬럼별로 저장한다.
            LenData = Si_new2.Length;
            for (int i = StartIndex; i < LenData; i++)
            {
                // tsv 형식의 데이터를 SingleLineData에 저장한다.
                SingleLineData = Si_new2[i].Split((char)0x09);  // 0x09 : 수평 탭.

                // 각 컬럼에 해당하는 데이터를 저장한다.
                wavelength_Si[i - 1] = Double.Parse(SingleLineData[0]);
                n_Si[i - 1]          = Double.Parse(SingleLineData[1]);
                k_Si[i - 1]          = Double.Parse(SingleLineData[2]);
            }
            #endregion

            //
            // 매질에 따른 interface matrix, layer matrix 를 구하여
            // scattering matrix 를 통해 alpha, beta 를 계산한다.
            //
            // 2021.03.30 이지원.
            //
            #region scattering matrix 를 통해 alpha, beta 를 계산한다.

            #region 배열, 변수 선언 및 초기화
            // degree, radian 변환 인라인 함수 정의.
            double degree2radian(double angle) => ((angle * (PI)) / 180.0);

            double  AOI_air = degree2radian(65.0);  // 입사각. (라디안)
            Complex N_air   = new Complex(1.0, 0);  // 공기의 굴절률.

            // 프레넬 반사계수를 담을 배열.
            Complex rp, rs;
            // 프레넬 투과계수를 담을 배열.
            Complex tp, ts;

            // 박막 두께 초기화.
            const double SiO2_thickness = 20.0,
                         SiN_thickness  = 30.0;

            const int LastLayer = 200;           // 박막 층수. (pair = 층수 / 2)
            int       LayerNum  = LastLayer + 1; // 박막의 층수. (1 : Si 기판)
            LenData = wavelength_Si.Length;

            Complex[,,] Sp = new Complex[LenData, 2, 2];      // scattering matrixs.
            Complex[,,] Ss = new Complex[LenData, 2, 2];
            Complex[,,] Ip = new Complex[LayerNum + 1, 2, 2]; // interface matrixs.
            Complex[,,] Is = new Complex[LayerNum + 1, 2, 2];
            Complex[,,] L  = new Complex[LayerNum, 2, 2];     // layer matrixs.
                                                              // alpha, beta 이론값을 담을 배열 선언.
            double[] alpha_cal = new double[LenData],
            beta_cal = new double[LenData];

            // Polarizer 오프셋 각.
            double polarizerAngle = degree2radian(45.0);

            Complex[] Rp = new Complex[LenData],
            Rs = new Complex[LenData];
            #endregion
            ///////////////////////////////////////////
            // 100 번 반복 시 소요 시간 측정.

            /*
             * int times = 100;
             * long timeSum = 0;
             * for (int time = 0; time < times; time++)
             * {
             *  Stopwatch stopwatch = new Stopwatch();
             *  stopwatch.Start();
             *  ///////////////////////////////////////////
             */
            // 층 구조 : air -> SiO2 -> SiN -> ... -> SiO2 -> SiN -> Si
            for (int i = 0; i < LenData; i++)
            {
                Complex Sintheta_j, Costheta_j, Sintheta_k, theta_k, Costheta_k;

                Complex PhaseThickness;

                // 파장에 대한 물질의 복소굴절률을 구한다.
                Complex N_SiO2 = new Complex(n_SiO2[i], -k_SiO2[i]);
                Complex N_SiN  = new Complex(n_SiN[i], -k_SiN[i]);
                Complex N_Si   = new Complex(n_Si[i], -k_Si[i]);

                #region air -> SiO2 경계면에서의 반사계수, 투과계수, 위상두께를 계산한다.

                // air, SiO2 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                Sintheta_j = new Complex(Sin((double)AOI_air), 0);
                Costheta_j = new Complex(Cos((double)AOI_air), 0);
                Sintheta_k = (N_air / N_SiO2) * Sintheta_j;
                // air, SiO2 경계면에서의 굴절각.
                theta_k    = Complex.Asin(Sintheta_k);
                Costheta_k = Complex.Cos(theta_k);

                // air, SiO2 경계면에서의 반사계수를 구한다.
                rp = ((N_SiO2 * Costheta_j) - (N_air * Costheta_k)) /
                     ((N_SiO2 * Costheta_j) + (N_air * Costheta_k));

                rs = ((N_air * Costheta_j) - (N_SiO2 * Costheta_k)) /
                     ((N_air * Costheta_j) + (N_SiO2 * Costheta_k));

                // air, SiO2 경계면에서의 투과계수를 구한다.
                tp = (N_air * Costheta_j * 2) /
                     ((N_SiO2 * Costheta_j) + (N_air * Costheta_k));

                ts = (N_air * Costheta_j * 2) /
                     ((N_air * Costheta_j) + (N_SiO2 * Costheta_k));


                // 위상 두께를 구한다.
                PhaseThickness = (SiO2_thickness * Math.PI * 2) * N_SiO2 * Costheta_k /
                                 wavelength_SiO2[i];

                Complex PlusE  = Complex.Exp(PhaseThickness * new Complex(0, 1.0));
                Complex MinusE = Complex.Exp(PhaseThickness * new Complex(0, -1.0));

                #endregion
                #region air -> SiO2 에서의 I, L 을 계산한다.
                // p-편광에 대한 interface matrix.
                Ip[0, 0, 0] = 1 / tp;
                Ip[0, 0, 1] = rp / tp;
                Ip[0, 1, 0] = rp / tp;
                Ip[0, 1, 1] = 1 / tp;

                // s-편광에 대한 interface matrix.
                Is[0, 0, 0] = 1 / ts;
                Is[0, 0, 1] = rs / ts;
                Is[0, 1, 0] = rs / ts;
                Is[0, 1, 1] = 1 / ts;

                // Layer matrix.
                L[0, 0, 0] = PlusE;
                L[0, 0, 1] = 0;
                L[0, 1, 0] = 0;
                L[0, 1, 1] = MinusE;


                #endregion

                #region air, Si 를 제외한 각 층마다 I, L 을 계산한다.
                for (int layer = 1; layer < LayerNum; layer++)
                {
                    switch (layer % 2)
                    {
                    // SiN -> SiO2.
                    case 0:
                    {
                        #region SiN -> SiO2 경계면에서의 반사계수, 투과계수, 위상두께를 구한다.

                        // SiN, SiO2 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                        Sintheta_j = Complex.Sin(theta_k);
                        Costheta_j = Complex.Cos(theta_k);
                        Sintheta_k = (N_SiN / N_SiO2) * Sintheta_j;
                        theta_k    = Complex.Asin(Sintheta_k);
                        Costheta_k = Complex.Cos(theta_k);

                        // SiN, SiO2 경계면에서의 반사계수를 구한다.
                        rp = ((N_SiO2 * Costheta_j) - (N_SiN * Costheta_k)) /
                             ((N_SiO2 * Costheta_j) + (N_SiN * Costheta_k));

                        rs = ((N_SiN * Costheta_j) - (N_SiO2 * Costheta_k)) /
                             ((N_SiN * Costheta_j) + (N_SiO2 * Costheta_k));

                        // SiN, SiO2 경계면에서의 투과계수를 구한다.
                        tp = (N_SiN * Costheta_j * 2) /
                             ((N_SiO2 * Costheta_j) + (N_SiN * Costheta_k));

                        ts = (N_SiN * Costheta_j * 2) /
                             ((N_SiN * Costheta_j) + (N_SiO2 * Costheta_k));

                        // SiO2 의 위상 두께를 구한다.
                        PhaseThickness = (SiO2_thickness * Math.PI * 2) * N_SiO2 * Costheta_k /
                                         wavelength_SiO2[i];

                        PlusE  = Complex.Exp(PhaseThickness * new Complex(0, 1.0));
                        MinusE = Complex.Exp(PhaseThickness * new Complex(0, -1.0));

                        #endregion
                        #region SiN -> SiO2 에서의 I, L 을 계산한다.
                        // p-편광에 대한 interface matrix.
                        Ip[layer, 0, 0] = 1 / tp;
                        Ip[layer, 0, 1] = rp / tp;
                        Ip[layer, 1, 0] = rp / tp;
                        Ip[layer, 1, 1] = 1 / tp;

                        // s-편광에 대한 interface matrix.
                        Is[layer, 0, 0] = 1 / ts;
                        Is[layer, 0, 1] = rs / ts;
                        Is[layer, 1, 0] = rs / ts;
                        Is[layer, 1, 1] = 1 / ts;

                        // Layer matrix.
                        L[layer, 0, 0] = PlusE;
                        L[layer, 0, 1] = 0;
                        L[layer, 1, 0] = 0;
                        L[layer, 1, 1] = MinusE;

                        #endregion
                    }
                    break;

                    // SiO2 -> SiN.
                    case 1:
                    {
                        #region SiO2 -> SiN 경계면에서의 반사계수, 투과계수, 위상두께를 구한다.

                        // SiO2, SiN 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                        Sintheta_j = Complex.Sin(theta_k);
                        Costheta_j = Complex.Cos(theta_k);
                        Sintheta_k = (N_SiO2 / N_SiN) * Sintheta_j;
                        theta_k    = Complex.Asin(Sintheta_k);
                        Costheta_k = Complex.Cos(theta_k);

                        // SiO2, SiN 경계면에서의 반사계수를 구한다.
                        rp = ((N_SiN * Costheta_j) - (N_SiO2 * Costheta_k)) /
                             ((N_SiN * Costheta_j) + (N_SiO2 * Costheta_k));

                        rs = ((N_SiO2 * Costheta_j) - (N_SiN * Costheta_k)) /
                             ((N_SiO2 * Costheta_j) + (N_SiN * Costheta_k));

                        // SiO2, SiN 경계면에서의 투과계수를 구한다.
                        tp = (N_SiO2 * Costheta_j * 2) /
                             ((N_SiN * Costheta_j) + (N_SiO2 * Costheta_k));

                        ts = (N_SiO2 * Costheta_j * 2) /
                             ((N_SiO2 * Costheta_j) + (N_SiN * Costheta_k));

                        // SiN 의 위상 두께를 구한다.
                        PhaseThickness = (SiN_thickness * Math.PI * 2) * N_SiN * Costheta_k /
                                         wavelength_SiO2[i];

                        PlusE  = Complex.Exp(PhaseThickness * new Complex(0, 1.0));
                        MinusE = Complex.Exp(PhaseThickness * new Complex(0, -1.0));

                        #endregion
                        #region SiO2 -> SiN 에서의 I, L 을 계산한다.
                        // p-편광에 대한 interface matrix.
                        Ip[layer, 0, 0] = 1 / tp;
                        Ip[layer, 0, 1] = rp / tp;
                        Ip[layer, 1, 0] = rp / tp;
                        Ip[layer, 1, 1] = 1 / tp;

                        // s-편광에 대한 interface matrix.
                        Is[layer, 0, 0] = 1 / ts;
                        Is[layer, 0, 1] = rs / ts;
                        Is[layer, 1, 0] = rs / ts;
                        Is[layer, 1, 1] = 1 / ts;

                        // Layer matrix.
                        L[layer, 0, 0] = PlusE;
                        L[layer, 0, 1] = 0;
                        L[layer, 1, 0] = 0;
                        L[layer, 1, 1] = MinusE;

                        #endregion
                    }
                    break;

                    default:
                        break;
                    }
                }
                #endregion

                #region SiN -> Si 경계면에서의 반사계수, 투과계수를 계산한다.

                // SiN, Si 경계면에서의 굴절각을 구한다. (스넬의 법칙)
                Sintheta_j = Complex.Sin(theta_k);
                Costheta_j = Complex.Cos(theta_k);
                Sintheta_k = (N_SiN / N_Si) * Sintheta_j;
                theta_k    = Complex.Asin(Sintheta_k);
                Costheta_k = Complex.Cos(theta_k);

                // SiO2, SiN 경계면에서의 반사계수를 구한다.
                rp = ((N_Si * Costheta_j) - (N_SiN * Costheta_k)) /
                     ((N_Si * Costheta_j) + (N_SiN * Costheta_k));

                rs = ((N_SiN * Costheta_j) - (N_Si * Costheta_k)) /
                     ((N_SiN * Costheta_j) + (N_Si * Costheta_k));

                // SiO2, SiN 경계면에서의 투과계수를 구한다.
                tp = (N_SiN * Costheta_j * 2) /
                     ((N_Si * Costheta_j) + (N_SiN * Costheta_k));

                ts = (N_SiN * Costheta_j * 2) /
                     ((N_SiN * Costheta_j) + (N_Si * Costheta_k));

                #endregion
                #region SiN -> Si 에서의 I 를 계산한다.

                Ip[LayerNum, 0, 0] = 1 / tp;
                Ip[LayerNum, 0, 1] = rp / tp;
                Ip[LayerNum, 1, 0] = rp / tp;
                Ip[LayerNum, 1, 1] = 1 / tp;

                Is[LayerNum, 0, 0] = 1 / ts;
                Is[LayerNum, 0, 1] = rs / ts;
                Is[LayerNum, 1, 0] = rs / ts;
                Is[LayerNum, 1, 1] = 1 / ts;

                #endregion

                #region scattering matrix 를 계산한다.

                #region strassen algorithm

                Sp[i, 0, 0] = new Complex(1, 0);
                Sp[i, 1, 1] = new Complex(1, 0);
                Ss[i, 0, 0] = new Complex(1, 0);
                Ss[i, 1, 1] = new Complex(1, 0);
                Complex[] C = new Complex[10];
                Complex[] P = new Complex[7];
                //Complex[,] tempP = new Complex[2,2];
                //Complex[,] tempS = new Complex[2,2];
                //tempP[0, 0] = new Complex(1, 0);
                //tempP[1, 1] = new Complex(1, 0);
                //tempS[0, 0] = new Complex(1, 0);
                //tempS[1, 1] = new Complex(1, 0);
                for (int layer = 0; layer < LayerNum; layer++)
                {
                    //strassen algorithm
                    //I 곱하기(p편광)
                    C[0] = Ip[layer, 0, 1] - Ip[layer, 1, 1];
                    C[1] = Sp[i, 0, 0] + Sp[i, 0, 1];
                    C[2] = Sp[i, 1, 0] + Sp[i, 1, 1];
                    C[3] = Ip[layer, 1, 0] - Ip[layer, 0, 0];
                    C[4] = Sp[i, 0, 0] + Sp[i, 1, 1];
                    C[5] = Ip[layer, 0, 0] + Ip[layer, 1, 1];
                    C[6] = Sp[i, 0, 1] - Sp[i, 1, 1];
                    C[7] = Ip[layer, 1, 0] + Ip[layer, 1, 1];
                    C[8] = Sp[i, 0, 0] - Sp[i, 1, 0];
                    C[9] = Ip[layer, 0, 0] + Ip[layer, 0, 1];

                    P[0] = Sp[i, 0, 0] * C[0];
                    P[1] = C[1] * Ip[layer, 1, 1];
                    P[2] = C[2] * Ip[layer, 0, 0];
                    P[3] = Sp[i, 1, 1] * C[3];
                    P[4] = C[4] * C[5];
                    P[5] = C[6] * C[7];
                    P[6] = C[8] * C[9];

                    Sp[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                    Sp[i, 0, 1] = P[0] + P[1];
                    Sp[i, 1, 0] = P[2] + P[3];
                    Sp[i, 1, 1] = P[0] + P[4] - P[2] - P[6];

                    //L곱하기(p편광)
                    C[0] = L[layer, 0, 1] - L[layer, 1, 1];
                    C[1] = Sp[i, 0, 0] + Sp[i, 0, 1];
                    C[2] = Sp[i, 1, 0] + Sp[i, 1, 1];
                    C[3] = L[layer, 1, 0] - L[layer, 0, 0];
                    C[4] = Sp[i, 0, 0] + Sp[i, 1, 1];
                    C[5] = L[layer, 0, 0] + L[layer, 1, 1];
                    C[6] = Sp[i, 0, 1] - Sp[i, 1, 1];
                    C[7] = L[layer, 1, 0] + L[layer, 1, 1];
                    C[8] = Sp[i, 0, 0] - Sp[i, 1, 0];
                    C[9] = L[layer, 0, 0] + L[layer, 0, 1];
                    //
                    P[0] = Sp[i, 0, 0] * C[0];
                    P[1] = C[1] * L[layer, 1, 1];
                    P[2] = C[2] * L[layer, 0, 0];
                    P[3] = Sp[i, 1, 1] * C[3];
                    P[4] = C[4] * C[5];
                    P[5] = C[6] * C[7];
                    P[6] = C[8] * C[9];

                    Sp[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                    Sp[i, 0, 1] = P[0] + P[1];
                    Sp[i, 1, 0] = P[2] + P[3];
                    Sp[i, 1, 1] = P[0] + P[4] - P[2] - P[6];

                    //I 곱하기(S편광)
                    C[0] = Is[layer, 0, 1] - Is[layer, 1, 1];
                    C[1] = Ss[i, 0, 0] + Ss[i, 0, 1];
                    C[2] = Ss[i, 1, 0] + Ss[i, 1, 1];
                    C[3] = Is[layer, 1, 0] - Is[layer, 0, 0];
                    C[4] = Ss[i, 0, 0] + Ss[i, 1, 1];
                    C[5] = Is[layer, 0, 0] + Is[layer, 1, 1];
                    C[6] = Ss[i, 0, 1] - Ss[i, 1, 1];
                    C[7] = Is[layer, 1, 0] + Is[layer, 1, 1];
                    C[8] = Ss[i, 0, 0] - Ss[i, 1, 0];
                    C[9] = Is[layer, 0, 0] + Is[layer, 0, 1];
                    ////
                    P[0] = Ss[i, 0, 0] * C[0];
                    P[1] = C[1] * Is[layer, 1, 1];
                    P[2] = C[2] * Is[layer, 0, 0];
                    P[3] = Ss[i, 1, 1] * C[3];
                    P[4] = C[4] * C[5];
                    P[5] = C[6] * C[7];
                    P[6] = C[8] * C[9];

                    Ss[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                    Ss[i, 0, 1] = P[0] + P[1];
                    Ss[i, 1, 0] = P[2] + P[3];
                    Ss[i, 1, 1] = P[0] + P[4] - P[2] - P[6];


                    //L곱하기(P편광, S편광)
                    C[0] = L[layer, 0, 1] - L[layer, 1, 1];
                    C[1] = Ss[i, 0, 0] + Ss[i, 0, 1];
                    C[2] = Ss[i, 1, 0] + Ss[i, 1, 1];
                    C[3] = L[layer, 1, 0] - L[layer, 0, 0];
                    C[4] = Ss[i, 0, 0] + Ss[i, 1, 1];
                    C[5] = L[layer, 0, 0] + L[layer, 1, 1];
                    C[6] = Ss[i, 0, 1] - Ss[i, 1, 1];
                    C[7] = L[layer, 1, 0] + L[layer, 1, 1];
                    C[8] = Ss[i, 0, 0] - Ss[i, 1, 0];
                    C[9] = L[layer, 0, 0] + L[layer, 0, 1];
                    //
                    P[0] = Ss[i, 0, 0] * C[0];
                    P[1] = C[1] * L[layer, 1, 1];
                    P[2] = C[2] * L[layer, 0, 0];
                    P[3] = Ss[i, 1, 1] * C[3];
                    P[4] = C[4] * C[5];
                    P[5] = C[6] * C[7];
                    P[6] = C[8] * C[9];

                    Ss[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                    Ss[i, 0, 1] = P[0] + P[1];
                    Ss[i, 1, 0] = P[2] + P[3];
                    Ss[i, 1, 1] = P[0] + P[4] - P[2] - P[6];
                }
                //마지막 Interface matrix계산

                //I 곱하기(P편광)
                C[0] = Ip[LayerNum, 0, 1] - Ip[LayerNum, 1, 1];
                C[1] = Sp[i, 0, 0] + Sp[i, 0, 1];
                C[2] = Sp[i, 1, 0] + Sp[i, 1, 1];
                C[3] = Ip[LayerNum, 1, 0] - Ip[LayerNum, 0, 0];
                C[4] = Sp[i, 0, 0] + Sp[i, 1, 1];
                C[5] = Ip[LayerNum, 0, 0] + Ip[LayerNum, 1, 1];
                C[6] = Sp[i, 0, 1] - Sp[i, 1, 1];
                C[7] = Ip[LayerNum, 1, 0] + Ip[LayerNum, 1, 1];
                C[8] = Sp[i, 0, 0] - Sp[i, 1, 0];
                C[9] = Ip[LayerNum, 0, 0] + Ip[LayerNum, 0, 1];

                P[0] = Sp[i, 0, 0] * C[0];
                P[1] = C[1] * Ip[LayerNum, 1, 1];
                P[2] = C[2] * Ip[LayerNum, 0, 0];
                P[3] = Sp[i, 1, 1] * C[3];
                P[4] = C[4] * C[5];
                P[5] = C[6] * C[7];
                P[6] = C[8] * C[9];

                Sp[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                Sp[i, 0, 1] = P[0] + P[1];
                Sp[i, 1, 0] = P[2] + P[3];
                Sp[i, 1, 1] = P[0] + P[4] - P[2] - P[6];

                //I 곱하기(S편광)
                C[0] = Is[LayerNum, 0, 1] - Is[LayerNum, 1, 1];
                C[1] = Ss[i, 0, 0] + Ss[i, 0, 1];
                C[2] = Ss[i, 1, 0] + Ss[i, 1, 1];
                C[3] = Is[LayerNum, 1, 0] - Is[LayerNum, 0, 0];
                C[4] = Ss[i, 0, 0] + Ss[i, 1, 1];
                C[5] = Is[LayerNum, 0, 0] + Is[LayerNum, 1, 1];
                C[6] = Ss[i, 0, 1] - Ss[i, 1, 1];
                C[7] = Is[LayerNum, 1, 0] + Is[LayerNum, 1, 1];
                C[8] = Ss[i, 0, 0] - Ss[i, 1, 0];
                C[9] = Is[LayerNum, 0, 0] + Is[LayerNum, 0, 1];

                P[0] = Ss[i, 0, 0] * C[0];
                P[1] = C[1] * Is[LayerNum, 1, 1];
                P[2] = C[2] * Is[LayerNum, 0, 0];
                P[3] = Ss[i, 1, 1] * C[3];
                P[4] = C[4] * C[5];
                P[5] = C[6] * C[7];
                P[6] = C[8] * C[9];

                Ss[i, 0, 0] = P[4] + P[3] - P[1] + P[5];
                Ss[i, 0, 1] = P[0] + P[1];
                Ss[i, 1, 0] = P[2] + P[3];
                Ss[i, 1, 1] = P[0] + P[4] - P[2] - P[6];

                #endregion

                #region 행렬 계산

                /*
                 * Complex[,] tempP = {
                 *  {new Complex(1, 0), new Complex(0, 0) },
                 *  {new Complex(0, 0), new Complex(1, 0) }
                 * };
                 *
                 * Complex[,] tempS = {
                 *  {new Complex(1, 0), new Complex(0, 0) },
                 *  {new Complex(0, 0), new Complex(1, 0) }
                 * };
                 * Complex tempP00, tempP01, tempP10, tempP11;
                 * Complex tempS00, tempS01, tempS10, tempS11;
                 *
                 * // 층의 개수만큼 I, L 을 곱해준다.
                 * for (int layer = 0; layer < LayerNum; layer++)
                 * {
                 *  tempP00 = tempP[0, 0];  // 1
                 *  tempP01 = tempP[0, 1];  // 0
                 *  tempP10 = tempP[1, 0];  // 0
                 *  tempP11 = tempP[1, 1];  // 1
                 *
                 *  // I 곱하기. (p편광)
                 *  tempP[0, 0] = tempP00 * Ip[layer, 0, 0] + tempP01 * Ip[layer, 1, 0];
                 *  tempP[0, 1] = tempP00 * Ip[layer, 0, 1] + tempP01 * Ip[layer, 1, 1];
                 *  tempP[1, 0] = tempP10 * Ip[layer, 0, 0] + tempP11 * Ip[layer, 1, 0];
                 *  tempP[1, 1] = tempP10 * Ip[layer, 0, 1] + tempP11 * Ip[layer, 1, 1];
                 *
                 *  tempP00 = tempP[0, 0];  // 1
                 *  tempP01 = tempP[0, 1];  // 0
                 *  tempP10 = tempP[1, 0];  // 0
                 *  tempP11 = tempP[1, 1];  // 1
                 *
                 *  // L 곱하기. (p편광)
                 *  tempP[0, 0] = tempP00 * L[layer, 0, 0] + tempP01 * L[layer, 1, 0];
                 *  tempP[0, 1] = tempP00 * L[layer, 0, 1] + tempP01 * L[layer, 1, 1];
                 *  tempP[1, 0] = tempP10 * L[layer, 0, 0] + tempP11 * L[layer, 1, 0];
                 *  tempP[1, 1] = tempP10 * L[layer, 0, 1] + tempP11 * L[layer, 1, 1];
                 *
                 *  // I 곱하기. (s편광)
                 *  tempS00 = tempS[0, 0];  // 1
                 *  tempS01 = tempS[0, 1];  // 0
                 *  tempS10 = tempS[1, 0];  // 0
                 *  tempS11 = tempS[1, 1];  // 1
                 *
                 *  tempS[0, 0] = tempS00 * Is[layer, 0, 0] + tempS01 * Is[layer, 1, 0];
                 *  tempS[0, 1] = tempS00 * Is[layer, 0, 1] + tempS01 * Is[layer, 1, 1];
                 *  tempS[1, 0] = tempS10 * Is[layer, 0, 0] + tempS11 * Is[layer, 1, 0];
                 *  tempS[1, 1] = tempS10 * Is[layer, 0, 1] + tempS11 * Is[layer, 1, 1];
                 *
                 *  // L 곱하기. (s편광)
                 *  tempS00 = tempS[0, 0];  // 1
                 *  tempS01 = tempS[0, 1];  // 0
                 *  tempS10 = tempS[1, 0];  // 0
                 *  tempS11 = tempS[1, 1];  // 1
                 *
                 *  tempS[0, 0] = tempS00 * L[layer, 0, 0] + tempS01 * L[layer, 1, 0];
                 *  tempS[0, 1] = tempS00 * L[layer, 0, 1] + tempS01 * L[layer, 1, 1];
                 *  tempS[1, 0] = tempS10 * L[layer, 0, 0] + tempS11 * L[layer, 1, 0];
                 *  tempS[1, 1] = tempS10 * L[layer, 0, 1] + tempS11 * L[layer, 1, 1];
                 * }
                 * // 마지막 interface matrix 를 곱해준다. (Si 기판에 관한 것)
                 * // I 곱하기. (p편광)
                 * tempP00 = tempP[0, 0];  // 1
                 * tempP01 = tempP[0, 1];  // 0
                 * tempP10 = tempP[1, 0];  // 0
                 * tempP11 = tempP[1, 1];  // 1
                 *
                 * tempP[0, 0] = tempP00 * Ip[LayerNum, 0, 0] + tempP01 * Ip[LayerNum, 1, 0];
                 * tempP[0, 1] = tempP00 * Ip[LayerNum, 0, 1] + tempP01 * Ip[LayerNum, 1, 1];
                 * tempP[1, 0] = tempP10 * Ip[LayerNum, 0, 0] + tempP11 * Ip[LayerNum, 1, 0];
                 * tempP[1, 1] = tempP10 * Ip[LayerNum, 0, 1] + tempP11 * Ip[LayerNum, 1, 1];
                 *
                 * // I 곱하기. (s편광)
                 * tempS00 = tempS[0, 0];  // 1
                 * tempS01 = tempS[0, 1];  // 0
                 * tempS10 = tempS[1, 0];  // 0
                 * tempS11 = tempS[1, 1];  // 1
                 *
                 * tempS[0, 0] = tempS00 * Is[LayerNum, 0, 0] + tempS01 * Is[LayerNum, 1, 0];
                 * tempS[0, 1] = tempS00 * Is[LayerNum, 0, 1] + tempS01 * Is[LayerNum, 1, 1];
                 * tempS[1, 0] = tempS10 * Is[LayerNum, 0, 0] + tempS11 * Is[LayerNum, 1, 0];
                 * tempS[1, 1] = tempS10 * Is[LayerNum, 0, 1] + tempS11 * Is[LayerNum, 1, 1];
                 *
                 * // 계산이 완료된 temp 행렬의 각 요소를 대응되는 scattering matrix 의 각 요소에 대입한다.
                 * Sp[i, 0, 0] = tempP[0, 0];
                 * Sp[i, 0, 1] = tempP[0, 1];
                 * Sp[i, 1, 0] = tempP[1, 0];
                 * Sp[i, 1, 1] = tempP[1, 1];
                 *
                 * Ss[i, 0, 0] = tempS[0, 0];
                 * Ss[i, 0, 1] = tempS[0, 1];
                 * Ss[i, 1, 0] = tempS[1, 0];
                 * Ss[i, 1, 1] = tempS[1, 1];
                 */
                #endregion

                #endregion
                #region alpha, beta 를 계산한다.
                Rp[i] = Sp[i, 1, 0] / Sp[i, 0, 0];
                Rs[i] = Ss[i, 1, 0] / Ss[i, 0, 0];

                // 총 반사계수비. (복소반사계수비)
                Complex rho = Rp[i] / Rs[i];

                // Psi, Delta.
                double Psi   = Atan(rho.Magnitude);
                double Delta = rho.Phase;


                alpha_cal[i] = (Pow(Tan(Psi), 2.0) - Pow(Tan(polarizerAngle), 2.0)) /
                               (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));

                beta_cal[i] = (2.0 * Tan(Psi) * Cos(Delta) * Tan(polarizerAngle)) /
                              (Pow(Tan(Psi), 2.0) + Pow(Tan(polarizerAngle), 2.0));
                #endregion
            }

            /*
             *  /////////////////////////////////////////////
             *  // 소요시간 측정 범위 종료 지점.
             *  stopwatch.Stop();
             *  timeSum += stopwatch.ElapsedMilliseconds;
             *  //WriteLine($"소요 시간: {stopwatch.ElapsedMilliseconds}ms");
             * }
             * long avgTime = timeSum / times;
             * //WriteLine($"avgTime: {avgTime}(ms)");
             * /////////////////////////////////////////////
             */

            #region 출력
            for (int i = 0; i < LenData; i++)
            {
                WriteLine(
                    wavelength_Si[i] + "\t"
                    + alpha_cal[i] + "\t"
                    + beta_cal[i]);
            }
            #endregion
            #endregion

            #region  일 쓰기.
            // 파일 쓰기.
            //using (StreamWriter NewSpectrumOutputFile = new StreamWriter("100pairs.dat"))
            //{
            //    // 컬럼 명 쓰기.
            //    NewSpectrumOutputFile.WriteLine(
            //        "wavelength(nm)"    + "\t"
            //        + "alpha"           + "\t"
            //        + "beta");    // 컬럼명 쓰기.
            //    // WriteLine(Columns);
            //
            //
            //    // 스펙트럼 데이터 쓰기.
            //    for (int i = 0; i < LenData; i++)
            //    {
            //        // tsv 데이터 형식으로 데이터를 쓴다.
            //        NewSpectrumOutputFile.WriteLine(
            //            wavelength_Si[i]    + "\t"
            //            + alpha_cal[i]      + "\t"
            //            + beta_cal[i]);
            //    }
            //}

            #endregion
        }
Example #11
0
        /// <summary>
        /// Method creates overlapping ERB filters (ported from Malcolm Slaney's MATLAB code).
        /// </summary>
        /// <param name="erbFilterCount">Number of ERB filters</param>
        /// <param name="fftSize">Assumed size of FFT</param>
        /// <param name="samplingRate">Assumed sampling rate</param>
        /// <param name="lowFreq">Lower bound of the frequency range</param>
        /// <param name="highFreq">Upper bound of the frequency range</param>
        /// <param name="normalizeGain">True if gain should be normalized; false if all filters should have same height 1.0</param>
        /// <returns>Array of ERB filters</returns>
        public static float[][] Erb(
            int erbFilterCount, int fftSize, int samplingRate, double lowFreq = 0, double highFreq = 0, bool normalizeGain = true)
        {
            if (lowFreq < 0)
            {
                lowFreq = 0;
            }
            if (highFreq <= lowFreq)
            {
                highFreq = samplingRate / 2.0;
            }

            const double earQ  = 9.26449;
            const double minBw = 24.7;
            const double bw    = earQ * minBw;
            const int    order = 1;

            var t = 1.0 / samplingRate;

            var frequencies = new double[erbFilterCount];

            for (var i = 1; i <= erbFilterCount; i++)
            {
                frequencies[erbFilterCount - i] =
                    -bw + Math.Exp(i * (-Math.Log(highFreq + bw) + Math.Log(lowFreq + bw)) / erbFilterCount) * (highFreq + bw);
            }

            var ucirc = new Complex[fftSize / 2 + 1];

            for (var i = 0; i < ucirc.Length; i++)
            {
                ucirc[i] = Complex.Exp((2 * Complex.ImaginaryOne * i * Math.PI) / fftSize);
            }

            var rootPos = Math.Sqrt(3 + Math.Pow(2, 1.5));
            var rootNeg = Math.Sqrt(3 - Math.Pow(2, 1.5));

            var fft = new Fft(fftSize);

            var erbFilterBank = new float[erbFilterCount][];

            for (var i = 0; i < erbFilterCount; i++)
            {
                var cf  = frequencies[i];
                var erb = Math.Pow(Math.Pow(cf / earQ, order) + Math.Pow(minBw, order), 1.0 / order);
                var b   = 1.019 * 2 * Math.PI * erb;

                var theta  = 2 * cf * Math.PI * t;
                var itheta = Complex.Exp(2 * Complex.ImaginaryOne * theta);

                var a0 = t;
                var a2 = 0.0;
                var b0 = 1.0;
                var b1 = -2 * Math.Cos(theta) / Math.Exp(b * t);
                var b2 = Math.Exp(-2 * b * t);

                var common = -t *Math.Exp(-b *t);

                var k1 = Math.Cos(theta) + rootPos * Math.Sin(theta);
                var k2 = Math.Cos(theta) - rootPos * Math.Sin(theta);
                var k3 = Math.Cos(theta) + rootNeg * Math.Sin(theta);
                var k4 = Math.Cos(theta) - rootNeg * Math.Sin(theta);

                var a11 = common * k1;
                var a12 = common * k2;
                var a13 = common * k3;
                var a14 = common * k4;

                var gainArg = Complex.Exp(Complex.ImaginaryOne * theta - b * t);

                var gain = Complex.Abs(
                    (itheta - gainArg * k1) *
                    (itheta - gainArg * k2) *
                    (itheta - gainArg * k3) *
                    (itheta - gainArg * k4) *
                    Complex.Pow(t * Math.Exp(b * t) / (-1.0 / Math.Exp(b * t) + 1 + itheta * (1 - Math.Exp(b * t))), 4.0));

                var filter1 = new IirFilter(new[] { a0, a11, a2 }, new[] { b0, b1, b2 });
                var filter2 = new IirFilter(new[] { a0, a12, a2 }, new[] { b0, b1, b2 });
                var filter3 = new IirFilter(new[] { a0, a13, a2 }, new[] { b0, b1, b2 });
                var filter4 = new IirFilter(new[] { a0, a14, a2 }, new[] { b0, b1, b2 });

                var ir = new DiscreteSignal(1, fftSize);
                ir[0] = 1.0f;

                var chain = new FilterChain(new[] { filter1, filter2, filter3, filter4 });

                var kernel = chain.ApplyTo(ir);

                erbFilterBank[i] = fft.PowerSpectrum(kernel, false).Samples;
            }

            // normalize gain (by default)

            if (!normalizeGain)
            {
                return(erbFilterBank);
            }

            foreach (var filter in erbFilterBank)
            {
                var sum = 0.0;
                for (var j = 0; j < filter.Length; j++)
                {
                    sum += Math.Abs(filter[j] * filter[j]);
                }

                var weight = Math.Sqrt(sum * samplingRate / fftSize);

                for (var j = 0; j < filter.Length; j++)
                {
                    filter[j] = (float)(filter[j] / weight);
                }
            }

            return(erbFilterBank);
        }
Example #12
0
        // Onset Detection function - Determines Start and Finish times of a note and the frequency of the note over each duration.

        private void onsetDetection()
        {
            float[]    HFC;
            int        starts = 0;
            int        stops  = 0;
            List <int> lengths;
            List <int> noteStarts;
            List <int> noteStops;

            double[] pitches;

            int     ll;
            double  pi = 3.14159265;
            Complex i  = Complex.ImaginaryOne;

            //max size
            noteStarts = new List <int>(100);
            noteStops  = new List <int>(100);
            lengths    = new List <int>(100);
            pitches    = new double[100];

            SolidColorBrush sheetBrush = new SolidColorBrush(Colors.Black);
            SolidColorBrush ErrorBrush = new SolidColorBrush(Colors.Red);
            SolidColorBrush whiteBrush = new SolidColorBrush(Colors.White);

            HFC = new float[stftRep.timeFreqData[0].Length];

            ////HFC fuckup
            //first thing to improve
            //Can be improved
            //for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            //{
            Parallel.For(0, stftRep.timeFreqData[0].Length, jj =>
            {
                for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
                {
                    //parallising this loop is bad
                    //Causing fuckups
                    HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
                }
            });
            //}

            float maxi = HFC.Max();

            //not worth
            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                HFC[jj] = (float)Math.Pow((HFC[jj] / maxi), 2);
            }

            //end of this goes up in note count
            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                if (starts > stops)
                {
                    if (HFC[jj] < 0.001)
                    {
                        noteStops.Add(jj * ((stftRep.wSamp - 1) / 2));
                        stops = stops + 1;
                    }
                }
                else if (starts - stops == 0)
                {
                    if (HFC[jj] > 0.001)
                    {
                        noteStarts.Add(jj * ((stftRep.wSamp - 1) / 2));
                        starts = starts + 1;
                    }
                }
            }

            if (starts > stops)
            {
                noteStops.Add(waveIn.data.Length);
            }


            // DETERMINES START AND FINISH TIME OF NOTES BASED ON ONSET DETECTION

            ///*

            for (int ii = 0; ii < noteStops.Count; ii++)
            {
                lengths.Add(noteStops[ii] - noteStarts[ii]);
            }
            int breakint = 0;

            //this is where the meat happens
            //insafe because of the instant yeet
            int[]       nearest = new int[lengths.Count];
            Complex[][] Y       = new Complex[lengths.Count][];
            Complex[][] compX   = new Complex[lengths.Count][];
            twiddles = new Complex[lengths.Count][];

            for (int mm = 0; mm < lengths.Count; mm++)
            {
                //Parallel.For(0, lengths.Count, mm =>
                //{
                nearest[mm]  = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                twiddles[mm] = new Complex[nearest[mm]];
                for (ll = 0; ll < nearest[mm]; ll++)
                {
                    double a = 2 * pi * ll / (double)nearest[mm];
                    twiddles[mm][ll] = Complex.Pow(Complex.Exp(-i), (float)a);
                }

                compX[mm] = new Complex[nearest[mm]];
                for (int kk = 0; kk < nearest[mm]; kk++)
                {
                    if (kk < lengths[mm] && (noteStarts[mm] + kk) < waveIn.wave.Length)
                    {
                        compX[mm][kk] = waveIn.wave[noteStarts[mm] + kk];
                    }
                    else
                    {
                        compX[mm][kk] = Complex.Zero;
                    }
                }
                //2ms
            }
            breakint = 1;
            //for (mm =0; mm < lengths.Count; mm++) {
            Parallel.For(0, lengths.Count, mm => {
                Y[mm] = new Complex[nearest[mm]];

                Y[mm] = fft(compX[mm], nearest[mm], mm);

                double[] absY;

                absY = new double[nearest[mm]];

                double maximum = 0;
                int maxInd     = 0;

                for (int jj = 0; jj < Y[mm].Length; jj++)
                {
                    //no improvement paral
                    //Parallel.For(0, Y[mm].Length, jj => {
                    absY[jj] = Y[mm][jj].Magnitude;
                    if (absY[jj] > maximum)
                    {
                        maximum = absY[jj];
                        maxInd  = jj;
                    }
                }
                //});
                //max ind is 50% broken
                for (int div = 6; div > 1; div--)
                {
                    if (maxInd > nearest[mm] / 2)
                    {
                        if (absY[(int)Math.Floor((double)(nearest[mm] - maxInd) / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = (nearest[mm] - maxInd) / div;
                        }
                    }
                    else
                    {
                        //these bottom calcs are breaking
                        if (absY[(int)Math.Floor((double)maxInd / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = maxInd / div;
                        }
                    }
                }

                //one of these might be breaking
                if (maxInd > nearest[mm] / 2)
                {
                    pitches[mm] = ((nearest[mm] - maxInd) * waveIn.SampleRate / nearest[mm]);
                }
                else
                {
                    pitches[mm] = (maxInd * waveIn.SampleRate / nearest[mm]);
                }
                //5ms

                //}
            });
            breakint = 0;
            //1.713s
            //});
            musicNote[] noteArray;
            noteArray = new musicNote[noteStarts.Count()];

            for (int ii = 0; ii < noteStarts.Count(); ii++)
            {
                noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            }

            int[] sheetPitchArray = new int[sheetmusic.Length];
            int[] notePitchArray  = new int[noteArray.Length];

            for (int ii = 0; ii < sheetmusic.Length; ii++)
            {
                sheetPitchArray[ii] = sheetmusic[ii].pitch % 12;
            }

            for (int jj = 0; jj < noteArray.Length; jj++)
            {
                notePitchArray[jj] = noteArray[jj].pitch % 12;
            }

            string[] alignedStrings = new string[2];

            //Bj in string match breaks because not pitch array is out of bounds
            alignedStrings = stringMatch(sheetPitchArray, notePitchArray);

            musicNote[] alignedStaffArray = new musicNote[alignedStrings[0].Length / 2];
            musicNote[] alignedNoteArray  = new musicNote[alignedStrings[1].Length / 2];
            int         staffCount        = 0;
            int         noteCount         = 0;

            for (int ii = 0; ii < alignedStrings[0].Length / 2; ii++)
            {
                if (alignedStrings[0][2 * ii] == ' ')
                {
                    alignedStaffArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedStaffArray[ii] = sheetmusic[staffCount];
                    staffCount++;
                }

                if (alignedStrings[1][2 * ii] == ' ')
                {
                    alignedNoteArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedNoteArray[ii] = noteArray[noteCount];
                    noteCount++;
                }
            }

            breakint = 1;
            // STAFF TAB DISPLAY

            Ellipse[] notes;
            Line[]    stems;
            notes = new Ellipse[alignedNoteArray.Length];
            stems = new Line[alignedNoteArray.Length];
            SolidColorBrush myBrush = new SolidColorBrush(Colors.Green);

            RotateTransform rotate = new RotateTransform(45);

            for (int ii = 0; ii < alignedNoteArray.Length; ii++)
            {
                //noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
                //System.Console.Out.Write("Note " + (ii + 1) + ": \nDuration: " + noteArray[ii].duration / waveIn.SampleRate + " seconds \nPitch: " + Enum.GetName(typeof(musicNote.notePitch), (noteArray[ii].pitch) % 12) + " / " + pitches[ii] + "\nError: " + noteArray[ii].error * 100 + "%\n");
                notes[ii]                 = new Ellipse();
                notes[ii].Tag             = alignedNoteArray[ii];
                notes[ii].Height          = 20;
                notes[ii].Width           = 15;
                notes[ii].Margin          = new Thickness(ii * 30, 0, 0, 0);
                notes[ii].LayoutTransform = rotate;
                notes[ii].MouseEnter     += DisplayStats;
                notes[ii].MouseLeave     += ClearStats;
                stems[ii]                 = new Line();
                stems[ii].StrokeThickness = 1;
                stems[ii].X1              = ii * 30 + 20;
                stems[ii].X2              = ii * 30 + 20;
                stems[ii].Y1              = 250 - 10 * alignedNoteArray[ii].staffPos;
                stems[ii].Y2              = 250 - 10 * alignedNoteArray[ii].staffPos - 40;
                notes[ii].Fill            = ErrorBrush;
                notes[ii].StrokeThickness = 1;
                stems[ii].Stroke          = ErrorBrush;


                Canvas.SetTop(notes[ii], (240 - 10 * alignedNoteArray[ii].staffPos));
                if (alignedNoteArray[ii].flat)
                {
                    System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
                    flat.Content    = "b";
                    flat.FontFamily = new FontFamily("Mistral");
                    flat.Margin     = new Thickness(ii * 30 + 15, 0, 0, 0);
                    Canvas.SetTop(flat, (240 - 10 * alignedNoteArray[ii].staffPos));
                    noteStaff.Children.Insert(ii, flat);
                }

                noteStaff.Children.Insert(ii, notes[ii]);
                noteStaff.Children.Insert(ii, stems[ii]);
            }

            Ellipse[]   sheetNotes;
            Rectangle[] timeRect;
            Line[]      sheetStems;
            sheetNotes = new Ellipse[alignedStaffArray.Length];
            sheetStems = new Line[alignedStaffArray.Length];
            timeRect   = new Rectangle[2 * alignedStaffArray.Length];

            Fline.Width     = alignedStaffArray.Length * 30;
            Dline.Width     = alignedStaffArray.Length * 30;
            Bline.Width     = alignedStaffArray.Length * 30;
            Gline.Width     = alignedStaffArray.Length * 30;
            Eline.Width     = alignedStaffArray.Length * 30;
            noteStaff.Width = alignedStaffArray.Length * 30;


            for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            {
                sheetNotes[ii]                 = new Ellipse();
                sheetNotes[ii].Tag             = alignedStaffArray[ii];
                sheetNotes[ii].Height          = 20;
                sheetNotes[ii].Width           = 15;
                sheetNotes[ii].Margin          = new Thickness(ii * 30, 0, 0, 0);
                sheetNotes[ii].LayoutTransform = rotate;
                sheetNotes[ii].MouseEnter     += DisplayStats;
                sheetNotes[ii].MouseLeave     += ClearStats;
                sheetStems[ii]                 = new Line();
                sheetStems[ii].StrokeThickness = 1;
                sheetStems[ii].X1              = ii * 30 + 20;
                sheetStems[ii].X2              = ii * 30 + 20;
                sheetStems[ii].Y1              = 250 - 10 * alignedStaffArray[ii].staffPos;
                sheetStems[ii].Y2              = 250 - 10 * alignedStaffArray[ii].staffPos - 40;

                sheetNotes[ii].Fill            = sheetBrush;
                sheetNotes[ii].StrokeThickness = 1;
                sheetStems[ii].Stroke          = sheetBrush;


                Canvas.SetTop(sheetNotes[ii], (240 - 10 * alignedStaffArray[ii].staffPos));
                if (alignedStaffArray[ii].flat)
                {
                    System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
                    flat.Content    = "b";
                    flat.FontFamily = new FontFamily("Mistral");
                    flat.Margin     = new Thickness(ii * 30 + 15, 0, 0, 0);
                    Canvas.SetTop(flat, (240 - 10 * alignedStaffArray[ii].staffPos));
                    noteStaff.Children.Insert(ii, flat);
                }
                noteStaff.Children.Insert(ii, sheetNotes[ii]);
                noteStaff.Children.Insert(ii, sheetStems[ii]);
            }

            // FOR TIMING ERROR RECTANGLES

            for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            {
                timeRect[ii]        = new Rectangle();
                timeRect[ii].Fill   = sheetBrush;
                timeRect[ii].Height = 10 * alignedStaffArray[ii].duration * 4 * bpm / (60 * waveIn.SampleRate);
                timeRect[ii].Width  = 15;
                timeRect[ii].Margin = new Thickness(ii * 30 + 5, 0, 0, 0);

                Canvas.SetTop(timeRect[ii], 200);

                noteStaff.Children.Insert(ii, timeRect[ii]);
            }

            for (int ii = alignedStaffArray.Length; ii < alignedStaffArray.Length + alignedNoteArray.Length; ii++)
            {
                timeRect[ii]        = new Rectangle();
                timeRect[ii].Fill   = ErrorBrush;
                timeRect[ii].Height = 10 * alignedNoteArray[ii - alignedStaffArray.Length].duration * 4 * bpm / (60 * waveIn.SampleRate);
                timeRect[ii].Width  = 10;
                timeRect[ii].Margin = new Thickness((ii - alignedStaffArray.Length) * 30 + 5, 0, 0, 0);

                Canvas.SetTop(timeRect[ii], 200);
                noteStaff.Children.Insert(ii, timeRect[ii]);
            }
        }
Example #13
0
            private Complex Phi(HestonProcess process, Complex a, double nu_0, double nu_t, double dt)
            {
                double theta = process.theta();
                double kappa = process.kappa();
                double sigma = process.sigma();

                double  sigma2 = sigma * sigma;
                Complex ga     = Complex.Sqrt(kappa * kappa - 2 * sigma2 * a * new Complex(0.0, 1.0));
                double  d      = 4 * theta * kappa / sigma2;

                double  nu    = 0.5 * d - 1;
                Complex z     = ga * Complex.Exp(-0.5 * ga * dt) / (1.0 - Complex.Exp(-ga * dt));
                Complex log_z = -0.5 * ga * dt + Complex.Log(ga / (1.0 - Complex.Exp(-ga * dt)));

                Complex alpha = 4.0 * ga * Complex.Exp(-0.5 * ga * dt) / (sigma2 * (1.0 - Complex.Exp(-ga * dt)));
                Complex beta  = 4.0 * kappa * Complex.Exp(-0.5 * kappa * dt) / (sigma2 * (1.0 - Complex.Exp(-kappa * dt)));

                return(ga * Complex.Exp(-0.5 * (ga - kappa) * dt) * (1 - Complex.Exp(-kappa * dt))
                       / (kappa * (1.0 - Complex.Exp(-ga * dt)))
                       * Complex.Exp((nu_0 + nu_t) / sigma2 * (
                                         kappa * (1.0 + Complex.Exp(-kappa * dt)) / (1.0 - Complex.Exp(-kappa * dt))
                                         - ga * (1.0 + Complex.Exp(-ga * dt)) / (1.0 - Complex.Exp(-ga * dt))))
                       * Complex.Exp(nu * log_z) / Complex.Pow(z, nu)
                       * ((nu_t > 1e-8)
                           ? Utils.modifiedBesselFunction_i(nu, Complex.Sqrt(nu_0 * nu_t) * alpha)
                          / Utils.modifiedBesselFunction_i(nu, Complex.Sqrt(nu_0 * nu_t) * beta)
                           : Complex.Pow(alpha / beta, nu)
                          ));
            }
Example #14
0
        // Attari Characteristic Function ==================================================================================================
        public Complex AttariCF(double phi, HParam param, double Tau, double Spot, double Rate, double Div, int Trap)
        {
            Complex S = new Complex(Spot, 0.0);              // Spot Price
            Complex T = new Complex(Tau, 0.0);               // Maturity in years
            Complex r = new Complex(Rate, 0.0);              // Interest rate
            Complex q = new Complex(Div, 0.0);               // Dividend yield
            Complex i = new Complex(0.0, 1.0);               // Imaginary unit
            Complex rho = new Complex(param.rho, 0.0);       // Heston parameter: correlation
            Complex kappa = new Complex(param.kappa, 0.0);   // Heston parameter: mean reversion speed
            Complex theta = new Complex(param.theta, 0.0);   // Heston parameter: mean reversion speed
            Complex lambda = new Complex(param.lambda, 0.0); // Heston parameter: price of volatility risk
            Complex sigma = new Complex(param.sigma, 0.0);   // Heston parameter: volatility of variance
            Complex v0 = new Complex(param.v0, 0.0);         // Heston parameter: initial variance
            Complex x = Complex.Log(S);
            Complex a = kappa * theta;
            Complex b, u, d, g, c, D, G, C = new Complex();

            u = -0.5;
            b = kappa + lambda;
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The Attari characteristic function.
            return(Complex.Exp(C + D * v0 + i * phi * x) * Complex.Exp(-i * phi * (x + r * T)));
        }
Example #15
0
 private Complex w(double x, int k)
 {
     return(Complex.Exp(new Complex(0, -2 * Math.PI * x / k)));
 }
Example #16
0
        // Fast Fourier Transform
        public double[,] HestonFFT(int N, double uplimit, double alpha, string rule, HParam param, OpSet settings)
        {
            double s0 = Math.Log(settings.S);
            double pi = Math.PI;

            // Specify the increments
            double eta       = uplimit / Convert.ToDouble(N);
            double lambdainc = 2 * pi / Convert.ToDouble(N) / eta;

            // Initialize and specify the weights
            double[] w = new double[N];
            if (rule == "Trapezoidal")
            {
                w[0]     = 0.5;
                w[N - 1] = 0.5;
                for (int j = 1; j <= N - 2; j++)
                {
                    w[j] = 1;
                }
            }
            else if (rule == "Simpsons")
            {
                w[0]     = 1.0 / 3.0;
                w[N - 1] = 1.0 / 3.0;
                for (int j = 1; j <= N - 1; j++)
                {
                    w[j] = (1.0 / 3.0) * (3 + Math.Pow(-1, j + 1));
                }
            }

            // Specify the b parameter
            double b = Convert.ToDouble(N) * lambdainc / 2.0;

            // Create the grid for the integration
            double[] v = new double[N];
            for (int j = 0; j <= N - 1; j++)
            {
                v[j] = eta * j;
            }

            // Create the grid for the log-strikes and strikes
            double[] k = new double[N];
            double[] K = new double[N];
            for (int j = 0; j <= N - 1; j++)
            {
                k[j] = -b + lambdainc * Convert.ToDouble(j) + s0;
                K[j] = Math.Exp(k[j]);
            }

            double tau = settings.T;
            double r   = settings.r;
            double q   = settings.q;

            // Implement the FFT
            HestonPrice HP = new HestonPrice();
            Complex     i  = new Complex(0.0, 1.0);

            Complex[] psi     = new Complex[N];
            Complex[] phi     = new Complex[N];
            Complex[] x       = new Complex[N];
            Complex[] e       = new Complex[N];
            double[]  CallFFT = new double[N];
            double[]  sume    = new double[N];
            for (int u = 0; u <= N - 1; u++)
            {
                for (int j = 0; j <= N - 1; j++)
                {
                    psi[j]   = HP.HestonCF(v[j] - (alpha + 1.0) * i, param, settings);
                    phi[j]   = Complex.Exp(-r * tau) * psi[j] / (alpha * alpha + alpha - v[j] * v[j] + i * v[j] * (2.0 * alpha + 1.0));
                    x[j]     = Complex.Exp(i * (b - s0) * v[j]) * phi[j] * w[j];
                    e[j]     = Complex.Exp(-i * 2 * pi / Convert.ToDouble(N) * j * u) * x[j];
                    sume[u] += e[j].Real;
                }
                CallFFT[u] = eta * Math.Exp(-alpha * k[u]) / pi * sume[u];
            }

            // Return the FFT call price and the strikes
            double[,] output = new double[N, 2];
            for (int j = 0; j <= N - 1; j++)
            {
                output[j, 0] = K[j];
                output[j, 1] = CallFFT[j];
            }
            return(output);
        }
Example #17
0
 public static Complex Sech(Complex value) => 2.0 / (Complex.Exp(value) + Complex.Exp(-value));
Example #18
0
        // Onset Detection function - Determines Start and Finish times of a note and the frequency of the note over each duration.

        public void onsetDetection()
        {
            float[] HFC;
            int     starts = 0;
            int     stops  = 0;

            Complex[]     Y;
            double[]      absY;
            List <int>    lengths;
            List <int>    noteStarts;
            List <int>    noteStops;
            List <double> pitches;

            int     ll;
            double  pi = 3.14159265;
            Complex i  = Complex.ImaginaryOne;

            noteStarts = new List <int>(100);
            noteStops  = new List <int>(100);
            lengths    = new List <int>(100);
            pitches    = new List <double>(100);

            SolidColorBrush sheetBrush = new SolidColorBrush(Colors.Black);
            SolidColorBrush ErrorBrush = new SolidColorBrush(Colors.Red);
            SolidColorBrush whiteBrush = new SolidColorBrush(Colors.White);

            HFC = new float[stftRep.timeFreqData[0].Length];

            //for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            //{
            //    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }
            //}
            for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            {
                for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
                {
                    HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
                }
            }
            //Parallel.For(0, stftRep.timeFreqData[0].Length, jj =>
            //{
            //    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }
            //});
            //Parallel.For(0, stftRep.wSamp / 2, ii =>
            //{
            //    for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }
            //});
            //for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            //{
            //    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }

            //}

            float maxi = HFC.Max();

            //Loop1
            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                HFC[jj] = (float)Math.Pow((HFC[jj] / maxi), 2);
            }

            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                if (starts > stops)
                {
                    if (HFC[jj] < 0.001)
                    {
                        noteStops.Add(jj * ((stftRep.wSamp - 1) / 2));
                        stops = stops + 1;
                    }
                }
                else if (starts - stops == 0)
                {
                    if (HFC[jj] > 0.001)
                    {
                        noteStarts.Add(jj * ((stftRep.wSamp - 1) / 2));
                        starts = starts + 1;
                    }
                }
            }

            if (starts > stops)
            {
                noteStops.Add(waveIn.data.Length);
            }


            // DETERMINES START AND FINISH TIME OF NOTES BASED ON ONSET DETECTION

            ///*

            for (int ii = 0; ii < noteStops.Count; ii++)
            {
                lengths.Add(noteStops[ii] - noteStarts[ii]);
            }

            //Can do around
            for (int mm = 0; mm < lengths.Count; mm++)
            {
                int nearest = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                twiddles = new Complex[nearest];
                compX    = new Complex[nearest];

                //Loop fusion, loo2
                Parallel.For(0, nearest, zz =>
                {
                    double a     = 2 * pi * zz / (double)nearest;
                    twiddles[zz] = Complex.Pow(Complex.Exp(-i), (float)a);

                    if (zz < lengths[mm] && (noteStarts[mm] + zz) < waveIn.wave.Length)
                    {
                        compX[zz] = waveIn.wave[noteStarts[mm] + zz];
                    }
                    else
                    {
                        compX[zz] = Complex.Zero;
                    }
                });
                //for (ll = 0; ll < nearest; ll++)
                //{
                //    double a = 2 * pi * ll / (double)nearest;
                //    twiddles[ll] = Complex.Pow(Complex.Exp(-i), (float)a);

                //    if (ll < lengths[mm] && (noteStarts[mm] + ll) < waveIn.wave.Length)
                //    {
                //        compX[ll] = waveIn.wave[noteStarts[mm] + ll];
                //    }
                //    else
                //    {
                //        compX[ll] = Complex.Zero;
                //    }
                //} //same as par for in timefreq, not worth


                //for (int kk = 0; kk < nearest; kk++)
                //{
                //    if (kk < lengths[mm] && (noteStarts[mm] + kk) < waveIn.wave.Length)
                //    {
                //        compX[kk] = waveIn.wave[noteStarts[mm] + kk];
                //    }
                //    else
                //    {
                //        compX[kk] = Complex.Zero;
                //    }
                //} //same as par for in timefreq, not worth

                Y = new Complex[nearest];

                Y = fft(compX, nearest); //same as par for in timefreq, not worth

                absY = new double[nearest];

                double maximum = 0;
                int    maxInd  = 0;

                //Loop distribution loop3
                Parallel.For(0, Y.Length, jj =>
                {
                    absY[jj] = Y[jj].Magnitude;
                });
                for (int jj = 0; jj < Y.Length; jj++)
                {
                    if (absY[jj] > maximum)
                    {
                        maximum = absY[jj];
                        maxInd  = jj;
                    }
                }
                //for (int jj = 0; jj < Y.Length; jj++)
                //{
                //    absY[jj] = Y[jj].Magnitude;
                //    if (absY[jj] > maximum)
                //    {
                //        maximum = absY[jj];
                //        maxInd = jj;
                //    }
                //} // requires a lock

                for (int div = 6; div > 1; div--)
                {
                    if (maxInd > nearest / 2)
                    {
                        if (absY[(int)Math.Floor((double)(nearest - maxInd) / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = (nearest - maxInd) / div;
                        }
                    }
                    else
                    {
                        if (absY[(int)Math.Floor((double)maxInd / div)] / absY[(maxInd)] > 0.10)
                        {
                            maxInd = maxInd / div;
                        }
                    }
                } // requires a lock / remove from array and test in its own array. Since it is a very small loop might be worth?

                if (maxInd > nearest / 2)
                {
                    pitches.Add((nearest - maxInd) * waveIn.SampleRate / nearest);
                } //converted to arr to maintain parallelism OR remove from parallel.For
                else
                {
                    pitches.Add(maxInd * waveIn.SampleRate / nearest);
                }
            }

            musicNote[] noteArray;
            noteArray = new musicNote[noteStarts.Count()];

            for (int ii = 0; ii < noteStarts.Count(); ii++)
            {
                noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            }

            int[] sheetPitchArray = new int[sheetmusic.Length];
            int[] notePitchArray  = new int[noteArray.Length];

            for (int ii = 0; ii < sheetmusic.Length; ii++)
            {
                sheetPitchArray[ii] = sheetmusic[ii].pitch % 12;
            }

            for (int jj = 0; jj < noteArray.Length; jj++)
            {
                notePitchArray[jj] = noteArray[jj].pitch % 12;
            }

            //string[] alignedStrings = new string[2];

            //alignedStrings = stringMatch(sheetPitchArray, notePitchArray);

            //musicNote[] alignedStaffArray = new musicNote[alignedStrings[0].Length / 2];
            //musicNote[] alignedNoteArray = new musicNote[alignedStrings[1].Length / 2];
            //int staffCount = 0;
            //int noteCount = 0;

            //for (int ii = 0; ii < alignedStrings[0].Length / 2; ii++)
            //{

            //    if (alignedStrings[0][2 * ii] == ' ')
            //    {
            //        alignedStaffArray[ii] = new musicNote(0, 0);
            //    }
            //    else
            //    {
            //        alignedStaffArray[ii] = sheetmusic[staffCount];
            //        staffCount++;
            //    }

            //    if (alignedStrings[1][2 * ii] == ' ')
            //    {
            //        alignedNoteArray[ii] = new musicNote(0, 0);
            //    }
            //    else
            //    {
            //        alignedNoteArray[ii] = noteArray[noteCount];
            //        noteCount++;
            //    }
            //}

            //// STAFF TAB DISPLAY

            //Ellipse[] notes;
            //Line[] stems;
            //notes = new Ellipse[alignedNoteArray.Length];
            //stems = new Line[alignedNoteArray.Length];
            //SolidColorBrush myBrush = new SolidColorBrush(Colors.Green);

            //RotateTransform rotate = new RotateTransform(45);

            //for (int ii = 0; ii < alignedNoteArray.Length; ii++)
            //{
            //    //noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            //    //System.Console.Out.Write("Note " + (ii + 1) + ": \nDuration: " + noteArray[ii].duration / waveIn.SampleRate + " seconds \nPitch: " + Enum.GetName(typeof(musicNote.notePitch), (noteArray[ii].pitch) % 12) + " / " + pitches[ii] + "\nError: " + noteArray[ii].error * 100 + "%\n");
            //    notes[ii] = new Ellipse();
            //    notes[ii].Tag = alignedNoteArray[ii];
            //    notes[ii].Height = 20;
            //    notes[ii].Width = 15;
            //    notes[ii].Margin = new Thickness(ii * 30, 0, 0, 0);
            //    notes[ii].LayoutTransform = rotate;
            //    notes[ii].MouseEnter += DisplayStats;
            //    notes[ii].MouseLeave += ClearStats;
            //    stems[ii] = new Line();
            //    stems[ii].StrokeThickness = 1;
            //    stems[ii].X1 = ii * 30 + 20;
            //    stems[ii].X2 = ii * 30 + 20;
            //    stems[ii].Y1 = 250 - 10 * alignedNoteArray[ii].staffPos;
            //    stems[ii].Y2 = 250 - 10 * alignedNoteArray[ii].staffPos - 40;
            //    notes[ii].Fill = ErrorBrush;
            //    notes[ii].StrokeThickness = 1;
            //    stems[ii].Stroke = ErrorBrush;


            //    Canvas.SetTop(notes[ii], (240 - 10 * alignedNoteArray[ii].staffPos));
            //    if (alignedNoteArray[ii].flat)
            //    {
            //        System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
            //        flat.Content = "b";
            //        flat.FontFamily = new FontFamily("Mistral");
            //        flat.Margin = new Thickness(ii * 30 + 15, 0, 0, 0);
            //        Canvas.SetTop(flat, (240 - 10 * alignedNoteArray[ii].staffPos));
            //        noteStaff.Children.Insert(ii, flat);
            //    }

            //    noteStaff.Children.Insert(ii, notes[ii]);
            //    noteStaff.Children.Insert(ii, stems[ii]);

            //}

            //Ellipse[] sheetNotes;
            //Rectangle[] timeRect;
            //Line[] sheetStems;
            //sheetNotes = new Ellipse[alignedStaffArray.Length];
            //sheetStems = new Line[alignedStaffArray.Length];
            //timeRect = new Rectangle[2 * alignedStaffArray.Length];

            //Fline.Width = alignedStaffArray.Length * 30;
            //Dline.Width = alignedStaffArray.Length * 30;
            //Bline.Width = alignedStaffArray.Length * 30;
            //Gline.Width = alignedStaffArray.Length * 30;
            //Eline.Width = alignedStaffArray.Length * 30;
            //noteStaff.Width = alignedStaffArray.Length * 30;


            //for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            //{

            //    sheetNotes[ii] = new Ellipse();
            //    sheetNotes[ii].Tag = alignedStaffArray[ii];
            //    sheetNotes[ii].Height = 20;
            //    sheetNotes[ii].Width = 15;
            //    sheetNotes[ii].Margin = new Thickness(ii * 30, 0, 0, 0);
            //    sheetNotes[ii].LayoutTransform = rotate;
            //    sheetNotes[ii].MouseEnter += DisplayStats;
            //    sheetNotes[ii].MouseLeave += ClearStats;
            //    sheetStems[ii] = new Line();
            //    sheetStems[ii].StrokeThickness = 1;
            //    sheetStems[ii].X1 = ii * 30 + 20;
            //    sheetStems[ii].X2 = ii * 30 + 20;
            //    sheetStems[ii].Y1 = 250 - 10 * alignedStaffArray[ii].staffPos;
            //    sheetStems[ii].Y2 = 250 - 10 * alignedStaffArray[ii].staffPos - 40;

            //    sheetNotes[ii].Fill = sheetBrush;
            //    sheetNotes[ii].StrokeThickness = 1;
            //    sheetStems[ii].Stroke = sheetBrush;


            //    Canvas.SetTop(sheetNotes[ii], (240 - 10 * alignedStaffArray[ii].staffPos));
            //    if (alignedStaffArray[ii].flat)
            //    {
            //        System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
            //        flat.Content = "b";
            //        flat.FontFamily = new FontFamily("Mistral");
            //        flat.Margin = new Thickness(ii * 30 + 15, 0, 0, 0);
            //        Canvas.SetTop(flat, (240 - 10 * alignedStaffArray[ii].staffPos));
            //        noteStaff.Children.Insert(ii, flat);
            //    }
            //    noteStaff.Children.Insert(ii, sheetNotes[ii]);
            //    noteStaff.Children.Insert(ii, sheetStems[ii]);
            //}

            //// FOR TIMING ERROR RECTANGLES

            //for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            //{

            //    timeRect[ii] = new Rectangle();
            //    timeRect[ii].Fill = sheetBrush;
            //    timeRect[ii].Height = 10 * alignedStaffArray[ii].duration * 4 * bpm / (60 * waveIn.SampleRate);
            //    timeRect[ii].Width = 15;
            //    timeRect[ii].Margin = new Thickness(ii * 30 + 5, 0, 0, 0);

            //    Canvas.SetTop(timeRect[ii], 200);

            //    noteStaff.Children.Insert(ii, timeRect[ii]);

            //}

            //for (int ii = alignedStaffArray.Length; ii < alignedStaffArray.Length + alignedNoteArray.Length; ii++)
            //{

            //    timeRect[ii] = new Rectangle();
            //    timeRect[ii].Fill = ErrorBrush;
            //    timeRect[ii].Height = 10 * alignedNoteArray[ii - alignedStaffArray.Length].duration * 4 * bpm / (60 * waveIn.SampleRate);
            //    timeRect[ii].Width = 10;
            //    timeRect[ii].Margin = new Thickness((ii - alignedStaffArray.Length) * 30 + 5, 0, 0, 0);

            //    Canvas.SetTop(timeRect[ii], 200);
            //    noteStaff.Children.Insert(ii, timeRect[ii]);
            //}
        }
Example #19
0
 public static Complex Csch(Complex value) => 2.0 / (Complex.Exp(value) - Complex.Exp(-value));
        public void LambertW_ComplexArgument_BenchmarkResult(double x, double y, int branch, double expectedReal, double expectedImaginary)
        {
            var specialFunctions = GetTestObject();
            var w = specialFunctions.LambertW(x + Complex.ImaginaryOne * y, branch);

            var actual = w;

            if (expectedReal == 0.0)  // do not check relative errors
            {
                Assert.That(actual.Real, Is.EqualTo(expectedReal).Within(1E-12), String.Format("x={0}; w ={1}; w * exp(w) = {2}", x, w, w * Complex.Exp(w)));
            }
            else
            {
                Assert.That(actual.Real, Is.EqualTo(expectedReal).Within(1E-12).Percent, String.Format("x={0}; w ={1}; w * exp(w) = {2}", x, w, w * Complex.Exp(w)));
            }

            if (expectedImaginary == 0.0)  // do not check relative errors
            {
                Assert.That(actual.Imaginary, Is.EqualTo(expectedImaginary).Within(1E-12), String.Format("x={0}; w ={1}; w * exp(w) = {2}", x, w, w * Complex.Exp(w)));
            }
            else
            {
                Assert.That(actual.Imaginary, Is.EqualTo(expectedImaginary).Within(1E-12).Percent, String.Format("x={0}; w ={1}; w * exp(w) = {2}", x, w, w * Complex.Exp(w)));
            }
        }
Example #21
0
 /// <summary>
 ///  Returns e raised to the power specified by a complex number.
 /// </summary>
 /// <param name="value">The number e raised to the power value.</param>
 public static Complex Exp(Complex value)
 {
     return(Complex.Exp(value));
 }
        public void LambertW_ComplexArgument_FunctionalEquation(
            [Values(1.0, 1.63, 2.831231313, -0.23441312, 7.9817231123, -0.1234567891011, 24.6152441235, 65.9823477234, 126.716265123, 1023.928242474247, -0.36787944117144)]
            double x,
            [Values(1.0, -0.52, 2.541, 5.126, -7.89)]
            double y,
            [Values(1, 2, 3, 5, 10, 0, -1, -2, -3, -5, -10)]
            int branch)
        {
            var specialFunctions = GetTestObject();

            var w = specialFunctions.LambertW(x + y * Complex.ImaginaryOne, branch);

            var actual   = w * Complex.Exp(w);
            var expected = x + y * Complex.ImaginaryOne;

            Assert.That(actual.Real, Is.EqualTo(expected.Real).Within(1E-10).Percent, String.Format("x={0}; w ={1}; w * exp(w) = {2} is not equal to x!", x, w, w * Complex.Exp(w)));
            Assert.That(actual.Imaginary, Is.EqualTo(expected.Imaginary).Within(1E-9).Percent, String.Format("x={0}; w ={1}; w * exp(w) = {2} is not equal to x!", x, w, w * Complex.Exp(w)));
        }
        /// <summary>
        /// Calculates the hyperbolic cosecant of the specified complex number.
        /// </summary>
        /// <param name="complex">A <see cref="Complex"/> instance.</param>
        /// <returns>Returns the hyperbolic cosecant of the specified complex number.</returns>
        public static Complex Csch(this Complex complex)
        {
            Complex exp = Complex.Exp(complex);

            return((2 * exp) / (Complex.Pow(exp, 2) - 1));
        }
        private void button1_Click(object sender, EventArgs e)  // Refresh
        {
            // Init Graphs
            double  intervals = 315; // "samples"
            double  mag       = 0;
            double  phase     = 0;
            double  w         = 0;
            double  scale     = 11;
            Complex i1        = new Complex(1, 0);
            Complex i2        = new Complex(0, 0);

            GlobalVar.refresh = 1;

            //Analog Plottage

            GAMag.Series[0].Points.Clear();
            GAPhase.Series[0].Points.Clear();

            // Analog Magnitude
            GAMag.ChartAreas[0].AxisX.Title = "Frequency (kHz)";
            GAMag.ChartAreas[0].AxisY.Title = "Magnitude (dB)";
            //GAMag.ChartAreas[0].AxisX.IsLogarithmic = true;
            GAMag.Series[0].LegendText        = "Magnitude";
            GAMag.Series[0].IsVisibleInLegend = false;

            // Analog Phase
            GAPhase.ChartAreas[0].AxisX.Title   = "Frequency (kHz)";
            GAPhase.ChartAreas[0].AxisY.Title   = "Phase";
            GAPhase.Series[0].IsVisibleInLegend = false;

            for (double n = 0; n < intervals; n = ++n)
            {
                w  = (2 * Math.PI * GlobalVar.samplef / intervals) * n;
                i2 = new Complex(0, w);  // i2 = 0 + jw
                // Mag = 20log(|Bandalog|)
                // Phase = Atan(Im(bandalog)/Re(bandalog)
                i1 = Bandalog(i2);                                                                 // s = jw

                mag = 20 * Math.Log10(Complex.Abs(i1));                                            // Log10!!!
                //Vector2 magpoints = [n / 2 * Math.PI, mag];
                GAMag.Series[0].Points.AddXY(Math.Round((n / (2 * Math.PI)) / scale, 2) + 1, mag); //Add x,y to chart
                //GAMag.ChartAreas[0].RecalculateAxesScale();

                phase = Math.Atan(i1.Imaginary / i1.Real);
                GAPhase.Series[0].Points.AddXY(Math.Round((n / (2 * Math.PI)) / scale, 2) + 1, phase); //Add x,y to chart
            }



            // Digital Plottage

            GDMag.Series[0].Points.Clear();
            GDPhase.Series[0].Points.Clear();

            // Init Graphs
            double  intervalz = 1000; // "samples"
            double  magz      = 0;
            double  phasez    = 0;
            Complex i3        = new Complex(1, 0);
            Complex i4        = new Complex(0, 0);

            // Digital Magnitude
            GDMag.ChartAreas[0].AxisX.Title   = "Frequency (kHz)";
            GDMag.ChartAreas[0].AxisY.Title   = "Magnitude (dB)";
            GDMag.Series[0].LegendText        = "Magnitude";
            GDMag.Series[0].IsVisibleInLegend = false; // Saves space

            // Digital Phase
            GDPhase.ChartAreas[0].AxisX.Title   = "Frequency (kHz)";
            GDPhase.ChartAreas[0].AxisY.Title   = "Phase";
            GDPhase.Series[0].IsVisibleInLegend = false; // Saves space

            Complex i5 = new Complex(0, 0);

            for (double j = 1; j < intervalz; ++j)  //  j = w from 0 -> pi
            {
                double dw = (Math.PI / (intervalz)) * j;
                i4 = new Complex(0, dw); // i4 = 0 + jw
                i5 = Complex.Exp(i4);    // i5 = e^jw = s
                // Mag = 20log(|Bandigital|)
                // Phase = Atan(Im(bandigital)/Re(bandigital)
                i3 = Bandigital(i5);

                magz = 20 * Math.Log10(Complex.Abs(i3));                                                                       // Log10!!!
                GDMag.Series[0].Points.Add(new DataPoint(Math.Round(GlobalVar.samplef * dw / (2 * Math.PI) / 1000, 3), magz)); // add x,y values

                phasez = Math.Atan(i3.Imaginary / i3.Real);
                GDPhase.Series[0].Points.Add(new DataPoint(Math.Round(GlobalVar.samplef * dw / (2 * Math.PI) / 1000, 3), phasez)); // add x,y values
            }


            // Realisations

            GIn1.Series[0].Points.Clear();
            GIn2.Series[0].Points.Clear();
            GOut1.Series[0].Points.Clear();
            GOut2.Series[0].Points.Clear();
            GFFT1.Series[0].Points.Clear();
            GFFT2.Series[0].Points.Clear();

            // Direct Realisation

            int    dintervals = 1000;
            double sineinputA = 0;

            //double[] inputA;
            //double[] outputA1;
            //double[] outputA2;
            double[] num = { 0.298534, 0.348534, 0.952554, 0.68258, 0.952554, 0.348534, 0.298534 };
            double[] den = { 1, 0.748427, 0.876976, 0.544886, 0.690464, 0.086335, -0.065264 };



            GIn1.ChartAreas[0].AxisX.Title   = "Time (s)";
            GIn1.ChartAreas[0].AxisY.Title   = "Amplitude";
            GIn1.Series[0].IsVisibleInLegend = false; // Saves space

            GOut1.ChartAreas[0].AxisX.Title   = "Time (s)";
            GOut1.ChartAreas[0].AxisY.Title   = "Amplitude";
            GOut1.Series[0].IsVisibleInLegend = false; // Saves space

            GIn2.ChartAreas[0].AxisX.Title   = "Time (s)";
            GIn2.ChartAreas[0].AxisY.Title   = "Amplitude";
            GIn2.Series[0].IsVisibleInLegend = false; // Saves space

            for (int oloop = 1; oloop < dintervals; oloop++)
            {
                GlobalVar.outputA1[oloop] = 0;
                sineinputA = findinputA(oloop);
                GlobalVar.inputA[oloop] = sineinputA;

                for (int iloop = 1; oloop - iloop > 1 && iloop <= 7; iloop++) //Realisation 1
                {
                    GlobalVar.outputA1[oloop] += num[iloop - 1] * GlobalVar.inputA[oloop - iloop] - den[iloop - 1] * GlobalVar.inputA[oloop];
                }

                GlobalVar.compinputA1[oloop]  = new Complex(GlobalVar.inputA[oloop], 0);
                GlobalVar.compoutputA1[oloop] = new Complex(GlobalVar.outputA1[oloop], 0);

                GIn1.Series[0].Points.Add(new DataPoint(oloop, GlobalVar.inputA[oloop]));
                GOut1.Series[0].Points.Add(new DataPoint(oloop, GlobalVar.outputA1[oloop]));
                GIn2.Series[0].Points.Add(new DataPoint(oloop, GlobalVar.inputA[oloop]));
                GOut2.Series[0].Points.Add(new DataPoint(oloop, GlobalVar.outputA1[oloop]));
            }

            GFFT1.Series[0].Points.Clear();

            Fourier.Forward(GlobalVar.compinputA1);
            for (int q = 0; q < dintervals; q++)
            {
                GFFT1.ChartAreas[0].AxisX.Title   = "Frequency (Hz)";
                GFFT1.ChartAreas[0].AxisY.Title   = "Amplitude";
                GFFT1.Series[0].IsVisibleInLegend = false; // Saves space
                GFFT1.ChartAreas[0].AxisY.Minimum = 0;
                GFFT1.ChartAreas[0].AxisX.Minimum = 0;
                GFFT1.ChartAreas[0].AxisX.Maximum = 5500;

                GFFT2.ChartAreas[0].AxisX.Title   = "Frequency (Hz)";
                GFFT2.ChartAreas[0].AxisY.Title   = "Amplitude";
                GFFT2.Series[0].IsVisibleInLegend = false; // Saves space
                GFFT2.ChartAreas[0].AxisY.Minimum = 0;
                GFFT2.ChartAreas[0].AxisX.Minimum = 0;
                GFFT2.ChartAreas[0].AxisX.Maximum = 5500;

                if (20 * Math.Log10(GlobalVar.compoutputA1[q].Magnitude) > 0)
                {
                    GFFT1.Series[0].Points.Add(new DataPoint(GlobalVar.samplef / dintervals * q, 20 * Math.Log10(GlobalVar.compinputA1[q].Magnitude)));
                    GFFT2.Series[0].Points.Add(new DataPoint(GlobalVar.samplef / dintervals * q, 20 * Math.Log10(GlobalVar.compinputA1[q].Magnitude)));
                }
                else
                {
                    GFFT1.Series[0].Points.Add(new DataPoint(GlobalVar.samplef / dintervals * q, 0));
                    GFFT2.Series[0].Points.Add(new DataPoint(GlobalVar.samplef / dintervals * q, 0));
                }
            }

            // Cascade Realisation


            GOut2.ChartAreas[0].AxisX.Title   = "Time (s)";
            GOut2.ChartAreas[0].AxisY.Title   = "Amplitude";
            GOut2.Series[0].IsVisibleInLegend = false; // Saves space

            double[] cnum1 = { -0.133277, 1 };
            double[] cden1 = { 0.184704, -0.0944 };
            double[] cnum2 = { 0.407766, 1 };
            double[] cden2 = { 1.217628, 0.848231 };
            double[] cnum3 = { 0.893, 1 };
            double[] cden3 = { -0.653845, 0.815172 };
            double   nmult = 2.629;
            double   temp  = 0;
            double   temp1 = 0;
            double   temp2 = 0;
            double   temp3 = 0;

            for (int jloop = 1; jloop < dintervals; jloop++)
            {
                GlobalVar.outputA1[jloop] = 0;
                sineinputA = findinputA(jloop);
                GlobalVar.inputA[jloop] = sineinputA;
                temp = 0;

                for (int kloop = 2; jloop - kloop > 1 && kloop >= 0; kloop--)
                {
                    //temp1 += cnum1[kloop] * GlobalVar.inputA[jloop - kloop] - cden1[kloop] * GlobalVar.inputA[jloop];
                }

                temp = temp1;

                for (int lloop = 2; jloop - lloop > 1 && lloop >= 0; lloop--)
                {
                    //temp3 += cnum2[lloop] * GlobalVar.inputA[jloop] - cden2[jloop-lloop] * GlobalVar.inputA[jloop-1];
                }

                temp += temp2;

                for (int mloop = 2; jloop - mloop > 1 && mloop >= 0; mloop--)
                {
                    //temp3 += cnum3[mloop] * GlobalVar.inputA[jloop] - cden3[jloop - mloop] * GlobalVar.inputA[jloop-1];
                    GlobalVar.outputA2[jloop] += 0 * temp3;
                    temp = temp3;
                }

                temp += temp3;

                GlobalVar.outputA2[jloop] += nmult * temp;
                GOut1.Series[0].Points.Add(new DataPoint(jloop, GlobalVar.outputA2[jloop]));
            }
        }
        // Heston Characteristic Function (f2) for the Greeks
        public Complex HestonCFGreek(Complex phi, double kappa, double theta, double lambda, double rho, double sigma, double T,
                                     double K, double S, double r, double q, double v0, int Trap, string Greek)
        {
            Complex i = new Complex(0.0, 1.0);       // Imaginary unit
            Complex b, u, d, g, c, D, G, C = new Complex();
            double  x = Math.Log(S);
            double  a = kappa * theta;

            u = -0.5;
            b = kappa + lambda;
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            Complex f = Complex.Exp(C + D * v0 + i * phi * x);

            // Return the integrand of choice
            if (Greek == "Price")
            {
                return(f);
            }
            else if (Greek == "Delta")
            {
                return(f * i * phi / S);
            }
            else if (Greek == "Gamma")
            {
                return(i * phi * f * (i * phi - 1.0) / S / S);
            }
            else if (Greek == "Theta")
            {
                Complex dDdT = d * Complex.Exp(d * T) * (b - rho * sigma * phi * i + d) * (g - 1.0) / sigma / sigma / Complex.Pow(1.0 - g * Complex.Exp(d * T), 2.0);
                Complex dCdT = r * phi * i + kappa * theta / sigma / sigma * ((b - rho * sigma * phi * i + d) + 2.0 * g * d * Complex.Exp(d * T) / (1.0 - g * Complex.Exp(d * T)));
                return(r * f - f * (dCdT + dDdT * v0));
            }
            else if (Greek == "Rho")
            {
                Complex dCdr = i * phi * T;
                return(f * dCdr - T * f);
            }
            else if (Greek == "Vega1")
            {
                return(f * D);
            }
            else if (Greek == "Vanna")
            {
                return(f * i * phi * D / S);
            }
            else if (Greek == "Volga")
            {
                return(2.0 * D * f * (2.0 * D * v0 + 1.0));
            }
            else
            {
                return(0.0);
            }
        }
Example #26
0
 public static Gate Phase(int n) =>
 new Gate(1, 0, 0, Complex.Exp((Complex.ImaginaryOne * 2 * Math.PI) / Math.Pow(2, n)));
        // Onset Detection function - Determines Start and Finish times of a note and the frequency of the note over each duration.

        private void onsetDetection()
        {
            float[] HFC;
            int     starts = 0;
            int     stops  = 0;

            List <int> lengths;
            List <int> noteStarts;
            List <int> noteStops;

            double  pi = 3.14159265;
            Complex i  = Complex.ImaginaryOne;

            double[] pitches = new double[100];

            noteStarts = new List <int>(100);
            noteStops  = new List <int>(100);
            lengths    = new List <int>(100);

            SolidColorBrush sheetBrush = new SolidColorBrush(Colors.Black);
            SolidColorBrush ErrorBrush = new SolidColorBrush(Colors.Red);
            SolidColorBrush whiteBrush = new SolidColorBrush(Colors.White);

            HFC = new float[stftRep.timeFreqData[0].Length];


            ////////////////////////////////////////////////////////////////////////
            ///                       Parallel Section                           ///
            ////////////////////////////////////////////////////////////////////////

            // Original and Chunked are slower

            //for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            //{
            //    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }
            //}

            int N = stftRep.timeFreqData[0].Length;

            Parallel.For(0, NUM_THREADS_USED, iterator =>
            {
                int chunk_size = (N + (NUM_THREADS_USED - 1)) / NUM_THREADS_USED;
                int start      = chunk_size * iterator;
                int end        = Math.Min(start + chunk_size, N);

                for (int jj = start; jj < end; jj++)
                {
                    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
                    {
                        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
                    }
                }
            });

            //Parallel.For(0, stftRep.timeFreqData[0].Length, jj =>
            //{
            //    for (int ii = 0; ii < stftRep.wSamp / 2; ii++)
            //    {
            //        HFC[jj] = HFC[jj] + (float)Math.Pow((double)stftRep.timeFreqData[ii][jj] * ii, 2);
            //    }
            //});

            ////////////////////////////// ~ END ~ /////////////////////////////////

            float maxi = HFC.Max();

            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                HFC[jj] = (float)Math.Pow((HFC[jj] / maxi), 2);
            }

            for (int jj = 0; jj < stftRep.timeFreqData[0].Length; jj++)
            {
                if (starts > stops)
                {
                    if (HFC[jj] < 0.001)
                    {
                        noteStops.Add(jj * ((stftRep.wSamp - 1) / 2));
                        stops = stops + 1;
                    }
                }
                else if (starts - stops == 0)
                {
                    if (HFC[jj] > 0.001)
                    {
                        noteStarts.Add(jj * ((stftRep.wSamp - 1) / 2));
                        starts = starts + 1;
                    }
                }
            }

            if (starts > stops)
            {
                noteStops.Add(waveIn.data.Length);
            }

            for (int ii = 0; ii < noteStops.Count; ii++)
            {
                lengths.Add(noteStops[ii] - noteStarts[ii]);
            }

            ////////////////////////////////////////////////////////////////////////
            ///                       Parallel Section                           ///
            ////////////////////////////////////////////////////////////////////////

            //Seq in other folder. Due to restructuring

            Parallel.For(0, NUM_THREADS_USED, iterator =>
            {
                int guardSize = lengths.Count;
                int chunkSize = (guardSize + (NUM_THREADS_USED - 1)) / NUM_THREADS_USED;
                int start     = chunkSize * iterator;
                int end       = Math.Min(start + chunkSize, guardSize);

                for (int mm = start; mm < end; mm++)
                {
                    Complex[] twiddles;
                    Complex[] compX;
                    Complex[] Y;
                    double[] absY;

                    int nearest = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
                    twiddles    = new Complex[nearest];

                    for (int ll = 0; ll < nearest; ll++)
                    {
                        double a     = 2 * pi * ll / (double)nearest;
                        twiddles[ll] = Complex.Pow(Complex.Exp(-i), (float)a);
                    }

                    compX = new Complex[nearest];
                    for (int kk = 0; kk < nearest; kk++)
                    {
                        if (kk < lengths[mm] && (noteStarts[mm] + kk) < waveIn.wave.Length)
                        {
                            compX[kk] = waveIn.wave[noteStarts[mm] + kk];
                        }
                        else
                        {
                            compX[kk] = Complex.Zero;
                        }
                    }

                    Y = new Complex[nearest];

                    Y = fft(compX, nearest, twiddles);

                    double maximum = 0;
                    int maxInd     = 0;

                    absY = new double[nearest];

                    for (int jj = 0; jj < Y.Length; jj++)
                    {
                        absY[jj] = Y[jj].Magnitude;
                        if (absY[jj] > maximum)
                        {
                            maximum = absY[jj];
                            maxInd  = jj;
                        }
                    }

                    for (int div = 6; div > 1; div--)
                    {
                        if (maxInd > nearest / 2)
                        {
                            if (absY[(int)Math.Floor((double)(nearest - maxInd) / div)] / absY[(maxInd)] > 0.10)
                            {
                                maxInd = (nearest - maxInd) / div;
                            }
                        }
                        else
                        {
                            if (absY[(int)Math.Floor((double)maxInd / div)] / absY[(maxInd)] > 0.10)
                            {
                                maxInd = maxInd / div;
                            }
                        }
                    }

                    if (maxInd > nearest / 2)
                    {
                        pitches[mm] = (nearest - maxInd) * waveIn.SampleRate / nearest;
                    }
                    else
                    {
                        pitches[mm] = maxInd * waveIn.SampleRate / nearest;
                    }
                }
            });

            //Parallel.For(0, lengths.Count, mm =>
            //{
            //    Complex[] twiddles;
            //    Complex[] compX;
            //    Complex[] Y;
            //    double[] absY;

            //    int nearest = (int)Math.Pow(2, Math.Ceiling(Math.Log(lengths[mm], 2)));
            //    twiddles = new Complex[nearest];

            //    for (int ll = 0; ll < nearest; ll++)
            //    {
            //        double a = 2 * pi * ll / (double)nearest;
            //        twiddles[ll] = Complex.Pow(Complex.Exp(-i), (float)a);
            //    }

            //    compX = new Complex[nearest];
            //    for (int kk = 0; kk < nearest; kk++)
            //    {
            //        if (kk < lengths[mm] && (noteStarts[mm] + kk) < waveIn.wave.Length)
            //        {
            //            compX[kk] = waveIn.wave[noteStarts[mm] + kk];
            //        }
            //        else
            //        {
            //            compX[kk] = Complex.Zero;
            //        }
            //    }

            //    Y = new Complex[nearest];

            //    Y = fft(compX, nearest, twiddles);

            //    double maximum = 0;
            //    int maxInd = 0;

            //    absY = new double[nearest];

            //    for (int jj = 0; jj < Y.Length; jj++)
            //    {
            //        absY[jj] = Y[jj].Magnitude;
            //        if (absY[jj] > maximum)
            //        {
            //            maximum = absY[jj];
            //            maxInd = jj;
            //        }
            //    }

            //    for (int div = 6; div > 1; div--)
            //    {

            //        if (maxInd > nearest / 2)
            //        {
            //            if (absY[(int)Math.Floor((double)(nearest - maxInd) / div)] / absY[(maxInd)] > 0.10)
            //            {
            //                maxInd = (nearest - maxInd) / div;
            //            }
            //        }
            //        else
            //        {
            //            if (absY[(int)Math.Floor((double)maxInd / div)] / absY[(maxInd)] > 0.10)
            //            {
            //                maxInd = maxInd / div;
            //            }
            //        }
            //    }

            //    if (maxInd > nearest / 2)
            //    {
            //        pitches[mm] = (nearest - maxInd) * waveIn.SampleRate / nearest;
            //    }
            //    else
            //    {
            //        pitches[mm] = maxInd * waveIn.SampleRate / nearest;
            //    }
            //});

            ////////////////////////////// ~ END ~ /////////////////////////////////

            musicNote[] noteArray;
            noteArray = new musicNote[noteStarts.Count()];

            for (int ii = 0; ii < noteStarts.Count(); ii++)
            {
                noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            }

            int[] sheetPitchArray = new int[sheetmusic.Length];
            int[] notePitchArray  = new int[noteArray.Length];

            for (int ii = 0; ii < sheetmusic.Length; ii++)
            {
                sheetPitchArray[ii] = sheetmusic[ii].pitch % 12;
            }

            for (int jj = 0; jj < noteArray.Length; jj++)
            {
                notePitchArray[jj] = noteArray[jj].pitch % 12;
            }

            string[] alignedStrings = new string[2];

            alignedStrings = stringMatch(sheetPitchArray, notePitchArray);

            musicNote[] alignedStaffArray = new musicNote[alignedStrings[0].Length / 2];
            musicNote[] alignedNoteArray  = new musicNote[alignedStrings[1].Length / 2];
            int         staffCount        = 0;
            int         noteCount         = 0;

            for (int ii = 0; ii < alignedStrings[0].Length / 2; ii++)
            {
                if (alignedStrings[0][2 * ii] == ' ')
                {
                    alignedStaffArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedStaffArray[ii] = sheetmusic[staffCount];
                    staffCount++;
                }

                if (alignedStrings[1][2 * ii] == ' ')
                {
                    alignedNoteArray[ii] = new musicNote(0, 0);
                }
                else
                {
                    alignedNoteArray[ii] = noteArray[noteCount];
                    noteCount++;
                }
            }

            // STAFF TAB DISPLAY -- Commented out to make timing consistant.

            //Ellipse[] notes;
            //Line[] stems;
            //notes = new Ellipse[alignedNoteArray.Length];
            //stems = new Line[alignedNoteArray.Length];
            //SolidColorBrush myBrush = new SolidColorBrush(Colors.Green);

            //RotateTransform rotate = new RotateTransform(45);

            //for (int ii = 0; ii < alignedNoteArray.Length; ii++)
            //{
            //    //noteArray[ii] = new musicNote(pitches[ii], lengths[ii]);
            //    //System.Console.Out.Write("Note " + (ii + 1) + ": \nDuration: " + noteArray[ii].duration / waveIn.SampleRate + " seconds \nPitch: " + Enum.GetName(typeof(musicNote.notePitch), (noteArray[ii].pitch) % 12) + " / " + pitches[ii] + "\nError: " + noteArray[ii].error * 100 + "%\n");
            //    notes[ii] = new Ellipse();
            //    notes[ii].Tag = alignedNoteArray[ii];
            //    notes[ii].Height = 20;
            //    notes[ii].Width = 15;
            //    notes[ii].Margin = new Thickness(ii * 30, 0, 0, 0);
            //    notes[ii].LayoutTransform = rotate;
            //    notes[ii].MouseEnter += DisplayStats;
            //    notes[ii].MouseLeave += ClearStats;
            //    stems[ii] = new Line();
            //    stems[ii].StrokeThickness = 1;
            //    stems[ii].X1 = ii * 30 + 20;
            //    stems[ii].X2 = ii * 30 + 20;
            //    stems[ii].Y1 = 250 - 10 * alignedNoteArray[ii].staffPos;
            //    stems[ii].Y2 = 250 - 10 * alignedNoteArray[ii].staffPos - 40;
            //    notes[ii].Fill = ErrorBrush;
            //    notes[ii].StrokeThickness = 1;
            //    stems[ii].Stroke = ErrorBrush;


            //    Canvas.SetTop(notes[ii], (240 - 10 * alignedNoteArray[ii].staffPos));
            //    if (alignedNoteArray[ii].flat)
            //    {
            //        System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
            //        flat.Content = "b";
            //        flat.FontFamily = new FontFamily("Mistral");
            //        flat.Margin = new Thickness(ii * 30 + 15, 0, 0, 0);
            //        Canvas.SetTop(flat, (240 - 10 * alignedNoteArray[ii].staffPos));
            //        noteStaff.Children.Insert(ii, flat);
            //    }

            //    noteStaff.Children.Insert(ii, notes[ii]);
            //    noteStaff.Children.Insert(ii, stems[ii]);

            //}

            //Ellipse[] sheetNotes;
            //Rectangle[] timeRect;
            //Line[] sheetStems;
            //sheetNotes = new Ellipse[alignedStaffArray.Length];
            //sheetStems = new Line[alignedStaffArray.Length];
            //timeRect = new Rectangle[2 * alignedStaffArray.Length];

            //Fline.Width = alignedStaffArray.Length * 30;
            //Dline.Width = alignedStaffArray.Length * 30;
            //Bline.Width = alignedStaffArray.Length * 30;
            //Gline.Width = alignedStaffArray.Length * 30;
            //Eline.Width = alignedStaffArray.Length * 30;
            //noteStaff.Width = alignedStaffArray.Length * 30;


            //for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            //{

            //    sheetNotes[ii] = new Ellipse();
            //    sheetNotes[ii].Tag = alignedStaffArray[ii];
            //    sheetNotes[ii].Height = 20;
            //    sheetNotes[ii].Width = 15;
            //    sheetNotes[ii].Margin = new Thickness(ii * 30, 0, 0, 0);
            //    sheetNotes[ii].LayoutTransform = rotate;
            //    sheetNotes[ii].MouseEnter += DisplayStats;
            //    sheetNotes[ii].MouseLeave += ClearStats;
            //    sheetStems[ii] = new Line();
            //    sheetStems[ii].StrokeThickness = 1;
            //    sheetStems[ii].X1 = ii * 30 + 20;
            //    sheetStems[ii].X2 = ii * 30 + 20;
            //    sheetStems[ii].Y1 = 250 - 10 * alignedStaffArray[ii].staffPos;
            //    sheetStems[ii].Y2 = 250 - 10 * alignedStaffArray[ii].staffPos - 40;

            //    sheetNotes[ii].Fill = sheetBrush;
            //    sheetNotes[ii].StrokeThickness = 1;
            //    sheetStems[ii].Stroke = sheetBrush;


            //    Canvas.SetTop(sheetNotes[ii], (240 - 10 * alignedStaffArray[ii].staffPos));
            //    if (alignedStaffArray[ii].flat)
            //    {
            //        System.Windows.Controls.Label flat = new System.Windows.Controls.Label();
            //        flat.Content = "b";
            //        flat.FontFamily = new FontFamily("Mistral");
            //        flat.Margin = new Thickness(ii * 30 + 15, 0, 0, 0);
            //        Canvas.SetTop(flat, (240 - 10 * alignedStaffArray[ii].staffPos));
            //        noteStaff.Children.Insert(ii, flat);
            //    }
            //    noteStaff.Children.Insert(ii, sheetNotes[ii]);
            //    noteStaff.Children.Insert(ii, sheetStems[ii]);
            //}

            //// FOR TIMING ERROR RECTANGLES

            //for (int ii = 0; ii < alignedStaffArray.Length; ii++)
            //{

            //    timeRect[ii] = new Rectangle();
            //    timeRect[ii].Fill = sheetBrush;
            //    timeRect[ii].Height = 10 * alignedStaffArray[ii].duration * 4 * bpm / (60 * waveIn.SampleRate);
            //    timeRect[ii].Width = 15;
            //    timeRect[ii].Margin = new Thickness(ii * 30 + 5, 0, 0, 0);

            //    Canvas.SetTop(timeRect[ii], 200);

            //    noteStaff.Children.Insert(ii, timeRect[ii]);

            //}

            //for (int ii = alignedStaffArray.Length; ii < alignedStaffArray.Length + alignedNoteArray.Length; ii++)
            //{

            //    timeRect[ii] = new Rectangle();
            //    timeRect[ii].Fill = ErrorBrush;
            //    timeRect[ii].Height = 10 * alignedNoteArray[ii - alignedStaffArray.Length].duration * 4 * bpm / (60 * waveIn.SampleRate);
            //    timeRect[ii].Width = 10;
            //    timeRect[ii].Margin = new Thickness((ii - alignedStaffArray.Length) * 30 + 5, 0, 0, 0);

            //    Canvas.SetTop(timeRect[ii], 200);
            //    noteStaff.Children.Insert(ii, timeRect[ii]);
            //}
        }
Example #28
0
        public void testWeightedModifiedBesselFunctions()
        {
            // Testing weighted modified Bessel functions
            double nu = -5.0;

            while (nu <= 5.0)
            {
                double x = 0.1;
                while (x <= 15.0)
                {
                    double vi = Utils.modifiedBesselFunction_i_exponentiallyWeighted(nu, x);
                    double wi = Utils.modifiedBesselFunction_i(nu, x) * Math.Exp(-x);
                    double vk = Utils.modifiedBesselFunction_k_exponentiallyWeighted(nu, x);
                    double wk = Const.M_PI_2 * (Utils.modifiedBesselFunction_i(-nu, x) * Math.Exp(-x) -
                                                Utils.modifiedBesselFunction_i(nu, x) * Math.Exp(-x)) / Math.Sin(Const.M_PI * nu);
                    if (Math.Abs((vi - wi) / (Math.Max(Math.Exp(x), 1.0) * vi)) > 1E3 * Const.QL_EPSILON)
                    {
                        QAssert.Fail("failed to verify exponentially weighted"
                                     + "modified Bessel function of first kind"
                                     + "\n order      : " + nu + "\n argument   : "
                                     + x + "\n calcuated  : " + vi
                                     + "\n expecetd   : " + wi);
                    }

                    if (Math.Abs((vk - wk) / (Math.Max(Math.Exp(x), 1.0) * vk)) > 1E3 * Const.QL_EPSILON)
                    {
                        QAssert.Fail("failed to verify exponentially weighted"
                                     + "modified Bessel function of second kind"
                                     + "\n order      : " + nu + "\n argument   : "
                                     + x + "\n calcuated  : " + vk
                                     + "\n expecetd   : " + wk);
                    }
                    x += 0.5;
                }
                nu += 0.5;
            }
            nu = -5.0;
            while (nu <= 5.0)
            {
                double x = -5.0;
                while (x <= 5.0)
                {
                    double y = -5.0;
                    while (y <= 5.0)
                    {
                        Complex z  = new Complex(x, y);
                        Complex vi = Utils.modifiedBesselFunction_i_exponentiallyWeighted(nu, z);
                        Complex wi = Utils.modifiedBesselFunction_i(nu, z) * Complex.Exp(-z);
                        Complex vk = Utils.modifiedBesselFunction_k_exponentiallyWeighted(nu, z);
                        Complex wk = Const.M_PI_2 * (Utils.modifiedBesselFunction_i(-nu, z) * Complex.Exp(-z) -
                                                     Utils.modifiedBesselFunction_i(nu, z) * Complex.Exp(-z)) /
                                     Math.Sin(Const.M_PI * nu);
                        if (Complex.Abs((vi - wi) / vi) > 1E3 * Const.QL_EPSILON)
                        {
                            QAssert.Fail("failed to verify exponentially weighted"
                                         + "modified Bessel function of first kind"
                                         + "\n order      : " + nu
                                         + "\n argument   : " + z +
                                         "\n calcuated: "
                                         + vi + "\n expecetd   : " + wi);
                        }
                        if (Complex.Abs((vk - wk) / vk) > 1E3 * Const.QL_EPSILON)
                        {
                            QAssert.Fail("failed to verify exponentially weighted"
                                         + "modified Bessel function of second kind"
                                         + "\n order      : " + nu
                                         + "\n argument   : " + z +
                                         "\n calcuated: "
                                         + vk + "\n expecetd   : " + wk);
                        }
                        y += 0.5;
                    }
                    x += 0.5;
                }
                nu += 0.5;
            }
        }
        // Integrands for Heston Greeks
        public double HestonGreeksProb(double phi, HParam param, OpSet settings, int Pnum, string Greek)
        {
            Complex i = new Complex(0.0, 1.0);                 // Imaginary unit
            Complex S = new Complex(settings.S, 0.0);          // Spot Price
            Complex K = new Complex(settings.K, 0.0);          // Strike Price
            Complex T = new Complex(settings.T, 0.0);          // Maturity in years
            Complex r = new Complex(settings.r, 0.0);          // Interest rate
            Complex q = new Complex(settings.q, 0.0);          // Dividend yield
            Complex rho = new Complex(param.rho, 0.0);         // Heston parameter: correlation
            Complex kappa = new Complex(param.kappa, 0.0);     // Heston parameter: mean reversion speed
            Complex theta = new Complex(param.theta, 0.0);     // Heston parameter: mean reversion speed
            Complex lambda = new Complex(param.lambda, 0.0);   // Heston parameter: price of volatility risk
            Complex sigma = new Complex(param.sigma, 0.0);     // Heston parameter: volatility of variance
            Complex v0 = new Complex(param.v0, 0.0);           // Heston parameter: initial variance
            Complex x = Complex.Log(S);
            Complex a = kappa * theta;
            int     Trap = settings.trap;
            Complex b, u, d, g, c, D, G, C, f = new Complex();

            // Parameters "u" and "b" are different for P1 and P2
            if (Pnum == 1)
            {
                u = 0.5;
                b = kappa + lambda - rho * sigma;
            }
            else
            {
                u = -0.5;
                b = kappa + lambda;
            }
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (Trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            f = Complex.Exp(C + D * v0 + i * phi * x);

            // Calculate the integrands for the various Greeks
            Complex y  = new Complex(0.0, 0.0);
            Complex dD = new Complex(0.0, 0.0);
            Complex dC = new Complex(0.0, 0.0);
            Complex df = new Complex(0.0, 0.0);

            if ((Greek == "Delta") | (Greek == "Rho"))
            {
                y = Complex.Exp(-i * phi * Complex.Log(K)) * f / i / phi;
            }
            else if (Greek == "Gamma")
            {
                // der(P1^2)/der(S^2)
                y = Complex.Exp(-i * phi * Complex.Log(K)) * f;
            }
            else if (Greek == "Theta")
            {
                // dP/dtau
                dD = d * Complex.Exp(d * T) * (b - rho * sigma * phi * i + d) * (g - 1.0) / sigma / sigma / Complex.Pow(1.0 - g * Complex.Exp(d * T), 2);
                dC = (r - q) * phi * i + kappa * theta / sigma / sigma * ((b - rho * sigma * phi * i + d) + 2.0 * g * d * Complex.Exp(d * T) / (1.0 - g * Complex.Exp(d * T)));
                df = f * (dC + dD * v0);
                y  = Complex.Exp(-i * phi * Complex.Log(K)) * df / i / phi;
            }
            else if (Greek == "Vega1")
            {
                // dP/dv0
                y = Complex.Exp(-i * phi * Complex.Log(K)) * f * D / i / phi;
            }
            else if (Greek == "Vega2")
            {
                if (Trap == 1)
                {
                    dC = (r - q) * i * phi * T + kappa / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
                }
                else if (Trap == 0)
                {
                    dC = (r - q) * i * phi * T + kappa / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                }
                df = f * dC;
                y  = Complex.Exp(-i * phi * Complex.Log(K)) * df / i / phi;
            }
            else if (Greek == "Volga")
            {
                // dP2/dv02
                y = Complex.Exp(-i * phi * Complex.Log(K)) * f * D * D / i / phi;
            }
            return(y.Real);
        }
Example #30
0
 public void CanComputeExponential(double real, double imag, double expectedReal, double expectedImag)
 {
     var value = new Complex(real, imag);
     var expected = new Complex(expectedReal, expectedImag);
     AssertHelpers.AlmostEqualRelative(expected, value.Exp(), 15);
 }
Example #31
0
        // Heston characteristic function (f2) ==============================================================================
        public Complex HestonCF(Complex phi, HParam param, double S, double r, double q, double T, int trap)
        {
            Complex i = new Complex(0.0, 1.0);                   // Imaginary unit
            double  kappa = param.kappa;
            double  theta = param.theta;
            double  sigma = param.sigma;
            double  v0 = param.v0;
            double  rho = param.rho;
            double  lambda = param.lambda;
            double  x = Math.Log(S);
            double  a = kappa * theta;
            Complex b, u, d, g, c, D, G, C = new Complex();

            u = -0.5;
            b = kappa + lambda;
            d = Complex.Sqrt(Complex.Pow(rho * sigma * i * phi - b, 2) - sigma * sigma * (2.0 * u * i * phi - phi * phi));
            g = (b - rho * sigma * i * phi + d) / (b - rho * sigma * i * phi - d);
            if (trap == 1)
            {
                // "Little Heston Trap" formulation
                c = 1.0 / g;
                D = (b - rho * sigma * i * phi - d) / sigma / sigma * ((1.0 - Complex.Exp(-d * T)) / (1.0 - c * Complex.Exp(-d * T)));
                G = (1.0 - c * Complex.Exp(-d * T)) / (1 - c);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi - d) * T - 2.0 * Complex.Log(G));
            }
            else
            {
                // Original Heston formulation.
                G = (1.0 - g * Complex.Exp(d * T)) / (1.0 - g);
                C = (r - q) * i * phi * T + a / sigma / sigma * ((b - rho * sigma * i * phi + d) * T - 2.0 * Complex.Log(G));
                D = (b - rho * sigma * i * phi + d) / sigma / sigma * ((1.0 - Complex.Exp(d * T)) / (1.0 - g * Complex.Exp(d * T)));
            }

            // The characteristic function.
            return(Complex.Exp(C + D * v0 + i * phi * x));
        }