/// <summary> /// 计算相位平滑伪距值 /// 对于30s采样率的 /// </summary> /// <remarks> /// 参考 任晓东. 多系统GNSS电离层TEC高精度建模及差分码偏差精确估计[D]. /// </remarks> public void SmoothP41() { double f1 = Common.GPS_F1; double f2 = Common.GPS_F2; OArc arc = null; foreach (var prn in Arcs.Keys) { for (int i = 0; i < Arcs[prn].Count; i++) { // 取某颗卫星的一个观测弧段 arc = Arcs[prn][i]; // 整个弧段P4+L4的均值<P4+L4> double p4l4 = 0; for (int j = 1; j < arc.Length; j++) { p4l4 = p4l4 * j / (j + 1) + arc[j]["P4"] / (j + 1); } // 平滑P4 for (int j = 0; j < arc.Length; j++) { arc[j].SatData.Add("SP4", arc[j]["L4"] - p4l4); } } } }
/// <summary> /// 将弧段以index为界分为2段,index为第2段的起始索引 /// </summary> /// <param name="index">第二段开始的索引</param> /// <returns></returns> public OArc[] Split(int index) { if (index < 0 || index >= Length) { return(null); } // 第一段 OArc arc1 = new OArc(); arc1.PRN = PRN; arc1.File = File; arc1.Station = Station; arc1.StartIndex = StartIndex; arc1.EndIndex = StartIndex + index - 1; // 第2段[index,end] OArc arc2 = new OArc(); arc2.Station = Station; arc2.File = File; arc2.PRN = PRN; arc2.StartIndex = StartIndex + index; arc2.EndIndex = EndIndex; // EndIndex = StartIndex + (index - 1 < 0 ? 0 : index - 1); return(new OArc[] { arc1, arc2 }); }
/// <summary> /// 浅拷贝 /// </summary> /// <param name="arc"></param> public OArc(OArc arc) { PRN = arc.PRN; File = arc.File; Station = arc.Station; StartIndex = arc.StartIndex; EndIndex = arc.EndIndex; }
/// <summary> /// 对弧段进行滑动窗口拟合 /// </summary> /// <param name="arc"></param> /// <param name="length">窗口的长度 单位:历元</param> /// <param name="order">多项式拟合的阶数</param> public void Fit(ref OArc arc, int length, int order) { int si = 0; int ei = si + length; double sp4 = 0d; PolynomialModel pm = new PolynomialModel(); while (si < arc.Length) { if (ei > arc.Length) { ei = arc.Length; } // 只有一个历元 if (si == ei) { arc[si]["vtec"] = 0d; break; } List <double> x = new List <double>(); List <double> y = new List <double>(); List <int> index = new List <int>(); for (int i = si; i < ei; i++) { sp4 = arc[i]["vtec"]; if (Math.Abs(sp4) > 1e-10) { x.Add(i); y.Add(sp4); index.Add(i); } } double sigma; List <double> residue; if (pm.Fit(x, y, out residue, out sigma)) { for (int i = 0; i < x.Count; i++) { // 剔粗差 if (Math.Abs(residue[i]) < 5 * sigma && Math.Abs(residue[i]) < 2.5) { arc[index[i]]["vtec"] = residue[i]; } else { arc[index[i]]["vtec"] = 0d; } } } si = ei; ei += length; } }
public void DetectArcs() { for (int i = 0; i < 32; i++) { string prn = string.Format("G{0:0#}", i + 1); List <OArc> arcList = OArc.Detect(this, prn); Arcs.Add(prn, arcList); } }
/// <summary> /// 计算相位平滑伪距值 /// </summary> public void SmoothP4() { ObsHelper.CalL4(ref Epoches); ObsHelper.CalP4(ref Epoches); foreach (var prn in Arcs.Keys) { for (int i = 0; i < Arcs[prn].Count; i++) { OArc arc = Arcs[prn][i]; Smoother.SmoothP4ByL4(ref arc); } } }
/// <summary> /// 滑动平均 /// </summary> /// <param name="arc">弧段</param> /// <param name="meas">要平滑的观测值名称</param> /// <param name="order">阶数</param> public static void Smooth(ref OArc arc, string meas, int order) { if (arc is null) { return; } int left = 0, right = 0; if (order % 2 == 0) { left = order / 2; right = left - 1; } else { left = right = (order - 1) / 2; } double[] values = new double[arc.Length]; double[] values1 = new double[arc.Length]; for (int i = left; i < arc.Length - right; i++) { values[i] = arc[i][meas]; int k = 0; double mean = 0d; for (int j = i - left; j < i + right + 1; j++) { if (Math.Abs(arc[j][meas]) < 1e-10) { continue; } mean = mean * k / (k + 1) + arc[j][meas] / (k + 1); k++; } values[i] = mean; } for (int i = 0; i < arc.Length; i++) { arc[i]["dtec"] = arc[i][meas] - values[i]; arc[i][meas] = values[i]; } arc.StartIndex += left; arc.EndIndex -= right; }
public void DetectCycleSlip() { for (int k = 0; k < Arcs.Keys.Count; k++) { string prn = Arcs.Keys.ElementAt(k); //// 旧的弧段 Stack <OArc> oldArcs = new Stack <OArc>(); //// 探测后新的弧段 List <OArc> newArcs = new List <OArc>(); for (int i = Arcs[prn].Count - 1; i >= 0; i--) { oldArcs.Push(Arcs[prn][i].Copy()); } int index = -1; OArc arc = null; while (oldArcs.Count() > 0) { arc = oldArcs.Pop(); if (ObsHelper.DetectCycleSlip(ref arc, out index)) { // 根据返回周跳的索引将弧段分为2段 OArc[] arcs = arc.Split(index); // 前一段加入已检测的列表 if (arcs[0].Length >= Options.ARC_MIN_LENGTH) { newArcs.Add(arcs[0]); } // 后一段加入未检测列表 if (arcs[1].Length >= Options.ARC_MIN_LENGTH) { oldArcs.Push(arcs[1]); } } else { newArcs.Add(arc); } } Arcs[prn] = newArcs; } }
public void CalVTEC() { foreach (var prn in Arcs.Keys) { for (int i = 0; i < Arcs[prn].Count; i++) { OArc arc = Arcs[prn][i]; for (int j = 0; j < arc.Length; j++) { if (Math.Abs(arc[j]["SP4"]) > 1e-10) { arc[j]["vtec"] = Iono.STEC2VTEC(9.52437 * arc[j]["SP4"], arc[j].Elevation); } } } } }
public void CalP4L4() { OArc arc = null; double p1 = 0d, p2 = 0d, l1 = 0d, l2 = 0d; foreach (var prn in Arcs.Keys) { for (int i = 0; i < Arcs[prn].Count; i++) { // 取某颗卫星的一个观测弧段 arc = Arcs[prn][i]; for (int j = 0; j < arc.Length; j++) { p1 = arc[j].SatData["P1"]; p2 = arc[j].SatData["P2"]; l1 = arc[j].SatData["L1"]; l2 = arc[j].SatData["L2"]; if (p1 == 0d) { p1 = arc[j].SatData["C1"]; } if (p1 != 0d || p2 != 0d) { arc[j]["P4"] = p2 - p1; } else { arc[j]["P4"] = 0; } if (l1 != 0 && l2 != 0) { arc[j]["L4"] = l2 - l1; } else { arc[j]["L4"] = 0; } } } } }
/// <summary> /// 平滑一个弧段 /// </summary> /// <param name="arc"></param> public static void SmoothP4ByL4_1(ref OArc arc) { double power = 1; // P4预报值 double p4_est = 0d; for (int i = 1; i < arc.Length; i++) { power = power - DEC_POWER; if (power < MIN_POWER) { power = MIN_POWER; } p4_est = arc[i - 1]["P4"] + arc[i]["L4"] - arc[i - 1]["L4"]; arc[i]["P4"] = arc[i]["P4"] * power + (1 - power) * p4_est; } }
/// <summary> /// 计算ROTI /// </summary> /// <param name="arc"></param> /// <remarks> /// 2019.研究台风引起电离层扰动的形态特征.许九靖. 安徽理工大学. /// </remarks> public static void CalROTI(ref OArc arc) { if (arc is null) { return; } // 利用相位观测值计算相对STEC信号 for (int i = 1; i < arc.Length; i++) { if (Math.Abs(arc[i]["L4"]) < 1e-13 || Math.Abs(arc[i + 1]["L4"]) < 1e-13) { continue; } arc[i]["ltec"] = 9.52437 * (arc[i]["L4"] - arc[i - 1]["L4"]); } int order = 9; int left, right; left = right = (order - 1) / 2; Vector <double> seg = new DenseVector(order); for (int i = left; i < arc.Length - right; i++) { for (int j = 0; j < order; j++) { seg[j] = arc[i - left + j]["ltec"]; } arc[i]["roti"] = Math.Sqrt(seg.DotProduct(seg) / order - Math.Pow(seg.Mean(), 2)); } arc.StartIndex += left + 1; arc.EndIndex -= right + 1; }
public static void CalDoubleDiff(ref OArc arc) { if (arc is null) { return; } for (int i = 1; i < arc.Length - 1; i++) { if (Math.Abs(arc[i - 1]["L4"]) < 1e-13 || Math.Abs(arc[i]["L4"]) < 1e-13 || Math.Abs(arc[i + 1]["L4"]) < 1e-13) { continue; } arc[i]["L6"] = 9.52437 * ((arc[i + 1]["L4"] - arc[i]["L4"]) - (arc[i]["L4"] - arc[i - 1]["L4"])); } arc.StartIndex += 1; arc.EndIndex -= 1; }
public void Fit(ref OArc arc) { List <int> index = new List <int>(); List <double> x = new List <double>(); List <double> y = new List <double>(); for (int i = 0; i < arc.Length; i++) { if (Math.Abs(arc[i]["SP4"]) > 1e-3) { index.Add(i); x.Add(i); y.Add(arc[i]["SP4"]); } } PolynomialModel pm = PolynomialModel.Fit(x, y, 3); for (int i = 0; i < x.Count; i++) { arc[index[i]]["SP4"] -= pm.CalFit(x[i]); } }
/// <summary> /// 平滑一个弧段 /// </summary> /// <param name="arc"></param> public static void SmoothP4ByL4(ref OArc arc, string type = "hatch") { if (type == "hatch") { // 整个弧段P4+L4的均值<P4+L4> int n = 0; double p4, l4; double p4l4 = 0d; double[] p4l4All = new double[arc.Length]; for (int i = 0; i < arc.Length; i++) { p4 = arc[i]["P4"]; l4 = arc[i]["L4"]; if (p4 != 0 && l4 != 0) { p4l4 += p4 + l4; n++; } p4l4All[i] = p4 + l4; } if (n > 0) { p4l4 /= n; } // 平滑P4 for (int j = 0; j < arc.Length; j++) { p4 = arc[j]["P4"]; l4 = arc[j]["L4"]; arc[j].SatData["SP4"] = 0; if (p4 != 0 && l4 != 0) { arc[j].SatData["SP4"] = p4l4 - l4; } } } else {//双向hatch滤波 double[] sp4Forward = new double[arc.Length]; double[] sp4Backward = new double[arc.Length]; // 前向 double power = 1; double MIN_POWER = 0.01; double POWER_DEC = 0.02; sp4Forward[0] = arc[0]["P4"]; for (int i = 1; i < arc.Length; i++) { power = power - POWER_DEC >= MIN_POWER ? power - POWER_DEC : MIN_POWER; sp4Forward[i] = (sp4Forward[i - 1] + arc[i]["L4"] - arc[i - 1]["L4"]) * (1 - power) + arc[i]["P4"] * power; } // 后向 power = 1d; sp4Backward[arc.Length - 1] = arc[arc.Length - 1]["P4"]; for (int i = arc.Length - 2; i >= 0; i--) { power = power - POWER_DEC >= MIN_POWER ? power - POWER_DEC : MIN_POWER; sp4Backward[i] = (sp4Forward[i + 1] + arc[i]["L4"] - arc[i + 1]["L4"]) * (1 - power) + arc[i]["P4"] * power; } if (arc.Length > 60) { for (int i = 0; i < 30; i++) { arc[i]["SP4"] = sp4Backward[i]; } for (int i = arc.Length - 1; i >= arc.Length - 30; i--) { arc[i]["SP4"] = sp4Forward[i]; } for (int i = 30; i < arc.Length - 30; i++) { arc[i]["SP4"] = sp4Forward[i] / 2d + sp4Backward[i] / 2d; } } else { int midIndex = arc.Length / 2; for (int i = 0; i < midIndex; i++) { arc[i]["SP4"] = sp4Backward[i]; } for (int i = midIndex; i < arc.Length; i++) { arc[i]["SP4"] = sp4Forward[i]; } } } }
/// <summary> /// 探测周跳 /// </summary> /// <remarks> /// GPS周跳探测与修复的算法研究与实现.彭秀英.2004 /// </remarks> public static bool DetectCycleSlip(ref OArc arc, out int index) { index = -1; // i-1历元宽巷模糊度估计值 double NW1 = 0d; // i历元宽巷模糊度估计值 double NW2 = 0d; // i+1历元宽巷模糊度估计值 double NW3 = 0d; // i-1历元宽巷模糊度估计值精度 double delta1 = 0d; // i历元宽巷模糊度估计值精度 double delta2 = 0d; // GPS L1频率(Hz) double f1 = Common.GPS_F1; // GPS L2频率(Hz) double f2 = Common.GPS_F2; // GPS L1波长(m) double l1 = Common.GPS_L1; // GPS L2波长(m) double l2 = Common.GPS_L2; // L1精度(m) double dL1 = Common.DELTA_L1; // L2精度(m) double dL2 = Common.DELTA_L2; // P1精度(m) double dP1 = Common.DELTA_P1; // P2精度(m) double dP2 = Common.DELTA_P2; double vp1, vp2, vl1, vl2; GetMeas(arc[0], out vp1, out vp2, out vl1, out vl2, out dP1); // 初始化NW(i-1) NW1 = (1 / (f1 - f2) * (f1 * vl1 * l1 - f2 * vl2 * l2) - 1 / (f1 + f2) * (f1 * vp1 + f2 * vp2)) / Common.GPS_Lw; GetMeas(arc[1], out vp1, out vp2, out vl1, out vl2, out dP1); // 初始化NW(i) NW2 = (1 / (f1 - f2) * (f1 * vl1 * l1 - f2 * vl2 * l2) - 1 / (f1 + f2) * (f1 * vp1 + f2 * vp2)) / Common.GPS_Lw; // 初始化δ(i-1) delta1 = Math.Sqrt( 1 / Math.Pow(f1 - f2, 2) * (f1 * f1 * dL1 + f2 * f2 * dL2) + 1 / Math.Pow(f1 + f2, 2) * (f1 * f1 * dP1 + f2 * f2 + dP2) ); // 前一历元gf值 double lstGF = arc[0]["GF"]; // 当前历元gf值 double curGF = arc[0]["GF"]; int arcLen = arc.Length - 1; for (int i = 1; i < arcLen; i++) { if (!GetMeas(arc[i + 1], out vp1, out vp2, out vl1, out vl2, out _)) { index = i + 1; return(true); } NW3 = (1 / (f1 - f2) * (f1 * vl1 * l1 - f2 * vl2 * l2) - 1 / (f1 + f2) * (f1 * vp1 + f2 * vp2)) / Common.GPS_Lw; delta2 = Math.Sqrt(delta1 * delta1 * i / (i + 1) + Math.Pow(NW2 - NW1, 2) / (i + 1)); // MW探测 if (Math.Abs(NW2 - NW1) > 4 * delta1) { if (Math.Abs(NW3 - NW2) < 1) { arc[i].CycleSlip = true; } else { arc[i].Outlier = true; } // 有周跳,分割成新弧段 //OArc newArc = arc.Split(i + 1); //arc.Station.Arcs[arc.PRN].Add(newArc); index = i + 1; Common.msgBox.Print(string.Format("\r\n检测到周跳,时间:{0},历元:{1:0000},编号:{2}", arc[i + 1].Epoch, i + 1 + arc.StartIndex, arc[i + 1].SatPRN)); return(true); } NW1 = NW1 * i / (i + 1) + NW2 / (i + 1); NW2 = NW3; delta1 = delta2; lstGF = curGF; curGF = arc[i]["GF"]; if (arc[i].CycleSlip || arc[i].Outlier) { continue; } // GF探测 if (!arc[i].CycleSlip) { if (Math.Abs(curGF - lstGF) > Options.Threshold_GF) { arc[i].CycleSlip = true; } } // 检查LLI if (!arc[i].CycleSlip) { if (arc[i]["L1"] == 1 || arc[i]["L2"] == 1) { arc[i].CycleSlip = true; } } } return(false); }
public static List <OArc> Detect(OStation sta, string prn, int minArcLen = -1) { if (sta is null) { return(null); } if (minArcLen < 0) { minArcLen = Options.ARC_MIN_LENGTH; } List <OArc> arcs = new List <OArc>(); int start = -1; double l1, l2, p1, p2, c1; for (int i = 0; i < sta.EpochNum; i++) { bool flag = true; if (!sta.Epoches[i].AllSat.ContainsKey(prn)) { flag = false; } else { l1 = sta.Epoches[i][prn]["L1"]; l2 = sta.Epoches[i][prn]["L2"]; p1 = sta.Epoches[i][prn]["P1"]; p2 = sta.Epoches[i][prn]["P2"]; c1 = sta.Epoches[i][prn]["C1"]; if (l1 == 0 || l2 == 0 || p2 == 0) { flag = false; } else if (p1 == 0 && c1 == 0) { flag = false; } else if (sta.Epoches[i][prn].Outlier) { flag = false; } else if (sta.Epoches[i][prn].CycleSlip) { flag = false; } } if (flag) { // 弧段继续 if (start > -1) { continue; } // 弧段开始 else { start = i; } } else { // 弧段结束 if (start > -1) { if (i - start > minArcLen) { OArc arc = new OArc(); arc.StartIndex = start + 10; arc.EndIndex = i - 1 - 10; arc.Station = sta; arc.PRN = prn; arcs.Add(arc); } start = -1; } else { continue; } } } return(arcs); }