public ProcessingReturnValues FitAndPlotFastFlyby( Dictionary <int, SingleMultiFrameMeasurement> measurements, FlybyMeasurementContext meaContext, FittingContext fittingContext, FittingValue fittingValue, GetFrameStateDataCallback getFrameStateDataCallback, Graphics g, FlybyPlottingContext plottingContext, float xScale, float yScale, int imageWidth, int imageHeight, out double motionRate) { // Do linear regression, use residual based exclusion rules // Two possible modes: (A) non trailed and (B) trailed images // A) Non Trailed Images // Report interpolated times for video normal position [How to use the MPC page for this?] // Don't forget to add the video normal position flag in the OBS file // Expect elongated images and apply instrumental delay corrections (in both integrated and non integrated modes) // B) Trailed Images // TODO: R&D Required if (fittingContext.ObjectExposureQuality == ObjectExposureQuality.GoodSignal) { return(FitAndPlotSlowFlyby( measurements, meaContext, fittingContext, fittingValue, getFrameStateDataCallback, g, plottingContext, xScale, yScale, imageWidth, imageHeight, out motionRate)); } else { MessageBox.Show("This operation is currently not suppored."); motionRate = double.NaN; return(new ProcessingReturnValues()); } }
public ProcessingReturnValues FitAndPlotSlowMotion( Dictionary<int, SingleMultiFrameMeasurement> measurements, FlybyMeasurementContext meaContext, GetProcessingValueCallback getValueCallback, Graphics g, FlybyPlottingContext plottingContext, float xScale, float yScale, int imageWidth) { // Compute median, use median based exclusion rules // Report the median position for the time at the middle of the measured interval // Do not expect elongated image (no corrections from the exposure) // May apply instrumental delay corrections for the frame time var rv = new ProcessingReturnValues(); double sum = 0; double userSum = 0; double stdDevUserSum = 0; int numFramesUser = 0; double userMidFrom = meaContext.UserMidValue - meaContext.MaxStdDev; double userMidTo = meaContext.UserMidValue + meaContext.MaxStdDev; rv.EarliestFrame = int.MaxValue; rv.LatestFrame = int.MinValue; List<double> medianList = new List<double>(); foreach (SingleMultiFrameMeasurement measurement in measurements.Values) { float x = (measurement.FrameNo - meaContext.MinFrameNo) * xScale + 5; ProcessingValues val = getValueCallback(measurement); 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; sum += val.Value; Pen mPen = plottingContext.IncludedPen; if (!double.IsNaN(meaContext.UserMidValue)) { if ((valueFrom >= userMidFrom && valueFrom <= userMidTo) || (valueTo >= userMidFrom && valueTo <= userMidTo)) { numFramesUser++; userSum += val.Value; medianList.Add(val.Value); stdDevUserSum += val.StdDev * val.StdDev; if (rv.EarliestFrame > measurement.FrameNo) rv.EarliestFrame = measurement.FrameNo; if (rv.LatestFrame < measurement.FrameNo) rv.LatestFrame = measurement.FrameNo; } else mPen = plottingContext.ExcludedPen; } g.DrawLine(mPen, x, yFrom, x, yTo); g.DrawLine(mPen, x - 1, yFrom, x + 1, yFrom); g.DrawLine(mPen, x - 1, yTo, x + 1, yTo); } if (!double.IsNaN(meaContext.UserMidValue) && numFramesUser > 0) { double average = userSum / numFramesUser; double err = Math.Sqrt(stdDevUserSum) / (numFramesUser - 1); float yAve = (float)(average - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.AveragePen, 5, yAve - 1, imageWidth - 5, yAve - 1); g.DrawLine(plottingContext.AveragePen, 5, yAve, imageWidth - 5, yAve); g.DrawLine(plottingContext.AveragePen, 5, yAve + 1, imageWidth - 5, yAve + 1); float yMin = (float)(userMidFrom - plottingContext.MinValue) * yScale + 5; float yMax = (float)(userMidTo - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.AveragePen, 5, yMin, imageWidth - 5, yMin); g.DrawLine(plottingContext.AveragePen, 5, yMax, imageWidth - 5, yMax); // TODO: Use weighted median double median = 0; medianList.Sort(); if (numFramesUser % 2 == 1) median = medianList[numFramesUser / 2]; else median = (medianList[numFramesUser / 2] + medianList[(numFramesUser / 2) - 1]) / 2; Trace.WriteLine(string.Format("{0}; Included: {1}; Average: {2}; Median: {3}", meaContext.UserMidValue.ToString("0.00000"), numFramesUser, AstroConvert.ToStringValue(average, "+HH MM SS.T"), AstroConvert.ToStringValue(median, "+HH MM SS.T"))); rv.FittedValue = median; // TODO: Use StdDev/SQRT(N) rv.FittedValueUncertaintyArcSec = TangraConfig.Settings.Astrometry.AssumedPositionUncertaintyPixels * meaContext.ArsSecsInPixel; rv.IsVideoNormalPosition = false; } else { double average = sum / measurements.Count; float yAve = (float)(average - plottingContext.MinValue) * yScale + 5; g.DrawLine(Pens.WhiteSmoke, 5, yAve, imageWidth - 5, yAve); rv.FittedValue = double.NaN; } return rv; }
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; } }
public ProcessingReturnValues FitAndPlotFastFlyby( Dictionary<int, SingleMultiFrameMeasurement> measurements, FlybyMeasurementContext meaContext, FittingContext fittingContext, FittingValue fittingValue, GetFrameStateDataCallback getFrameStateDataCallback, Graphics g, FlybyPlottingContext plottingContext, float xScale, float yScale, int imageWidth, int imageHeight, out double motionRate) { // Do linear regression, use residual based exclusion rules // Two possible modes: (A) non trailed and (B) trailed images // A) Non Trailed Images // Report interpolated times for video normal position [How to use the MPC page for this?] // Don't forget to add the video normal position flag in the OBS file // Expect elongated images and apply instrumental delay corrections (in both integrated and non integrated modes) // B) Trailed Images // TODO: R&D Required if (fittingContext.ObjectExposureQuality == ObjectExposureQuality.GoodSignal) { return FitAndPlotSlowFlyby( measurements, meaContext, fittingContext, fittingValue, getFrameStateDataCallback, g, plottingContext, xScale, yScale, imageWidth, imageHeight, out motionRate); } else { MessageBox.Show("This operation is currently not suppored."); motionRate = double.NaN; return new ProcessingReturnValues(); } }
public ProcessingReturnValues FitAndPlotSlowMotion( Dictionary <int, SingleMultiFrameMeasurement> measurements, FlybyMeasurementContext meaContext, GetProcessingValueCallback getValueCallback, Graphics g, FlybyPlottingContext plottingContext, float xScale, float yScale, int imageWidth) { // Compute median, use median based exclusion rules // Report the median position for the time at the middle of the measured interval // Do not expect elongated image (no corrections from the exposure) // May apply instrumental delay corrections for the frame time var rv = new ProcessingReturnValues(); double sum = 0; double userSum = 0; double stdDevUserSum = 0; int numFramesUser = 0; double userMidFrom = meaContext.UserMidValue - meaContext.MaxStdDev; double userMidTo = meaContext.UserMidValue + meaContext.MaxStdDev; rv.EarliestFrame = int.MaxValue; rv.LatestFrame = int.MinValue; List <double> medianList = new List <double>(); List <double> medianWeightsList = new List <double>(); var minPosUncertaintyArcSec = TangraConfig.Settings.Astrometry.AssumedPositionUncertaintyPixels * meaContext.ArsSecsInPixel; foreach (SingleMultiFrameMeasurement measurement in measurements.Values) { float x = (measurement.FrameNo - meaContext.MinFrameNo) * xScale + 5; ProcessingValues val = getValueCallback(measurement); 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; sum += val.Value; Pen mPen = plottingContext.IncludedPen; if (!double.IsNaN(meaContext.UserMidValue)) { if ((valueFrom >= userMidFrom && valueFrom <= userMidTo) || (valueTo >= userMidFrom && valueTo <= userMidTo)) { numFramesUser++; userSum += val.Value; medianList.Add(val.Value); medianWeightsList.Add(ComputePositionWeight(val.StdDev, measurement, minPosUncertaintyArcSec, WeightingMode.SNR)); stdDevUserSum += val.StdDev * val.StdDev; if (rv.EarliestFrame > measurement.FrameNo) { rv.EarliestFrame = measurement.FrameNo; } if (rv.LatestFrame < measurement.FrameNo) { rv.LatestFrame = measurement.FrameNo; } } else { mPen = plottingContext.ExcludedPen; } } g.DrawLine(mPen, x, yFrom, x, yTo); g.DrawLine(mPen, x - 1, yFrom, x + 1, yFrom); g.DrawLine(mPen, x - 1, yTo, x + 1, yTo); } if (!double.IsNaN(meaContext.UserMidValue) && numFramesUser > 0) { double average = userSum / numFramesUser; double err = Math.Sqrt(stdDevUserSum) / (numFramesUser - 1); float yAve = (float)(average - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.AveragePen, 5, yAve - 1, imageWidth - 5, yAve - 1); g.DrawLine(plottingContext.AveragePen, 5, yAve, imageWidth - 5, yAve); g.DrawLine(plottingContext.AveragePen, 5, yAve + 1, imageWidth - 5, yAve + 1); float yMin = (float)(userMidFrom - plottingContext.MinValue) * yScale + 5; float yMax = (float)(userMidTo - plottingContext.MinValue) * yScale + 5; g.DrawLine(plottingContext.AveragePen, 5, yMin, imageWidth - 5, yMin); g.DrawLine(plottingContext.AveragePen, 5, yMax, imageWidth - 5, yMax); double median; double medianWeight; WeightedMedian(Tuple.Create(medianList, medianWeightsList), out median, out medianWeight); double standardMedian = medianList.Median(); Trace.WriteLine(string.Format("{0}; Included: {1}; Average: {2}; Wighted Median: {3}; Standard Median: {4}", meaContext.UserMidValue.ToString("0.00000"), numFramesUser, AstroConvert.ToStringValue(average, "+HH MM SS.TTT"), AstroConvert.ToStringValue(median, "+HH MM SS.TTT"), AstroConvert.ToStringValue(standardMedian, "+HH MM SS.TTT"))); rv.FittedValue = median; var stdDevArcSec = 3600 * Math.Sqrt(medianList.Sum(x => (x - median) * (x - median)) / (medianList.Count - 1)); var tCoeff95 = TDistribution.CalculateCriticalValue(medianList.Count, (1 - 0.95), 0.0001); var error95 = 1.253 * tCoeff95 * stdDevArcSec / Math.Sqrt(medianList.Count); rv.FittedValueUncertaintyArcSec = error95; rv.IsVideoNormalPosition = false; } else { double average = sum / measurements.Count; float yAve = (float)(average - plottingContext.MinValue) * yScale + 5; g.DrawLine(Pens.WhiteSmoke, 5, yAve, imageWidth - 5, yAve); rv.FittedValue = double.NaN; } return(rv); }
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 when integration is used or no correction when integration of x1 is used. double dataPointFrameNo = rv.EarliestFrame + fittingContext.IntegratedFramesCount * integratedFrameNo + (fittingContext.IntegratedFramesCount / 2) - (fittingContext.IntegratedFramesCount > 1 ? 0.5 : 0); 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.FrameTimeStamp); var lastTime = GetTimeForFrame(fittingContext, rv.LatestFrame, meaContext.FirstVideoFrame, getFrameStateDataCallback, lastPos.FrameTimeStamp); 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].FrameTimeStamp); #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 ProcessingReturnValues DrawRAPanel() { ProcessingReturnValues retVal = null; using (Graphics g = Graphics.FromImage(m_RAImage)) { g.Clear(Color.Gray); int midY = m_RAImage.Height / 2; g.DrawLine(Pens.DarkGray, 5, midY, m_RAImage.Width - 5, midY); int minFrame = m_AllMeasurements.Keys.Min(); int maxFrame = m_AllMeasurements.Keys.Max(); int frames = 1 + maxFrame - minFrame; if (m_AllMeasurements.Count > 0) { float xScale = m_RAImage.Width * 1.0f / frames; float yScale = (m_RAImage.Height - 10) / (float)(m_MaxRA - m_MinRA); double from = m_MinRA - (6 / 3600.0); double to = m_MaxRA + (6 / 3600.0); double curr = Math.Truncate((from * 3600.0) / 5) * 5 / (3600.0); while (curr < to) { float y = (float)(curr - m_MinRA) * yScale + 5; g.DrawLine(s_SecondLinesPen, 5, y, m_RAImage.Width - 5, y); curr += (1 / 3600.0); } var meaContext = new FlybyMeasurementContext { UserMidValue = m_UserRAMid, UserMidFrame = m_UserFrame, MaxStdDev = m_MeasurementContext.MaxStdDev/3600.0, FirstVideoFrame = m_VideoController.VideoFirstFrame, ArsSecsInPixel = m_AstrometryController.GetCurrentAstroPlate().GetDistanceInArcSec(0, 0, 1, 1), MinPositionUncertaintyPixels = TangraConfig.Settings.Astrometry.AssumedPositionUncertaintyPixels, MinFrameNo = minFrame, MaxFrameNo = maxFrame }; var fittingContext = m_MeasurementContext.ToFittingContext(); fittingContext.Weighting = TangraConfig.Settings.Astrometry.MotionFitWeightingMode; var plottingContext = new FlybyPlottingContext { MinValue = m_MinRA, IncludedPen = Pens.SkyBlue, ExcludedPen = Pens.Tomato, AveragePen = s_RAAveragePen, }; #region Compute the RA or DE value at the middle of the interval GetProcessingValueCallback processingValueCallback = delegate(SingleMultiFrameMeasurement measurement) { return new ProcessingValues { StdDev = measurement.StdDevRAArcSec / 3600.0, Value = measurement.RADeg }; }; switch (m_MeasurementContext.MovementExpectation) { case MovementExpectation.Slow: retVal = m_FlyByMotionFitter.FitAndPlotSlowMotion( m_AllMeasurements, meaContext, processingValueCallback, g, plottingContext, xScale, yScale, m_RAImage.Width); break; case MovementExpectation.SlowFlyby: double motionRate; retVal = m_FlyByMotionFitter.FitAndPlotSlowFlyby( m_AllMeasurements, meaContext, fittingContext, FittingValue.RA, (frameId) => m_AstrometryController.GetFrameTimeInfo(frameId), g, plottingContext, xScale, yScale, m_RAImage.Width, m_RAImage.Height, out motionRate); m_MotionRate = motionRate; break; case MovementExpectation.FastFlyby: retVal = m_FlyByMotionFitter.FitAndPlotFastFlyby( m_AllMeasurements, meaContext, fittingContext, FittingValue.RA, (frameId) => m_AstrometryController.GetFrameTimeInfo(frameId), g, plottingContext, xScale, yScale, m_RAImage.Width, m_RAImage.Height, out motionRate); break; default: throw new IndexOutOfRangeException(); } #endregion if (retVal != null) { m_EarliestDEFrame = retVal.EarliestFrame; m_LatestDEFrame = retVal.LatestFrame; if (!double.IsNaN(retVal.FittedValue)) { lblAstRA.Text = string.Format("{0}", AstroConvert.ToStringValue(retVal.FittedValue / 15, "HH MM SS.TT")); lblAlpha.Visible = true; m_RADeg = retVal.FittedValue; m_RAUncertaintyArcSec = retVal.FittedValueUncertaintyArcSec; if (TangraConfig.Settings.Astrometry.ExportUncertainties) m_MPCRAUncertainty = retVal.FittedValueUncertaintyArcSec; lblAstUncertainty.Text = string.Format("({0:0.00}, {1:0.00})\"", m_RAUncertaintyArcSec * Math.Cos(m_DEDeg * Math.PI / 180), m_DEUncertaintyArcSec); lblUncert.Visible = true; m_MPCRAHours = m_RADeg / 15; m_MPCTime = retVal.FittedValueTime; m_MPCTimePrecission = TimeSpan.MinValue; m_MPCIsVideoNormalPosition = retVal.IsVideoNormalPosition; } CheckAndSetTimeAndMPCAdd(); } } g.DrawString("a", s_SymbolFont12, Brushes.Yellow, 5, 5); g.Save(); } pnlRASeries.Image = m_RAImage; if (m_AstrometricState.MeasuringState != AstrometryInFramesState.RunningMeasurements) pnlRASeries.Refresh(); return retVal; }