public ProcessingReturnValues FitAndPlotSlowFlyby( Dictionary<int, SingleMultiFrameMeasurement> measurements, FlybyMeasurementContext meaContext, FittingContext fittingContext, FittingValue fittingValue, GetFrameStateDataCallback getFrameStateDataCallback, Graphics g, FlybyPlottingContext plottingContext, float xScale, float yScale, int imageWidth, int imageHight, out double motionRate) { try { #region Building Test Cases if (m_DumpTestCaseData) { var mvSer = new XmlSerializer(typeof(FlybyMeasurementContext)); var sb = new StringBuilder(); using (var wrt = new StringWriter(sb)) { mvSer.Serialize(wrt, meaContext); } Trace.WriteLine(sb.ToString()); var fcSer = new XmlSerializer(typeof(FittingContext)); sb.Clear(); using (var wrt = new StringWriter(sb)) { fcSer.Serialize(wrt, fittingContext); } Trace.WriteLine(sb.ToString()); var smfmSer = new XmlSerializer(typeof(SingleMultiFrameMeasurement)); foreach (int key in measurements.Keys) { sb.Clear(); using (var wrt2 = new StringWriter(sb)) { smfmSer.Serialize(wrt2, measurements[key]); if (measurements[key].FrameNo != key) throw new InvalidOperationException(); Trace.WriteLine(sb.ToString()); } } } #endregion // Do linear regression, use residual based exclusion rules // Report the interpolated position at the middle of the measured interva // Don't forget to add the video normal position flag in the OBS file // Expect elongated images and apply instrumental delay corrections motionRate = double.NaN; var rv = new ProcessingReturnValues(); int numFramesUser = 0; rv.EarliestFrame = int.MaxValue; rv.LatestFrame = int.MinValue; var intervalValues = new Dictionary<int, Tuple<List<double>, List<double>>>(); var intervalMedians = new Dictionary<double, double>(); var intervalWeights = new Dictionary<double, double>(); LinearRegression regression = null; if (measurements.Values.Count > 1) { rv.EarliestFrame = measurements.Values.Select(m => m.FrameNo).Min(); rv.LatestFrame = measurements.Values.Select(m => m.FrameNo).Max(); var minUncertainty = meaContext.MinPositionUncertaintyPixels * meaContext.ArsSecsInPixel; foreach (SingleMultiFrameMeasurement measurement in measurements.Values) { int integrationInterval = (measurement.FrameNo - fittingContext.FirstFrameIdInIntegrationPeroid) / fittingContext.IntegratedFramesCount; Tuple<List<double>,List<double>> intPoints; if (!intervalValues.TryGetValue(integrationInterval, out intPoints)) { intPoints = Tuple.Create(new List<double>(), new List<double>()); intervalValues.Add(integrationInterval, intPoints); } if (fittingValue == FittingValue.RA) { intPoints.Item1.Add(measurement.RADeg); intPoints.Item2.Add(ComputePositionWeight(measurement.SolutionUncertaintyRACosDEArcSec, measurement, minUncertainty, fittingContext.Weighting)); } else { intPoints.Item1.Add(measurement.DEDeg); intPoints.Item2.Add(ComputePositionWeight(measurement.SolutionUncertaintyDEArcSec, measurement, minUncertainty, fittingContext.Weighting)); } } if (intervalValues.Count > 2) { regression = new LinearRegression(); foreach (int integratedFrameNo in intervalValues.Keys) { Tuple<List<double>, List<double>> data = intervalValues[integratedFrameNo]; double median; double medianWeight; WeightedMedian(data, out median, out medianWeight); // Assign the data point to the middle of the integration interval (using frame numbers) // // |--|--|--|--|--|--|--|--| // | | | // // Because the time associated with the first frame is the middle of the frame, but the // time associated with the middle of the interval is the end of the field then the correction // is (N / 2) - 0.5 frames double dataPointFrameNo = rv.EarliestFrame + fittingContext.IntegratedFramesCount * integratedFrameNo + (fittingContext.IntegratedFramesCount / 2) - 0.5; intervalMedians.Add(dataPointFrameNo, median); intervalWeights.Add(dataPointFrameNo, medianWeight); if (fittingContext.Weighting != WeightingMode.None) regression.AddDataPoint(dataPointFrameNo, median, medianWeight); else regression.AddDataPoint(dataPointFrameNo, median); } regression.Solve(); var firstPos = measurements[rv.EarliestFrame]; var lastPos = measurements[rv.LatestFrame]; double distanceArcSec = AngleUtility.Elongation(firstPos.RADeg, firstPos.DEDeg, lastPos.RADeg, lastPos.DEDeg) * 3600; var firstTime = GetTimeForFrame(fittingContext, rv.EarliestFrame, meaContext.FirstVideoFrame, getFrameStateDataCallback, firstPos.OCRedTimeStamp); var lastTime = GetTimeForFrame(fittingContext, rv.LatestFrame, meaContext.FirstVideoFrame, getFrameStateDataCallback, lastPos.OCRedTimeStamp); double elapsedSec = new TimeSpan(lastTime.UT.Ticks - firstTime.UT.Ticks).TotalSeconds; motionRate = distanceArcSec / elapsedSec; } } FrameTime resolvedTime = null; if (int.MinValue != meaContext.UserMidFrame) { // Find the closest video 'normal' MPC time and compute the frame number for it // Now compute the RA/DE for the computed 'normal' frame resolvedTime = GetTimeForFrame(fittingContext, meaContext.UserMidFrame, meaContext.FirstVideoFrame, getFrameStateDataCallback, measurements[meaContext.UserMidFrame].OCRedTimeStamp); #region Plotting Code if (g != null) { float xPosBeg = (float)(resolvedTime.ClosestNormalIntervalFirstFrameNo - rv.EarliestFrame) * xScale + 5; float xPosEnd = (float)(resolvedTime.ClosestNormalIntervalLastFrameNo - rv.EarliestFrame) * xScale + 5; g.FillRectangle(s_NormalTimeIntervalHighlightBrush, xPosBeg, 1, (xPosEnd - xPosBeg), imageHight - 2); } #endregion } Dictionary<double, double> secondPassData = new Dictionary<double, double>(); int minFrameId = measurements.Keys.Min(); #region Plotting Code if (g != null) { foreach (SingleMultiFrameMeasurement measurement in measurements.Values) { float x = (measurement.FrameNo - minFrameId) * xScale + 5; ProcessingValues val = new ProcessingValues() { Value = fittingValue == FittingValue.RA ? measurement.RADeg : measurement.DEDeg, StdDev = fittingValue == FittingValue.RA ? measurement.StdDevRAArcSec / 3600.0 : measurement.StdDevDEArcSec / 3600.0 }; double valueFrom = val.Value - val.StdDev; double valueTo = val.Value + val.StdDev; float yFrom = (float)(valueFrom - plottingContext.MinValue) * yScale + 5; float yTo = (float)(valueTo - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.IncludedPen, x, yFrom, x, yTo); g.DrawLine(plottingContext.IncludedPen, x - 1, yFrom, x + 1, yFrom); g.DrawLine(plottingContext.IncludedPen, x - 1, yTo, x + 1, yTo); } } #endregion foreach (double integrFrameNo in intervalMedians.Keys) { double val = intervalMedians[integrFrameNo]; double fittedValAtFrame = regression != null ? regression.ComputeY(integrFrameNo) : double.NaN; bool included = Math.Abs(fittedValAtFrame - val) < 3 * regression.StdDev; #region Plotting Code if (g != null) { if (fittingContext.IntegratedFramesCount > 1) { Pen mPen = included ? plottingContext.IncludedPen : plottingContext.ExcludedPen; float x = (float)(integrFrameNo - minFrameId) * xScale + 5; float y = (float)(val - plottingContext.MinValue) * yScale + 5; g.DrawEllipse(mPen, x - 3, y - 3, 6, 6); g.DrawLine(mPen, x - 5, y - 5, x + 5, y + 5); g.DrawLine(mPen, x + 5, y - 5, x - 5, y + 5); } } #endregion if (included) secondPassData.Add(integrFrameNo, val); } #region Second Pass regression = null; if (secondPassData.Count > 2) { regression = new LinearRegression(); foreach (double frameNo in secondPassData.Keys) { if (fittingContext.Weighting != WeightingMode.None) regression.AddDataPoint(frameNo, secondPassData[frameNo], intervalWeights[frameNo]); else regression.AddDataPoint(frameNo, secondPassData[frameNo]); } regression.Solve(); } #endregion if (regression != null) { #region Plotting Code if (g != null) { double leftFittedVal = regression.ComputeY(rv.EarliestFrame); double rightFittedVal = regression.ComputeY(rv.LatestFrame); double err = 3 * regression.StdDev; float leftAve = (float)(leftFittedVal - plottingContext.MinValue) * yScale + 5; float rightAve = (float)(rightFittedVal - plottingContext.MinValue) * yScale + 5; float leftX = 5 + (float)(rv.EarliestFrame - rv.EarliestFrame) * xScale; float rightX = 5 + (float)(rv.LatestFrame - rv.EarliestFrame) * xScale; g.DrawLine(plottingContext.AveragePen, leftX, leftAve - 1, rightX, rightAve - 1); g.DrawLine(plottingContext.AveragePen, leftX, leftAve, rightX, rightAve); g.DrawLine(plottingContext.AveragePen, leftX, leftAve + 1, rightX, rightAve + 1); float leftMin = (float)(leftFittedVal - err - plottingContext.MinValue) * yScale + 5; float leftMax = (float)(leftFittedVal + err - plottingContext.MinValue) * yScale + 5; float rightMin = (float)(rightFittedVal - err - plottingContext.MinValue) * yScale + 5; float rightMax = (float)(rightFittedVal + err - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.AveragePen, leftX, leftMin, rightX, rightMin); g.DrawLine(plottingContext.AveragePen, leftX, leftMax, rightX, rightMax); } #endregion if (int.MinValue != meaContext.UserMidFrame && resolvedTime != null) { // Find the closest video 'normal' MPC time and compute the frame number for it // Now compute the RA/DE for the computed 'normal' frame double fittedValueUncertainty; double fittedValueAtMiddleFrame = regression.ComputeYWithError(resolvedTime.ClosestNormalFrameNo, out fittedValueUncertainty); Trace.WriteLine(string.Format("{0}; Included: {1}; Normal Frame No: {2}; Fitted Val: {3} +/- {4:0.00}", meaContext.UserMidValue.ToString("0.00000"), numFramesUser, resolvedTime.ClosestNormalFrameNo, AstroConvert.ToStringValue(fittedValueAtMiddleFrame, "+HH MM SS.T"), regression.StdDev * 60 * 60)); // Report the interpolated position at the middle of the measured interval // Don't forget to add the video normal position flag in the OBS file // Expect elongated images and apply instrumental delay corrections rv.FittedValue = fittedValueAtMiddleFrame; rv.FittedValueTime = resolvedTime.ClosestNormalFrameTime; rv.IsVideoNormalPosition = true; rv.FittedNormalFrame = resolvedTime.ClosestNormalFrameNo; rv.FittedValueUncertaintyArcSec = fittedValueUncertainty * 60 * 60; #region Plotting Code if (g != null) { // Plot the frame float xPos = (float)(resolvedTime.ClosestNormalFrameNo - rv.EarliestFrame) * xScale + 5; float yPos = (float)(rv.FittedValue - plottingContext.MinValue) * yScale + 5; g.DrawLine(Pens.Yellow, xPos, 1, xPos, imageHight - 2); g.FillEllipse(Brushes.Yellow, xPos - 3, yPos - 3, 6, 6); } #endregion } else rv.FittedValue = double.NaN; } else rv.FittedValue = double.NaN; return rv; } catch (Exception ex) { Trace.WriteLine(ex.GetFullStackTrace()); motionRate = 0; return null; } }
private ImagePixel GetExpectedPosition(int frameNo) { ImagePixel rv = null; var intervalValues = new Dictionary<int, List<ImagePixel>>(); var intervalMedians = new Dictionary<int, ImagePixel>(); int earliestFrame = m_PastFrameNos[0]; for (int i = 0; i < m_PastFrameNos.Count; i++) { int integrationInterval = (m_PastFrameNos[i] - earliestFrame) / m_MeasurementContext.IntegratedFramesCount; List<ImagePixel> intPoints; if (!intervalValues.TryGetValue(integrationInterval, out intPoints)) { intPoints = new List<ImagePixel>(); intervalValues.Add(integrationInterval, intPoints); } intPoints.Add(new ImagePixel(m_PastFramePosX[i], m_PastFramePosY[i])); } var calcBucketX = new List<double>(); var calcBucketY = new List<double>(); foreach (int key in intervalValues.Keys) { calcBucketX.Clear(); calcBucketY.Clear(); intervalValues[key].ForEach(v => { calcBucketX.Add(v.XDouble); calcBucketY.Add(v.YDouble); }); double xMed = calcBucketX.Median(); double yMed = calcBucketY.Median(); intervalMedians.Add(key, new ImagePixel(xMed, yMed)); } var xMotion = new LinearRegression(); var yMotion = new LinearRegression(); foreach (int intInt in intervalMedians.Keys) { long t = intInt; double x = intervalMedians[intInt].XDouble; double y = intervalMedians[intInt].YDouble; if (x > 0 && y > 0) { xMotion.AddDataPoint(t, x); yMotion.AddDataPoint(t, y); } } try { xMotion.Solve(); yMotion.Solve(); int currIntInterval = (frameNo - earliestFrame) / m_MeasurementContext.IntegratedFramesCount; rv = new ImagePixel(xMotion.ComputeY(currIntInterval), yMotion.ComputeY(currIntInterval)); } catch (Exception ex) { Trace.WriteLine(ex.GetFullStackTrace()); } return rv; }
public void Test1() { // Based on https://www.medcalc.org/manual/weighted-regression-worked-example.php var reg = new LinearRegression(); double[] x_values = new double[] { 27, 21, 22, 24, 25, 23, 20, 20, 29, 24, 25, 28, 26, 38, 32, 33, 31, 34, 37, 38, 33, 35, 30, 31, 37, 39, 46, 49, 40, 42, 43, 46, 43, 44, 46, 47, 45, 49, 48, 40, 42, 55, 54, 57, 52, 53, 56, 52, 50, 59, 50, 52, 58, 57 }; double[] y_values = new double[] { 73, 66, 63, 75, 71, 70, 65, 70, 79, 72, 68, 67, 79, 91, 76, 69, 66, 73, 78, 87, 76, 79, 73, 80, 68, 75, 89, 101, 70, 72, 80, 83, 75, 71, 80, 96, 92, 80, 70, 90, 85, 76, 71, 99, 86, 79, 92, 85, 71, 90, 91, 100, 80, 109 }; for (int i = 0; i < x_values.Length; i++) { reg.AddDataPoint(x_values[i], y_values[i]); } reg.Solve(); Assert.AreEqual(0.5800, reg.A, 0.0001); Assert.AreEqual(56.1569, reg.B, 0.0001); Assert.AreEqual(8.1457, reg.StdDev, 0.0001); Assert.AreEqual(0.09695, reg.Uncertainty_A, 0.0001); Assert.AreEqual(3.9937, reg.Uncertainty_B, 0.0001); var residuals = reg.Residuals.ToArray(); var reg2 = new LinearRegression(); for (int i = 0; i < x_values.Length; i++) { reg2.AddDataPoint(x_values[i], Math.Abs(residuals[i])); } reg2.Solve(); Assert.AreEqual(0.1982, reg2.A, 0.0001); Assert.AreEqual(-1.5495, reg2.B, 0.0001); Assert.AreEqual(4.4606, reg2.StdDev, 0.0001); Assert.AreEqual(0.05309, reg2.Uncertainty_A, 0.0001); Assert.AreEqual(2.1869, reg2.Uncertainty_B, 0.0001); var predictedValues = new double[x_values.Length]; for (int i = 0; i < x_values.Length; i++) { predictedValues[i] = reg2.ComputeY(x_values[i]); } var reg3 = new LinearRegression(); var factor = 1; for (int i = 0; i < x_values.Length; i++) { double weight = factor / (predictedValues[i] * predictedValues[i]); reg3.AddDataPoint(x_values[i], y_values[i], weight); } reg3.Solve(); Assert.AreEqual(0.5963, reg3.A, 0.0001); Assert.AreEqual(55.5658, reg3.B, 0.0001); Assert.AreEqual(1.2130, reg3.StdDevUnscaled, 0.0001); }
public void Test2() { var reg = new LinearRegression(); reg.AddDataPoint(1, 6); reg.AddDataPoint(2, 5); reg.AddDataPoint(3, 7); reg.AddDataPoint(4, 10); reg.Solve(); Assert.AreEqual(1.4, reg.A, 0.001); Assert.AreEqual(3.5, reg.B, 0.001); }
public void Test3() { // Based on https://onlinecourses.science.psu.edu/stat501/node/352 double[] x_values = new double[] { 0.21, 0.20, 0.19, 0.18, 0.17, 0.16, 0.15 }; double[] y_values = new double[] { 0.1726, 0.1707, 0.1637, 0.1640, 0.1613, 0.1617, 0.1598 }; double[] sd_values = new double[] { 0.01988, 0.01938, 0.01896, 0.02037, 0.01654, 0.01594, 0.01763 }; var reg_ols = new LinearRegression(); var reg_wls = new LinearRegression(); var reg_wls2 = new LinearRegression(); for (int i = 0; i < x_values.Length; i++) { reg_ols.AddDataPoint(x_values[i], y_values[i]); reg_wls.AddDataPoint(x_values[i], y_values[i], 1 / (sd_values[i] * sd_values[i])); reg_wls2.AddDataPoint(x_values[i], y_values[i], 2 / (sd_values[i] * sd_values[i])); } reg_ols.Solve(); reg_wls.Solve(); reg_wls2.Solve(); Assert.AreEqual(0.2048, reg_wls.A, 0.0001); Assert.AreEqual(0.12796, reg_wls.B, 0.0001); Assert.AreEqual(0.2048, reg_wls2.A, 0.0001); Assert.AreEqual(0.12796, reg_wls2.B, 0.0001); if (Math.Abs(reg_wls.StdDevUnscaled - reg_wls2.StdDevUnscaled) < 0.0001) { Assert.Fail("Proportional weights result in different StdDevs in the weighted population"); }; Assert.AreEqual(reg_wls.StdDev, reg_wls2.StdDev, 0.0001, "Proportional weights result in the same scaled StdDev"); Assert.AreEqual(0.2100, reg_ols.A, 0.0001); Assert.AreEqual(0.12703, reg_ols.B, 0.0001); }
public void Test4() { // Based on https://onlinecourses.science.psu.edu/stat501/node/397 double[] x_values = new double[] { 16, 14, 22, 10, 14, 17, 10, 13, 19, 12, 18, 11 }; double[] y_values = new double[] { 77, 70, 85, 50, 62, 70, 55, 63, 88, 57, 81, 51 }; var reg_ols = new LinearRegression(); for (int i = 0; i < x_values.Length; i++) { reg_ols.AddDataPoint(x_values[i], y_values[i]); } reg_ols.Solve(); Assert.AreEqual(3.269, reg_ols.A, 0.001); Assert.AreEqual(19.47, reg_ols.B, 0.01); Assert.AreEqual(4.5983, reg_ols.StdDev, 0.0001); Assert.AreEqual(0.365, reg_ols.Uncertainty_A, 0.001); Assert.AreEqual(5.52, reg_ols.Uncertainty_B, 0.01); var residuals = reg_ols.Residuals.ToArray(); var reg2 = new LinearRegression(); for (int i = 0; i < x_values.Length; i++) { reg2.AddDataPoint(x_values[i], Math.Abs(residuals[i])); } reg2.Solve(); var predictedValues = new double[x_values.Length]; for (int i = 0; i < x_values.Length; i++) { predictedValues[i] = reg2.ComputeY(x_values[i]); } var reg_wls = new LinearRegression(); var factor = 1; for (int i = 0; i < x_values.Length; i++) { double weight = factor / (predictedValues[i] * predictedValues[i]); reg_wls.AddDataPoint(x_values[i], y_values[i], weight); } reg_wls.Solve(); Assert.AreEqual(3.421, reg_wls.A, 0.001); Assert.AreEqual(17.30, reg_wls.B, 0.01); Assert.AreEqual(1.15935, reg_wls.StdDevUnscaled, 0.00001); }
private void ImproveSolution(LeastSquareFittedAstrometry fit, double coeff, int i, int j, int k) { m_SolutionSolver = new PlateConstantsSolver(m_PlateConfig); double ra0, de0; fit.GetRADEFromImageCoords(m_PlateConfig.CenterXImage, m_PlateConfig.CenterXImage, out ra0, out de0); m_SolutionSolver.InitPlateSolution(ra0, de0); List<IStar> consideredStars = new List<IStar>(); List<ulong> nonStellarStars = new List<ulong>(); foreach (IStar star in m_CelestialAllStars) { if (star.Mag < m_MinMag || star.Mag > m_MaxMag) continue; if (m_DetermineAutoLimitMagnitude && !double.IsNaN(m_DetectedLimitingMagnitude) && star.Mag > m_DetectedLimitingMagnitude) { #if ASTROMETRY_DEBUG Trace.Assert(false); #endif continue; } double x, y; fit.GetImageCoordsFromRADE(star.RADeg, star.DEDeg, out x, out y); if (x < 0 || x > m_PlateConfig.ImageWidth || y < 0 || y > m_PlateConfig.ImageHeight) continue; ImagePixel pixel = null; PSFFit psfFit; PSFFit asymPsfFit = null; //if (m_FitSettings.CenterDetectionMethod == StarCenterDetection.PSFFit) { if (m_Settings.PyramidRemoveNonStellarObject) m_StarMap.GetPSFFit((int)x, (int)y, PSFFittingMethod.NonLinearAsymetricFit, out asymPsfFit); pixel = m_StarMap.GetPSFFit((int)x, (int)y, PSFFittingMethod.NonLinearFit, out psfFit); } //else if (m_FitSettings.CenterDetectionMethod == StarCenterDetection.Centroid) { // NOTE: Centroid detection is way faster and PSF will not lead to big improvement considering the threshold for star matching //pixel = m_StarMap.GetCentroid((int)x, (int)y, (int)Math.Ceiling(m_Settings.SearchArea)); } if (pixel != null && psfFit.Certainty >= CorePyramidConfig.Default.MinDetectionLimitForSolutionImprovement / coeff) { consideredStars.Add(star); double distance = fit.GetDistanceInArcSec(pixel.XDouble, pixel.YDouble, x, y); if (distance < CorePyramidConfig.Default.MaxPreliminaryResidualForSolutionImprovement / coeff) { #if ASTROMETRY_DEBUG Trace.Assert(!double.IsNaN(pixel.XDouble)); Trace.Assert(!double.IsNaN(pixel.YDouble)); #endif if ( Math.Sqrt((x - pixel.XDouble) * (x - pixel.XDouble) + (y - pixel.YDouble) * (y - pixel.YDouble)) > CoreAstrometrySettings.Default.SearchArea) continue; pixel.SignalNoise = psfFit.Certainty; pixel.Brightness = psfFit.Brightness; m_SolutionSolver.AddStar(pixel, star); if (m_Settings.PyramidRemoveNonStellarObject && ( asymPsfFit.FWHM < m_Settings.MinReferenceStarFWHM || asymPsfFit.FWHM > m_Settings.MaxReferenceStarFWHM || asymPsfFit.ElongationPercentage > m_Settings.MaximumPSFElongation) ) { nonStellarStars.Add(star.StarNo); } } } } double ffl = fit.FitInfo.FittedFocalLength; m_ImprovedSolution = m_SolutionSolver.SolveWithLinearRegression(m_Settings, out m_FirstImprovedSolution); //if (m_ImprovedSolution != null && m_ImprovedSolution.FitInfo.AllStarPairs.Count < 12) //{ // // Attempt to reject errorous solutions with small number of fitted stars // int totalMatched = 0; // var largeFeatures = m_StarMap.Features.Where(x => x.MaxBrightnessPixels > 1).ToList(); // if (largeFeatures.Count > 5) // { // foreach (var feature in largeFeatures) // { // var ftrCenter = feature.GetCenter(); // // TODO: PFS Fit on the feature? // var matchedFittedStar = m_ImprovedSolution.FitInfo.AllStarPairs.FirstOrDefault( // x => // Math.Sqrt(Math.Pow(x.x - ftrCenter.XDouble, 2) + Math.Pow(x.x - ftrCenter.XDouble, 2)) < // 2); // if (matchedFittedStar != null) totalMatched++; // } // double percentLargeFeaturesMatched = 1.0*totalMatched/largeFeatures.Count; // if (percentLargeFeaturesMatched < 0.75) // { // if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceInfo()) // Trace.WriteLine(string.Format("Only {0:0.0}% ({1} features) of the large {2} features have been matched, where 75% is required.", percentLargeFeaturesMatched*100, totalMatched, largeFeatures.Count)); // // At least 75% of the bright features from the video need to be matched to stars for the solution to be accepted // m_ImprovedSolution = null; // } // } //} if (m_ImprovedSolution != null) { m_ImprovedSolution.FitInfo.FittedFocalLength = ffl; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceWarning()) Trace.WriteLine(string.Format("Improved solution: {0} considered stars, UsedInSolution: {1}, ExcludedForHighResidual: {2}", m_ImprovedSolution.FitInfo.AllStarPairs.Count(), m_ImprovedSolution.FitInfo.AllStarPairs.Count(x => x.FitInfo.UsedInSolution), m_ImprovedSolution.FitInfo.AllStarPairs.Count(x => x.FitInfo.ExcludedForHighResidual))); // Fit was successful, exclude all unused non stellar objects so they // don't interfere with the included/excluded stars improved solution tests m_ImprovedSolution.FitInfo.AllStarPairs.RemoveAll(p => (p.FitInfo.ExcludedForHighResidual || !p.FitInfo.UsedInSolution) && nonStellarStars.Contains(p.StarNo)); // NOTE: How excluding stars for FWHM/Elongation may lead to incorrectly accepted solutions that include small number of stars // because the majority haven't been used for the fit. This is why we have another solution check here. if (m_ImprovedSolution.FitInfo.AllStarPairs.Count > 3) { List<PlateConstStarPair> usedStarPairs = m_ImprovedSolution.FitInfo.AllStarPairs.Where(p => p.FitInfo.UsedInSolution).ToList(); double maxIncludedMag = usedStarPairs.Max(p => p.Mag); int nonIncludedConsideredStars = consideredStars.Count(s => s.Mag <= maxIncludedMag) - usedStarPairs.Count; if (nonIncludedConsideredStars > CorePyramidConfig.Default.MaxFWHMExcludedImprovemntStarsCoeff * usedStarPairs.Count) { LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("More than {0:0.0}% of the stars ({1} stars) down to mag {2:0.00} have not been matched. Attempted stars: {3}, Coeff: {4:0.00}", CorePyramidConfig.Default.MaxFWHMExcludedImprovemntStarsCoeff * 100, nonIncludedConsideredStars, maxIncludedMag, m_SolutionSolver.Pairs.Count, nonIncludedConsideredStars / m_SolutionSolver.Pairs.Count)); m_ImprovedSolution = null; return; } List<double> intensities = usedStarPairs.Select(s => (double)s.Intensity).ToList(); List<double> mags = usedStarPairs.Select(s => s.Mag).ToList(); if (usedStarPairs.Count > 3) { LinearRegression reg = new LinearRegression(); int pointsAdded = 0; for (int ii = 0; ii < intensities.Count; ii++) { if (intensities[ii] > 0) { reg.AddDataPoint(intensities[ii], Math.Log10(mags[ii])); pointsAdded++; } } if (pointsAdded > 3) { reg.Solve(); if (Math.Pow(10, reg.StdDev) > CorePyramidConfig.Default.MagFitTestMaxStdDev || reg.A > CorePyramidConfig.Default.MagFitTestMaxInclination) { LogUnsuccessfulFitImage(m_ImprovedSolution, i, j, k, string.Format("Failing solution for failed magnitude fit. Intensity(Log10(Magntude)) = {1} * x + {2}, StdDev = {0:0.0000}, ChiSquare = {3:0.000}", Math.Pow(10, reg.StdDev), reg.A, reg.B, reg.ChiSquare)); m_ImprovedSolution = null; return; } } } } } }
public int AstroAnalogueVideoNormaliseNtpDataIfNeeded(Action<int> progressCallback, out float oneSigmaError) { int ntpError = -1; oneSigmaError = float.NaN; if (NtpDataAvailable && !OcrDataAvailable && !m_UseNtpTimeAsCentralExposureTime) { if (m_CountFrames > 1 /* No Timestamp for first frame */ + 1 /* No Timestamp for last frame*/ + 3 /* Minimum timestamped frames for a FIT */) { try { double frameDurationMilliseconds = 1000 / m_FrameRate; var lr = new LinearRegression(); long zeroPointTicks = -1; int percentDone = 0; int percentDoneCalled = 0; if (progressCallback != null) progressCallback(percentDone); long ntpTimestampErrorSum = 0; int ntpTimestampErrorDatapoints = 0; for (int i = m_FirstFrame; i < m_FirstFrame + m_CountFrames; i++) { FrameStateData stateChannel = GetFrameStatusChannel(i); if (stateChannel.HasValidNtpTimeStamp) { long centralTicks = stateChannel.EndFrameNtpTime.AddMilliseconds(-0.5 * frameDurationMilliseconds).Ticks; if (zeroPointTicks == -1) zeroPointTicks = centralTicks; lr.AddDataPoint(i, new TimeSpan(centralTicks - zeroPointTicks).TotalMilliseconds); ntpTimestampErrorSum += stateChannel.NtpTimeStampError; ntpTimestampErrorDatapoints++; } percentDone = 100 * (i - m_FirstFrame) / m_CountFrames; if (progressCallback != null && percentDone - percentDoneCalled> 5) { progressCallback(percentDone); percentDoneCalled = percentDone; } } if (lr.NumberOfDataPoints > 3) { lr.Solve(); m_CalibratedNtpTimeZeroPoint = zeroPointTicks; m_CalibratedNtpTimeSource = lr; m_UseNtpTimeAsCentralExposureTime = true; m_NtpTimeFitSigma = lr.StdDev; m_NtpTimeAverageNetworkError = (ntpTimestampErrorSum * 1.0 / ntpTimestampErrorDatapoints); ntpError = (int)Math.Round(m_NtpTimeFitSigma + m_NtpTimeAverageNetworkError); Trace.WriteLine(string.Format("NTP Timebase Established. 1-Sigma = {0} ms", lr.StdDev.ToString("0.00"))); oneSigmaError = (float)m_NtpTimeFitSigma; } progressCallback(100); } catch (Exception ex) { Trace.WriteLine(ex.GetFullStackTrace()); } } } return ntpError; }
private void LinearFitOfAveragedModel(uint[,] intensity) { if (m_BackgroundModel != null) throw new NotSupportedException("Background modelling cannot be used directly with linear fit of average model."); // First do a non linear fit to find X0 and Y0 NonLinearFit(intensity, false); if (m_IsSolved) { // Then do a linear fit to find IBackground and IStarMax // I(x, y) = IBackground + IStarMax * Exp ( -((x - X0)*(x - X0) + (y - Y0)*(y - Y0)) / (r0 * r0)) LinearRegression linearFit = new LinearRegression(); double modelR = m_ModelFWHM/(2*Math.Sqrt(Math.Log(2))); double modelRSquare = modelR*modelR; double[,] modelData = new double[m_MatrixSize, m_MatrixSize]; for (int x = 0; x < m_MatrixSize; x++) for (int y = 0; y < m_MatrixSize; y++) { double modelVal = Math.Exp(-((x - X0)*(x - X0) + (y - Y0)*(y - Y0))/(modelRSquare)); modelData[x, y] = modelVal; linearFit.AddDataPoint(modelVal, intensity[x, y]); } linearFit.Solve(); for (int x = 0; x < m_MatrixSize; x++) for (int y = 0; y < m_MatrixSize; y++) { m_Residuals[x, y] = intensity[x, y] - linearFit.ComputeY(modelData[x, y]); } m_IBackground = linearFit.B; m_IStarMax = linearFit.A; m_R0 = modelR; } }
private void PerformLinearFitReadingsNormalisation(ref List<double> normalIndexes) { var linearRegression = new LinearRegression(); foreach (LCMeasurement reading in m_LightCurveController.Context.AllReadings[m_LightCurveController.Context.Normalisation]) { if (reading.IsSuccessfulReading) linearRegression.AddDataPoint(reading.CurrFrameNo, reading.AdjustedReading); } linearRegression.Solve(); double firstValue = linearRegression.ComputeY(m_LightCurveController.Context.AllReadings[m_LightCurveController.Context.Normalisation][0].CurrFrameNo); foreach (LCMeasurement reading in m_LightCurveController.Context.AllReadings[m_LightCurveController.Context.Normalisation]) { normalIndexes.Add(firstValue / linearRegression.ComputeY(reading.CurrFrameNo)); } }
private void PerformLinearFitBinnedNormalisation(ref List<double> normalIndexes) { var linearRegression = new LinearRegression(); foreach (BinnedValue binnedValue in m_AllBinnedReadings[m_LightCurveController.Context.Normalisation]) { if (binnedValue.IsSuccessfulReading) linearRegression.AddDataPoint(binnedValue.BinNo, binnedValue.AdjustedValue); } linearRegression.Solve(); double firstValue = linearRegression.ComputeY(m_AllBinnedReadings[m_LightCurveController.Context.Normalisation][0].BinNo); foreach (BinnedValue binnedValue in m_AllBinnedReadings[m_LightCurveController.Context.Normalisation]) { normalIndexes.Add(firstValue / linearRegression.ComputeY(binnedValue.BinNo)); } }