public static SphericalHarmonicIonoModel Load(string path)
        {
            if (!File.Exists(path))
            {
                throw new FileNotFoundException(path);
            }

            SphericalHarmonicIonoModel spm = new SphericalHarmonicIonoModel();

            var lines = File.ReadAllLines(path);

            string[] segs = lines[0].Replace('\n', ' ').Split(' ');
            int      degree, order;

            if (segs.Length >= 2 &&
                int.TryParse(segs[0], out degree) &&
                int.TryParse(segs[1], out order))
            {
                spm.Degree = degree;
                spm.Order  = order;
            }
            else
            {
                return(null);
            }

            spm.Anm = new List <double[]>(spm.Degree * 2);
            spm.Bnm = new List <double[]>(spm.Degree * 2);

            for (int i = 0; i <= spm.Degree; i++)
            {
                double[] anm = new double[i + 1];
                double[] bnm = new double[i + 1];
                for (int j = 0; j < anm.Length; j++)
                {
                    anm[j] = 0d;
                    bnm[j] = 0d;
                }
                spm.Anm.Add(anm);
                spm.Bnm.Add(bnm);
            }

            for (int i = 1; i < lines.Count(); i++)
            {
                segs = lines[i].Split();
                if (segs.Length >= 4)
                {
                    degree = int.Parse(segs[0]);
                    order  = int.Parse(segs[1]);
                    spm.Anm[degree][order] = double.Parse(segs[2]);
                    spm.Bnm[degree][order] = double.Parse(segs[3]);
                }
            }

            return(spm);
        }
        /// <summary>
        /// 最小二乘拟合球谐函数模型(单站,不估DCB)
        /// </summary>
        /// <param name="degree">阶</param>
        /// <param name="order">次</param>
        /// <param name="lat">纬度(弧度)</param>
        /// <param name="lon">经度(弧度)</param>
        /// <param name="vtec">VTEC(TECU)</param>
        /// <returns></returns>
        public static SphericalHarmonicIonoModel CalculateModel(int degree, int order,
                                                                List <double> lat, List <double> lon, List <double> vtec)
        {
            if (degree != order)
            {
                throw new Exception("球谐函数阶数!=次数,暂时无法计算");
            }
            if (lat is null || lon is null || vtec is null)
            {
                return(null);
            }

            //// 检测观测值个数是否满足要求
            int minCount = System.Math.Min(System.Math.Min(lat.Count, lon.Count), vtec.Count);
            int paraNum  = (degree + 1) * (degree + 1);

            if (minCount == 0)
            {
                return(null);
            }
            if (minCount < paraNum)
            {
                throw new Exception("球谐函数,观测值个数无法满足建模要求");
            }

            //// 设计矩阵
            Matrix <double> B = new DenseMatrix(minCount, (int)paraNum);
            Vector <double> L = new DenseVector(minCount);

            for (int i = 0; i < minCount; i++)
            {
                int col = 0;
                for (int n = 0; n <= degree; n++)
                {
                    for (int m = 0; m <= n; m++)
                    {
                        double Pnm = Legendre.lpmv(n, m, System.Math.PI / 2d - lat[i]);
                        B[i, col] = Pnm * System.Math.Cos(m * lon[i]);
                        col++;
                        // Bn0不需要估计,因为sin(0)乘任何数都是0
                        if (m == 0)
                        {
                            continue;
                        }
                        B[i, col] = Pnm * System.Math.Sin(m * lon[i]);
                        col++;
                    }
                }

                L[i] = vtec[i];
            }

            //// 求解
            var             btb  = B.Transpose() * B;
            var             btbi = btb.Inverse();
            Vector <double> x    = (B.Transpose() * B).Inverse() * (B.Transpose() * L);

            SphericalHarmonicIonoModel model = new SphericalHarmonicIonoModel();

            model.Degree = degree;
            model.Order  = order;
            model.Factor = x;

            return(model);
        }
