【WPF学习手记】C#实现高斯拟合的模拟退火算法

算法功能:实现高斯拟合,可根据需要修改。

  • 源码
public static double PeakPicker(double[] xfit, double[] yfit)
        {
            // 定义子函数 *************************
            // 数组拷贝
            void ArrCopy(double[] data, double[] DataCopy)
            {
                for (int i = 0; i < data.Length; i++)
                {
                    DataCopy[i] = data[i];
                }
            }

            // 最大值
            double ArrMax(double[] x)
            {
                double result = x[0];
                for (int i = 1; i < x.Length; i++)
                {
                    if (result < x[i])
                    {
                        result = x[i];
                    }
                }
                return result;
            }

            /// 最小值
            double ArrMin(double[] x)
            {
                double result = x[0];
                for (int i = 1; i < x.Length; i++)
                {
                    if (result > x[i])
                    {
                        result = x[i];
                    }
                }
                return result;
            }

            // 高斯拟合目标函数
            double Obj_Gaussian(double[] p, double[] x, double[] y)
            {
                double result = 0;
                for (int i = 0; i < x.Length; i++)
                {
                    result = result + Math.Pow(y[i] - p[0] * Math.Exp(-Math.Pow(x[i] - p[1], 2) / Math.Pow(p[2], 2)), 2);
                }
                return Math.Sqrt(result / y.Length);
            }

            // 条件判断
            bool IsTrue(double[] x, double[] x_min, double[] x_max)
            {
                bool result = false;
                bool Judge1 = (x[0] > x_min[0]) && (x[0] < x_max[0]);
                bool Judge2 = (x[1] > x_min[1]) && (x[1] < x_max[1]);
                bool Judge3 = (x[2] > x_min[2]) && (x[2] < x_max[2]);
                if (Judge1 && Judge2 && Judge3)
                {
                    result = true;
                }
                return result;
            }

            // 产生 0~1 之间的随机数
            double random()
            {
                var seed = Guid.NewGuid().GetHashCode();  // 这个种子很重要,不然随机数是重复的
                Random r = new Random(seed);
                int i = r.Next(0, 100000);
                return (double)i / 100000;
            }

            // 程序主体 ************************
            // 常量值
            double T0 = 1000;
            double Alpha = 0.99;
            double IteMax = 3000;

            // 变量初始化
            double[] MassComps = new double[3];
            double[] MassCompsNew = new double[3];
            double[] MassLB = new double[3];
            double[] MassUB = new double[3];
            double[] dMass = new double[3];
            MassLB[0] = ArrMin(yfit);
            MassLB[1] = ArrMin(xfit);
            MassLB[2] = 0;
            MassUB[0] = ArrMax(yfit);
            MassUB[1] = ArrMax(xfit);
            MassUB[2] = 5;

            // 初始模型
            for (int j = 0; j < 3; j++)
            {
                MassComps[j] = random() * (MassUB[j] - MassLB[j]) + MassLB[j];
            }
            // 计算目标函数
            double Fun = Obj_Gaussian(MassComps, xfit, yfit);
            // 迭代
            for (int i = 0; i < IteMax; i++)
            {
                double Tk = T0 * Math.Pow(Alpha, i);
                // 预更新
                double[] rand = new double[3];
                for (int j = 0; j < 3; j++)
                {
                    rand[j] = random();
                    dMass[j] = Tk * Math.Sign(random() - 0.5) * (Math.Pow(1 + 1.0 / Tk , Math.Abs(2 * random() - 1)) - 1);
                    MassCompsNew[j] = MassComps[j] + dMass[j] * (MassUB[j] - MassLB[j]);
                }
                // 判断
                if (IsTrue(MassCompsNew, MassLB, MassUB))
                {
                    double NewFun = Obj_Gaussian(MassCompsNew, xfit, yfit);
                    if (NewFun <= Fun)
                    {
                        ArrCopy(MassCompsNew, MassComps);
                        Fun = NewFun;
                    }
                    else
                    {
                        if (Math.Exp( - (NewFun - Fun) / Tk) > random())
                        {
                            ArrCopy(MassCompsNew, MassComps);
                            Fun = NewFun;
                        }
                    }
                }
            }
            // 程序计算完成
            return MassComps[0];
        }
  • 测试代码
            double[] x = new double[1000];
            double[] y = new double[1000];
            double[] xfit = new double[201];
            double[] yfit = new double[201];
            double c = 5;
            double sigm = 3;
            for (int i = 0; i < 1000; i++)
            {
                x[i] = 0.01 * i;
                y[i] = Math.Exp(- (x[i] - c) * (x[i] - c) / (sigm * sigm));
                y[i] = y[i] + 0.1 * (random() - 0.5) * y[i];
            }
            for (int i = 0; i < 201; i++)
            {
                xfit[i] = x[400 + i];
                yfit[i] = y[400 + i];
            }
            double result = UnitPeakW.PeakPicker(xfit, yfit);
            MessageBox.Show(result.ToString());

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值