Пример #1
0
 public static void FitPeakThread(PointD[] pt, bool BackgroundFitting, double RemoveBadSN, ref PeakFunction p)
 {
     PeakFunction[] param = new PeakFunction[1];
     param[0] = p;
     FitMultiPeaksThread(pt, BackgroundFitting, RemoveBadSN, ref param);
     p = param[0];
 }
Пример #2
0
        //1ImageModeのときのコンストラクタ
        public PlaneParameters(string StrHKL, double millimeterObs1, double millimeterCalc1, bool IsThisChecked)
        {
            strHKL = StrHKL;
            //millimeterObs = new double[2];
            //millimeterCalc = new double[2];

            pvp = new PeakFunction();
        }
Пример #3
0
        //2ImageModeのときのコンストラクタ
        public PlaneParameters(string StrHKL, double millimeterObs1, double millimeterObs2, double millimeterCalc1, double millimeterCalc2, bool IsThisChecked, double D)
        {
            strHKL = StrHKL;
            //millimeterObs = new double[2];
            //millimeterCalc = new double[2];
            //pvp=new PeakFunction[2];
            pvp   = new PeakFunction();
            pvp.X = double.NaN;
            //pvp = new PeakFunction();
            //pvp[1].X = double.NaN;

            d = D;
        }
Пример #4
0
        public PeakFunction Copy()
        {
            PeakFunction p = new PeakFunction();

            p.Option    = this.Option;
            p.intensity = this.intensity;
            p.eta       = this.eta;
            p.etaH      = this.etaH;
            p.etaL      = this.etaL;
            p.Rl        = this.Rl;
            p.Rh        = this.Rh;
            p.X         = this.X;
            p.Hk        = this.Hk;
            p.Int       = this.Int;
            p.A         = this.A;//非対称パラメータ
            p.B1        = this.B1;
            p.B2        = this.B2;
            p.B3        = this.B3;
            p.m         = this.m;
            p.range     = this.range;
            return(p);
        }