Exemple #3
0
        /// <summary>
        /// 计算球谐函数模型,同时估计测站DCB,卫星DCB由星历提供
        /// </summary>
        /// <param name="degree">球谐函数阶数(中国地区一般为9,参见耿长江)</param>
        /// <param name="order">球谐函数次数</param>
        /// <param name="stations">测站名</param>
        /// <param name="prn">卫星编号</param>
        /// <param name="lat">地磁纬度</param>
        /// <param name="lon">日固经度</param>
        /// <param name="sp4">平滑后的P4</param>
        /// <param name="ele">高度角(弧度)</param>
        /// <param name="spm">输出的球谐模型</param>
        /// <param name="receiverDCB">接收机的dcb</param>
        /// <param name="satelliteDCB">卫星的dcb</param>
        /// <returns></returns>
        public static bool CalSphericalHarmonicModel(
            int degree, int order,
            List <string> stations,
            List <LinkedList <int> > prn,
            List <LinkedList <double> > lat,
            List <LinkedList <double> > lon,
            List <LinkedList <double> > sp4,
            List <LinkedList <double> > ele,
            Dictionary <string, double> satelliteDCB,
            out SphericalHarmonicIonoModel spm,
            out Dictionary <string, double> receiverDCB)
        {
            spm         = null;
            receiverDCB = new Dictionary <string, double>();
            if (satelliteDCB is null)
            {
                satelliteDCB = new Dictionary <string, double>();
            }

            Dictionary <int, double> satDCB = new Dictionary <int, double>();

            foreach (var key in satelliteDCB.Keys)
            {
                satDCB.Add(int.Parse(key.Substring(1)), satelliteDCB[key]);
            }

            if (degree != order)
            {
                throw new Exception("球谐函数阶数!=次数,暂时无法计算");
            }
            if (sp4 is null || sp4.Count() <= 0)
            {
                return(false);
            }

            // 获取到本次观测中的所有卫星编号,以估计卫星DCB
            // hashset是非重复集合,自动剔除重复元素
            HashSet <int> prns = new HashSet <int>();

            for (int i = 0; i < prn.Count(); i++)
            {
                foreach (var p in prn[i])
                {
                    prns.Add(p);
                }
            }

            // 测站数量
            int stationNum = stations.Count();
            // 卫星数量
            int satelliteNum = prns.Count();
            // 观测值数量
            int obsNum = (from item in sp4
                          select item.Count()).Sum();

            // 球谐系数参数个数
            int spmParaNum = (degree + 1) * (degree + 1);
            // 接收机DCB参数个数
            int recParaNum = stationNum;

            // 参数个数
            int paraNum = spmParaNum + stationNum;

            if (obsNum < paraNum)
            {
                throw new Exception("观测值个数无法满足建模要求!");
            }

            // 球谐系数起始索引位置
            int spmStart = 0;
            // 接收机DCB系数起始位置
            int recStart = spmParaNum;

            //// 设计矩阵
            Matrix <double> B        = new DenseMatrix(obsNum, (int)paraNum);
            Vector <double> L        = new DenseVector(obsNum);
            int             obsIndex = 0;
            int             satIndex = 0;
            int             recIndex = 0;
            double          sdcb     = 0;

            for (int i = 0; i < sp4.Count(); i++)
            {
                for (int j = 0; j < paraNum; j++)
                {
                    B[i, j] = 0d;
                }

                recIndex = i;

                var sp4i = sp4[i].First;
                var lati = lat[i].First;
                var loni = lon[i].First;
                var prni = prn[i].First;
                var elei = ele[i].First;
                for (int j = 0; j < sp4[i].Count; j++)
                {
                    satIndex = prni.Value;

                    double sp4j = sp4i.Value;
                    double latj = lati.Value;
                    double lonj = loni.Value;
                    double elej = elei.Value;
                    int    prnj = prni.Value;

                    sdcb = 0d;
                    satDCB.TryGetValue(prnj, out sdcb);

                    double fz = MathHelper.CalIonoFactor(elej);

                    // Anm,Bnm系数
                    int col = 0;
                    for (int n = 0; n <= degree; n++)
                    {
                        for (int m = 0; m <= n; m++)
                        {
                            double Pnm = Legendre.lpmv(n, m, System.Math.PI / 2d - latj);
                            B[obsIndex, col] = Pnm * System.Math.Cos(m * lonj) * fz;
                            col++;
                            // Bn0不需要估计,因为sin(0)乘任何数都是0
                            if (m == 0)
                            {
                                continue;
                            }
                            B[obsIndex, col] = Pnm * System.Math.Sin(m * lonj) * fz;
                            col++;
                        }
                    }

                    // 接收机DCB系数
                    B[obsIndex, recStart + recIndex] = 9.52437;

                    L[obsIndex] = sp4j * 9.52437 + 9.52437 * sdcb;

                    obsIndex++;

                    sp4i = sp4i.Next;
                    lati = lati.Next;
                    loni = loni.Next;
                    prni = prni.Next;
                    elei = elei.Next;
                }
            }

            ////// 求解
            var             btb  = B.Transpose() * B;
            var             btbi = btb.Inverse();
            Vector <double> x    = (B.Transpose() * B).Inverse() * (B.Transpose() * L);

            //提取球谐系数
            int             index = 0;
            List <double[]> anm   = new List <double[]>();
            List <double[]> bnm   = new List <double[]>();

            for (int i = 0; i <= degree; i++)
            {
                anm.Add(new double[i + 1]);
                bnm.Add(new double[i + 1]);
                for (int j = 0; j <= i; j++)
                {
                    anm[i][j] = x[index];
                    bnm[i][j] = 0d;
                    if (j == 0)
                    {
                        bnm[i][j] = x[index + 1];
                    }
                    if (j == 0)
                    {
                        index += 1;
                    }
                    else
                    {
                        index += 2;
                    }
                }
            }


            // 提取球谐系数
            Vector <double> spmFactor = new DenseVector(spmParaNum);

            for (int i = 0; i < spmParaNum; i++)
            {
                spmFactor[i] = x[i];
            }
            SphericalHarmonicIonoModel model = new SphericalHarmonicIonoModel();

            model.Degree = degree;
            model.Order  = order;
            model.Factor = spmFactor;
            spm.Anm      = anm;
            spm.Bnm      = bnm;

            // 提取接收机dcb
            for (int i = 0; i < stationNum; i++)
            {
                receiverDCB.Add(stations[i], x[recStart + i]);
            }

            return(true);
        }
