Exemple #1
0
        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;
        }
Exemple #9
0
        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));
            }
        }