Пример #5
0
        /// <summary>
        /// 複数ピークをフィッティングする. 戻り値は、R値
        /// </summary>
        /// <param name="pt">フィッティング対象プロファイルのデータ配列</param>
        /// <param name="BackgroundFitting">バックグラウンドをフィッティングするかどうか</param>
        /// <param name="RemoveBadSN">SN比の悪いピークについてはNaNを返すかどうか</param>
        /// <param name="p">ピーク関数 格納されている中心値、半値幅、フィッティングRangeを設定しておく</param>
        public static double FitMultiPeaksThread(PointD[] pt, bool BackgroundFitting, double RemoveBadSN, ref PeakFunction[] p)
        {
            //マルカールの方法でPseudoVoigtをとく。高速になるはず

            if (p.Length == 0)
            {
                return(double.PositiveInfinity);
            }
            if (pt == null || pt.Length < 3)
            {
                return(double.PositiveInfinity);
            }

            //まずここからプロファイルをとる領域や強度ななどの情報を集める
            List <double> PtX     = new List <double>();
            List <double> PtY     = new List <double>();
            double        sum     = 0;
            double        temp    = double.NegativeInfinity;
            double        tempMin = double.PositiveInfinity;

            //指定された範囲内のプロファイルをPtX,PtYに格納
            for (int i = 0; i < pt.Length; i++)
            {
                if (pt[i].X >= Math.Min(p[0].X - p[0].range, p[p.Length - 1].X - p[p.Length - 1].range) && pt[i].X <= Math.Max(p[0].X + p[0].range, p[p.Length - 1].X + p[p.Length - 1].range))
                {
                    PtX.Add(pt[i].X);
                    PtY.Add(pt[i].Y / 1000);
                    sum += pt[i].Y / 1000;
                    if (temp < pt[i].Y / 1000)
                    {
                        temp = pt[i].Y / 1000;
                    }
                }
            }

            //p[i].SerchPeakTop
            for (int i = 0; i < p.Length; i++)
            {
                if (p[i].SerchPeakTop)
                {
                    double max   = double.NegativeInfinity;
                    double tempX = 0;
                    for (int j = 0; j < PtX.Count; j++)
                    {
                        if (PtX[j] >= p[i].X - p[i].range && PtX[j] <= p[0].X + p[0].range)
                        {
                            if (max < PtY[j])
                            {
                                max   = PtY[j];
                                tempX = PtX[j];
                            }
                        }
                    }
                    p[i].X = tempX;
                }
            }

            //最も小さい強度を探す
            for (int i = 0; i < pt.Length; i++)
            {
                if (pt[i].X >= Math.Min(p[0].X - p[0].range, p[p.Length - 1].X - p[p.Length - 1].range) && pt[i].X <= Math.Max(p[0].X + p[0].range, p[p.Length - 1].X + p[p.Length - 1].range))
                {
                    if (tempMin > pt[i].Y / 1000)
                    {
                        tempMin = pt[i].Y / 1000;
                    }
                }
            }

            if (PtY.Count < 3 || /*temp <= 0 ||*/ (PtY[PtY.Count - 1] == 0 && PtY[PtY.Count - 2] == 0 && PtY[PtY.Count - 3] == 0))
            {
                for (int i = 0; i < p.Length; i++)
                {
                    p[i].X   = double.NaN;
                    p[i].Int = double.NaN;
                }
                return(double.PositiveInfinity);
            }

            double[] x      = PtX.ToArray();
            double[] y      = PtY.ToArray();
            int      length = x.Length;
            //ここまででプロファイルの領域などを決定

            //ここから決めなければいけないパラメータの数を設定する
            int ParamNum = 0;

            for (int i = 0; i < p.Length; i++)
            {
                ParamNum += p[i].GetParamNumber();
            }
            if (ParamNum < 0)
            {
                for (int i = 0; i < p.Length; i++)
                {
                    p[i].X   = double.NaN;
                    p[i].Int = double.NaN;
                }
                return(double.PositiveInfinity);
            }

            double[,] diff = new double[ParamNum + 2, length];
            var Alpha = new DenseMatrix(ParamNum + 2, ParamNum + 2);
            var Beta  = new DenseMatrix(ParamNum + 2, 1);

            PeakFunction[] pCurrent = new PeakFunction[p.Length];
            PeakFunction[] pNew     = new PeakFunction[p.Length];
            for (int i = 0; i < p.Length; i++)
            {
                pCurrent[i] = new PeakFunction();
                pNew[i]     = new PeakFunction();
                pCurrent[i] = p[i].Copy();
            }
            //ここまで

            //Intの値を大雑把に決める
            double[] peakIntensity = new double[p.Length];
            for (int i = 0; i < p.Length; i++)
            {
                double d = double.PositiveInfinity;
                for (int j = 0; j < PtX.Count; j++)
                {
                    if (d > Math.Abs(x[j] - p[i].X))
                    {
                        d = Math.Abs(x[j] - p[i].X);
                        peakIntensity[i] = y[j];
                    }
                }
                peakIntensity[i] -= tempMin;
            }
            //相対値として再配分する
            peakIntensity = Statistics.Normarize(peakIntensity);

            double[] ResidualCurrent = new double[length];
            double[] ResidualNew     = new double[length];
            double   ResidualSquareCurrent;
            double   ResidualSquareNew = 0;
            double   residual;
            double   centerX = (x[0] + x[x.Length - 1]) / 2;
            double   B1, B2, B1_New, B2_New;

            B1 = B2 = 0;

            double bestResidual = double.PositiveInfinity;
            int    bestInitial  = 0;
            int    startInitial = 0;
            int    endInitial   = 1;// 2;
            int    counter      = 0;

            for (int Initial = startInitial; Initial < endInitial; Initial++)
            {
                double[] c = new double[3];
                switch (Initial)
                {
                case 00: c = new double[] { 1, 1, 1 }; break;

                case 01: c = new double[] { 1, 1, 2 }; break;

                case 02: c = new double[] { 1, 1, 0.5 }; break;

                case 03: c = new double[] { 0.5, 1, 1 }; break;

                case 04: c = new double[] { 0.5, 1, 2 }; break;

                case 05: c = new double[] { 0.5, 1, 0.5 }; break;

                case 06: c = new double[] { 2, 1, 1 }; break;

                case 07: c = new double[] { 2, 1, 0.5 }; break;

                case 08: c = new double[] { 2, 1, 2 }; break;

                case 09: c = new double[] { 1, 2, 1 }; break;

                case 10: c = new double[] { 1, 0.5, 1 }; break;

                case 11: c = new double[] { 0.5, 2, 2 }; break;
                }
                //ここから初期値をきめる
                //Xはすでに代入済み
                //Int以外のの初期値を大雑把に決める
                for (int i = 0; i < p.Length; i++)
                {
                    pCurrent[i].X = p[i].X;

                    if (p[i].Hk > 0)
                    {
                        pCurrent[i].Hk = p[i].Hk * c[0];
                    }
                    else
                    {
                        pCurrent[i].Hk = p[i].range * 0.5 * c[0];
                    }

                    pCurrent[i].eta  = 0.5 * c[1];
                    pCurrent[i].etaH = 0.5 * c[1];
                    pCurrent[i].etaL = 0.5 * c[1];
                    pCurrent[i].m    = 2 * c[1];
                    pCurrent[i].Rl   = 2 * c[1];
                    pCurrent[i].Rh   = 2 * c[1];
                    pCurrent[i].A    = 0;
                }
                B1 = tempMin;
                B2 = 0;
                //Int
                for (int i = 0; i < p.Length; i++)
                {
                    pCurrent[i].Int = 1;
                    pCurrent[i].Int = (sum - tempMin * x.Length) * (x[1] - x[0]) * peakIntensity[i] / pCurrent[i].GetIntegral() * c[2];
                }
                //ここまで初期値決め

                //現在の残差を計算
                ResidualSquareCurrent = 0;
                double[] IntCurrent = new double[x.Length];
                double[] IntNew     = new double[x.Length];
                for (int i = 0; i < length; i++)
                {
                    IntCurrent[i] = B1 + B2 * (x[i] - centerX);
                }
                for (int j = 0; j < p.Length; j++)
                {
                    pCurrent[j].RenewParameter();
                    for (int i = 0; i < length; i++)
                    {
                        IntCurrent[i] += pCurrent[j].GetValue(x[i], false);
                    }
                }
                for (int i = 0; i < length; i++)
                {
                    ResidualCurrent[i]     = y[i] - IntCurrent[i];
                    ResidualSquareCurrent += ResidualCurrent[i] * ResidualCurrent[i];
                }

                double ramda = 100;
                counter = 0;
                do
                {
                    counter++;
                    //偏微分を作る
                    int n = 0;
                    int m = 0;
                    for (int j = 0; j < p.Length; j++)
                    {
                        n = m;
                        pCurrent[j].RenewParameter();
                        for (int i = 0; i < length; i++)
                        {
                            m = n;
                            double[] d = pCurrent[j].GetDifferentialValue(x[i], false);
                            for (int k = 0; k < d.Length; k++)
                            {
                                diff[m, i] = d[k];
                                m++;
                            }
                        }
                    }
                    for (int i = 0; i < length; i++)
                    {//バックグラウンド変数の偏微分
                        diff[ParamNum, i]     = 1;
                        diff[ParamNum + 1, i] = x[i] - centerX;
                    }
                    //偏微分を作る ここまで

                    //行列Alpha, Betaを作る
                    for (int i = 0; i < ParamNum + 2; i++)
                    {
                        for (int j = i; j < ParamNum + 2; j++)
                        {
                            Alpha[i, j] = 0;
                            for (int k = 0; k < length; k++)
                            {
                                Alpha[i, j] += diff[i, k] * diff[j, k];
                            }
                            Alpha[j, i] = Alpha[i, j];
                            if (i == j)
                            {
                                Alpha[i, j] *= (1 + ramda);
                            }
                        }
                        Beta[i, 0] = 0;
                        for (int k = 0; k < length; k++)
                        {
                            Beta[i, 0] += ResidualCurrent[k] * diff[i, k];
                        }
                    }
                    //行列Alpha、Beta、ここまで

                    var alphaInv = Alpha.TryInverse();

                    if (alphaInv == null)
                    {
                        for (int i = 0; i < p.Length; i++)
                        {
                            p[i].X   = double.NaN;
                            p[i].Int = double.NaN;
                        }
                        return(double.PositiveInfinity);
                    }

                    var delta = alphaInv * Beta;

                    //新しいパラメータをセットして適宜修正
                    n = 0;
                    bool flag = true;
                    for (int j = 0; j < p.Length; j++)
                    {
                        pNew[j] = pCurrent[j].Copy();
                        if (p[j].Option == PeakFunctionForm.PseudoVoigt)//PseudoVoigt:      Int, Eta, Hk, X ;
                        {
                            pNew[j].Int = pCurrent[j].Int + delta[n++, 0];
                            pNew[j].eta = pCurrent[j].eta + delta[n++, 0];
                            pNew[j].Hk  = pCurrent[j].Hk + delta[n++, 0];
                            pNew[j].X   = pCurrent[j].X + delta[n++, 0];

                            //if (pNew[j].eta < 0 || pNew[j].eta > 1)
                            //    flag = false;
                            if (pNew[j].eta < 0)
                            {
                                pNew[j].eta = 0;
                            }
                            if (pNew[j].eta > 1)
                            {
                                pNew[j].eta = 1;
                            }
                        }
                        else if (p[j].Option == PeakFunctionForm.Peason)//PearsonVII:       Int, Hk,  m,  X
                        {
                            pNew[j].Int = pCurrent[j].Int + delta[n++, 0];
                            pNew[j].Hk  = pCurrent[j].Hk + delta[n++, 0];
                            pNew[j].m   = pCurrent[j].m + delta[n++, 0];
                            pNew[j].X   = pCurrent[j].X + delta[n++, 0];

                            if (pNew[j].m <= 0.5 || pNew[j].m >= 10)
                            {
                                flag = false;
                            }
                        }
                        else if (p[j].Option == PeakFunctionForm.SplitPseudoVoigt)//SplitPseudoVoigt:  Int, Hk,  A,  etaL , etaH, X
                        {
                            pNew[j].Int  = pCurrent[j].Int + delta[n++, 0];
                            pNew[j].Hk   = pCurrent[j].Hk + delta[n++, 0];
                            pNew[j].A    = pCurrent[j].A + delta[n++, 0];
                            pNew[j].etaL = pCurrent[j].etaL + delta[n++, 0];
                            pNew[j].etaH = pCurrent[j].etaH + delta[n++, 0];
                            pNew[j].X    = pCurrent[j].X + delta[n++, 0];
                            if (pNew[j].etaL < 0 || pNew[j].etaL > 1)
                            {
                                flag = false;
                            }
                            if (pNew[j].etaH < 0 || pNew[j].etaH > 1)
                            {
                                flag = false;
                            }
                            if (pNew[j].A < -2 || pNew[j].A > 2)
                            {
                                flag = false;
                            }
                        }
                        else if (p[j].Option == PeakFunctionForm.SplitPearson)//SplitPearsonVII:  Int, Hk,  A,  Rl , Rh, X
                        {
                            pNew[j].Int = pCurrent[j].Int + delta[n++, 0];
                            pNew[j].Hk  = pCurrent[j].Hk + delta[n++, 0];
                            pNew[j].A   = pCurrent[j].A + delta[n++, 0];
                            pNew[j].Rl  = pCurrent[j].Rl + delta[n++, 0];
                            pNew[j].Rh  = pCurrent[j].Rh + delta[n++, 0];
                            pNew[j].X   = pCurrent[j].X + delta[n++, 0];
                            if (pNew[j].Rl <= 0.5 || pNew[j].Rl >= 10)
                            {
                                flag = false;
                            }
                            if (pNew[j].Rh <= 0.5 || pNew[j].Rh >= 10)
                            {
                                flag = false;
                            }
                            if (pNew[j].A < -2 || pNew[j].A > 2)
                            {
                                flag = false;
                            }
                        }

                        if (pNew[j].Hk < 0)
                        {
                            flag = false; //pNew[j].Hk = pCurrent[j].Hk;
                        }
                        //2本以上のフィッティングの場合、XがRangeの1/8以上動いたらもどす
                        if (p.Length > 1)
                        {
                            if (pNew[j].X - p[j].X > p[j].range / 8 || pNew[j].X - p[j].X < -p[j].range / 8)
                            {
                                pNew[j].X = pCurrent[j].X;
                            }
                        }
                        //    flag = false; //pNew[j].X = p[j].X + p[j].range / 4;
                    }
                    B1_New = B1 + delta[ParamNum, 0];
                    B2_New = B2 + delta[ParamNum + 1, 0];
                    //if (B1_New + B2_New * (x[0] - centerX) < 0 || B1_New + B2_New * (x[x.Length - 1] - centerX) < 0)
                    //    flag = false; //B1_New = B1;//B2_New = B2;

                    //あたらしいパラメータでの残差を計算
                    if (flag)
                    {
                        ResidualSquareNew = 0;
                        for (int i = 0; i < length; i++)
                        {
                            IntNew[i] = B1_New + B2_New * (x[i] - centerX);
                        }
                        for (int j = 0; j < p.Length; j++)
                        {
                            pNew[j].RenewParameter();
                            for (int i = 0; i < length; i++)
                            {
                                IntNew[i] += pNew[j].GetValue(x[i], false);
                            }
                        }
                        for (int i = 0; i < length; i++)
                        {
                            ResidualNew[i]     = y[i] - IntNew[i];
                            ResidualSquareNew += ResidualNew[i] * ResidualNew[i];
                        }
                    }
                    //残差計算ここまで

                    //新旧の値を比較
                    if (flag && ResidualSquareCurrent >= ResidualSquareNew)
                    {
                        ramda *= 0.8;
                        for (int i = 0; i < length; i++)
                        {
                            ResidualCurrent[i] = ResidualNew[i];
                        }
                        for (int j = 0; j < p.Length; j++)
                        {
                            pCurrent[j] = pNew[j].Copy();
                        }
                        B1 = B1_New;
                        B2 = B2_New;
                        if (counter > 50 && (ResidualSquareCurrent - ResidualSquareNew) / ResidualSquareCurrent < 0.0000000001)
                        {
                            break;
                        }
                        ResidualSquareCurrent = ResidualSquareNew;
                    }
                    else
                    {
                        ramda *= 2;
                    }
                } while (ramda < 100000000000 && counter < 1000);

                for (int i = 0; i < length; i++)
                {
                    IntNew[i] = B1_New + B2_New * (x[i] - centerX);
                }
                for (int j = 0; j < p.Length; j++)
                {
                    pNew[j].RenewParameter();
                    for (int i = 0; i < length; i++)
                    {
                        IntNew[i] += pNew[j].GetValue(x[i], false);
                    }
                }
                residual = 0;
                for (int i = 0; i < length; i++)
                {
                    residual += (IntNew[i] - y[i]) / IntNew[i] * (IntNew[i] - y[i]) / IntNew[i];
                }
                residual /= length;
                if (bestResidual > residual)//最も結果のよかったカウントを格納
                {
                    bestResidual = residual;
                    bestInitial  = Initial;
                }
                if (Math.Sqrt(residual) < 0.25)//平均2乗残差が5%以下だったら終了
                {
                    break;
                }
                if (Initial == endInitial - 1 && endInitial - startInitial > 2)//5%以下のものが見つからなかったとき
                {
                    //50%を超えるくらいひどかったら
                    if (Math.Sqrt(bestResidual) > 0.90)
                    {
                        for (int i = 0; i < p.Length; i++)
                        {
                            p[i].X   = double.NaN;
                            p[i].Int = double.NaN;
                        }
                        return(double.PositiveInfinity);
                    }
                    //一番ましな初期値でやり直す
                    startInitial = bestInitial - 1;
                    Initial      = bestInitial - 1;
                    endInitial   = bestInitial + 1;
                }
            }

            //行列アルファを決める
            //行列Alpha, Betaを作る
            for (int i = 0; i < ParamNum + 2; i++)
            {
                for (int j = i; j < ParamNum + 2; j++)
                {
                    Alpha[i, j] = 0;
                    for (int k = 0; k < length; k++)
                    {
                        Alpha[i, j] += diff[i, k] * diff[j, k];
                    }
                    Alpha[j, i] = Alpha[i, j];
                }
            }
            counter = 0;
            //最後にそれぞれもとまった数値を入れる。
            for (int i = 0; i < p.Length; i++)
            {
                //p[i] = pCurrent[i].Copy();
                p[i].Option    = pCurrent[i].Option;
                p[i].intensity = pCurrent[i].intensity;
                p[i].eta       = pCurrent[i].eta;
                p[i].etaH      = pCurrent[i].etaH;
                p[i].etaL      = pCurrent[i].etaL;
                p[i].Rl        = pCurrent[i].Rl;
                p[i].Rh        = pCurrent[i].Rh;
                p[i].X         = pCurrent[i].X;
                p[i].Hk        = pCurrent[i].Hk;
                p[i].Int       = pCurrent[i].Int;
                p[i].A         = pCurrent[i].A;
                p[i].B1        = pCurrent[i].B1;
                p[i].B2        = pCurrent[i].B2;
                p[i].B3        = pCurrent[i].B3;
                counter       += p[i].GetParamNumber();
                p[i].Xerr      = 1 / Math.Sqrt(Alpha[counter - 1, counter - 1]);
                p[i].m         = pCurrent[i].m;
                p[i].range     = pCurrent[i].range;
                p[i].Residual  = bestResidual;
                p[i].Int      *= 1000;
                p[i].B1        = B1 + B2 * (pCurrent[i].X - centerX);
                p[i].B2        = B2;
                p[i].B1       *= 1000;
                p[i].B2       *= 1000;
            }

            //これより下は主にIPAからだけ呼ばれる部分
            if (RemoveBadSN > 0)
            {
                //S/N比が悪いデータは除去する
                double BackGround = 0;
                double Signal     = 0;
                p[0].RenewParameter();
                for (int i = 0; i < length; i++)
                {
                    Signal     += p[0].GetValue(x[i], false);
                    BackGround += p[0].B1 + p[0].B2 * (p[0].X - x[i]);
                }
                if (double.IsNaN(Signal / (BackGround + Signal)) || double.IsInfinity(Signal / (BackGround + Signal)) || (Signal / (BackGround + Signal)) < RemoveBadSN)
                {
                    p[0].X = double.NaN;
                }

                //中心位置が外れて過ぎても失格
                if (p[0].X < x[0] || x[x.Length - 1] < p[0].X)
                {
                    p[0].X = double.NaN;
                }
            }

            /*if (counter < 1000)
             *  return true;
             * else
             *  return false;*/
            return(bestResidual);
        }