Exemple #4
0
        /// <summary>
        /// 计算球谐函数模型,同时估计测站和接收机DCB
        /// </summary>
        /// <param name="degree">球谐函数阶数(中国地区一般为9,参见耿长江)</param>
        /// <param name="order">球谐函数次数</param>
        /// <param name="stations">测站名</param>
        /// <param name="prn">卫星编号</param>
        /// <param name="lat">地磁纬度</param>
        /// <param name="lon">日固经度</param>
        /// <param name="sp4">平滑后的P4</param>
        /// <param name="ele">高度角(弧度)</param>
        /// <param name="spm">输出的球谐模型</param>
        /// <param name="receiverDCB">接收机的dcb</param>
        /// <param name="satelliteDCB">卫星的dcb</param>
        /// <returns></returns>
        public static bool CalSphericalHarmonicModel(
            int degree, int order,
            List <string> stations,
            List <LinkedList <int> > prn,
            List <LinkedList <double> > lat,
            List <LinkedList <double> > lon,
            List <LinkedList <double> > sp4,
            List <LinkedList <double> > ele,
            out SphericalHarmonicIonoModel spm,
            out Dictionary <string, double> receiverDCB,
            out Dictionary <string, double> satelliteDCB)
        {
            spm          = null;
            receiverDCB  = new Dictionary <string, double>();
            satelliteDCB = new Dictionary <string, double>();

            if (degree != order)
            {
                throw new Exception("球谐函数阶数!=次数,暂时无法计算");
            }
            if (sp4 is null || sp4.Count() <= 0)
            {
                return(false);
            }

            // 获取到本次观测中的所有卫星编号,以估计卫星DCB
            // hashset是非重复集合,自动剔除重复元素
            HashSet <int> prns = new HashSet <int>();

            for (int i = 0; i < prn.Count(); i++)
            {
                foreach (var p in prn[i])
                {
                    prns.Add(p);
                }
            }

            // 测站数量
            int stationNum = stations.Count();
            // 卫星数量
            int satelliteNum = prns.Count();
            // 观测值数量
            int obsNum = (from item in sp4
                          select item.Count()).Sum();

            // 球谐系数参数个数
            int spmParaNum = (degree + 1) * (degree + 1);
            // 接收机DCB参数个数
            int recParaNum = stationNum;
            // 卫星DCB参数个数
            int satParaNum = satelliteNum;

            // 参数个数
            int paraNum = spmParaNum + stationNum + satelliteNum;

            if (obsNum < paraNum)
            {
                throw new Exception("观测值个数无法满足建模要求!");
            }

            // 球谐系数起始索引位置
            int spmStart = 0;
            // 接收机DCB系数起始位置
            int recStart = spmParaNum;
            // 卫星DCB系数起始位置
            int satStart = spmParaNum + recParaNum;

            //// 设计矩阵
            Matrix <double> B        = new DenseMatrix(obsNum + 1, (int)paraNum);
            Vector <double> L        = new DenseVector(obsNum + 1);
            int             obsIndex = 0;
            int             satIndex = 0;
            int             recIndex = 0;

            for (int i = 0; i < sp4.Count(); i++)
            {
                for (int j = 0; j < paraNum; j++)
                {
                    B[i, j] = 0d;
                }

                recIndex = i;

                var sp4i = sp4[i].First;
                var lati = lat[i].First;
                var loni = lon[i].First;
                var prni = prn[i].First;
                var elei = ele[i].First;
                for (int j = 0; j < sp4[i].Count; j++)
                {
                    satIndex = prni.Value;

                    double sp4j = sp4i.Value;
                    double latj = lati.Value;
                    double lonj = loni.Value;
                    double elej = elei.Value;
                    double fz   = MathHelper.CalIonoFactor(elej);

                    // Anm,Bnm系数
                    int col = 0;
                    for (int n = 0; n <= degree; n++)
                    {
                        for (int m = 0; m <= n; m++)
                        {
                            double Pnm = Legendre.lpmv(n, m, System.Math.PI / 2d - latj);
                            B[obsIndex, col] = Pnm * System.Math.Cos(m * lonj) * fz;
                            col++;
                            // Bn0不需要估计,因为sin(0)乘任何数都是0
                            if (m == 0)
                            {
                                continue;
                            }
                            B[obsIndex, col] = Pnm * System.Math.Sin(m * lonj) * fz;
                            col++;
                        }
                    }

                    // 接收机DCB系数
                    B[obsIndex, recStart + recIndex] = 9.52437;
                    // 卫星DCB系数
                    B[obsIndex, satStart + satIndex - 1] = -9.52437;

                    L[obsIndex] = sp4j * 9.52437;

                    obsIndex++;

                    sp4i = sp4i.Next;
                    lati = lati.Next;
                    loni = loni.Next;
                    prni = prni.Next;
                    elei = elei.Next;
                }
            }

            // 加入卫星DCB之和为0的约束
            for (int i = 0; i < paraNum; i++)
            {
                B[obsNum, i] = 0d;
            }
            foreach (var p in prns)
            {
                B[obsNum, satStart + p - 1] = 1;
            }

            ////// 求解
            var             btb  = B.Transpose() * B;
            var             btbi = btb.Inverse();
            Vector <double> x    = (B.Transpose() * B).Inverse() * (B.Transpose() * L);

            // 单位权中误差(平方)
            double sigma = x.DotProduct(x) / (obsNum + 1 - paraNum);
            // 协因数阵
            Matrix <double> Qxx = sigma * btbi;


            // 提取球谐系数
            int             index = 0;
            List <double[]> anm   = new List <double[]>();
            List <double[]> bnm   = new List <double[]>();

            for (int i = 0; i <= degree; i++)
            {
                anm.Add(new double[i + 1]);
                bnm.Add(new double[i + 1]);
                for (int j = 0; j <= i; j++)
                {
                    anm[i][j] = x[index];
                    index++;
                    bnm[i][j] = 0d;
                    if (j != 0)
                    {
                        bnm[i][j] = x[index];
                        index++;
                    }
                }
            }

            Vector <double> spmFactor = new DenseVector(spmParaNum);

            for (int i = 0; i < spmParaNum; i++)
            {
                spmFactor[i] = x[i];
            }
            spm        = new SphericalHarmonicIonoModel();
            spm.Degree = degree;
            spm.Order  = order;
            spm.Factor = spmFactor;
            spm.Anm    = anm;
            spm.Bnm    = bnm;

            Dictionary <string, double> receiverDCBRMS  = new Dictionary <string, double>();
            Dictionary <string, double> satelliteDCBRMS = new Dictionary <string, double>();

            // 提取接收机dcb
            for (int i = 0; i < stationNum; i++)
            {
                receiverDCB.Add(stations[i], x[recStart + i]);
                receiverDCBRMS.Add(stations[i], Math.Sqrt(Qxx[recStart + i, recStart + i]));
            }

            // 提取卫星DCB
            foreach (var p in prns)
            {
                satelliteDCB.Add(string.Format("G{0:00}", p), x[satStart + p - 1]);
                satelliteDCBRMS.Add(string.Format("G{0:00}", p), Math.Sqrt(Qxx[satStart + p - 1, satStart + p - 1]));
            }

            return(true);
        }