public double GetDistanceInArcSec(double distanceInPixels) { double dxRad = (distanceInPixels) * EffectivePixelWidth / (EffectiveFocalLength * 1000.0); double dyRad = (distanceInPixels) * EffectivePixelHeight / (EffectiveFocalLength * 1000.0); return(AngleUtility.Elongation(0, 0, dxRad * 180 / Math.PI, dyRad * 180 / Math.PI) * 3600.0); }
public double GetDistanceInArcSec(double x1, double y1, double x2, double y2, double effectiveFocalLength) { double dxRad = (x1 - x2) * EffectivePixelWidth / (effectiveFocalLength * 1000.0); double dyRad = (y1 - y2) * EffectivePixelHeight / (effectiveFocalLength * 1000.0); return(AngleUtility.Elongation(0, 0, dxRad * 180 / Math.PI, dyRad * 180 / Math.PI) * 3600.0); }
public double GetDistanceInArcSec(double x1, double y1, double x2, double y2) { double ra1, de1, ra2, de2; GetRADEFromImageCoords(x1, y1, out ra1, out de1); GetRADEFromImageCoords(x2, y2, out ra2, out de2); return(AngleUtility.Elongation(ra1, de1, ra2, de2) * 3600.0); }
public double GetMaxFOVInArcSec() { if (double.IsNaN(EffectiveFocalLength)) { throw new InvalidOperationException("EffectiveFocalLength must be set before computing MaxFOVInDeg"); } double dxRad = m_ImageWidth * EffectivePixelWidth / (EffectiveFocalLength * 1000.0); double dyRad = m_ImageHeight * EffectivePixelHeight / (EffectiveFocalLength * 1000.0); return(AngleUtility.Elongation(0, 0, dxRad * 180 / Math.PI, dyRad * 180 / Math.PI) * 3600.0); }
internal IIdentifiedObject GetIdentifiedObjectAt(double raDeg, double deDeg) { foreach (IIdentifiedObject entry in m_IdentifiedObjects) { double distance = AngleUtility.Elongation(raDeg, deDeg, entry.RAHours * 15, entry.DEDeg); if (distance < CoreAstrometrySettings.Default.IdentifiedObjectResidualInArcSec) { return(entry); } } return(null); }
private void GenerateSimulatedVideo(object state) { InvokeUpdateUI(2, 0, true); try { ModelConfig modelConfig = (ModelConfig)state; modelConfig.MaxPixelValue = modelConfig.IsAAVFile ? (uint)modelConfig.Integration * 255 : 255; double dxRad = modelConfig.FrameWidth * modelConfig.PlatePixWidth / (modelConfig.PlateFocLength * 1000.0); double dyRad = modelConfig.FrameHeight * modelConfig.PlatePixHeight / (modelConfig.PlateFocLength * 1000.0); double fovDeg = AngleUtility.Elongation(0, 0, dxRad * 180 / Math.PI, dyRad * 180 / Math.PI); var catFac = new StarCatalogueFacade(TangraConfig.Settings.StarCatalogue); List <IStar> stars = catFac.GetStarsInRegion(m_RA * 15, m_DE, 2 * fovDeg, modelConfig.LimitStarMag, 2000); if (modelConfig.IsAAVFile) { GenerateAAVVideo(modelConfig, stars); } else { GenerateAVIVideo(modelConfig, stars); } if (modelConfig.DarkFrameMean > 0 && cbxPhotometricFilter != null) { // Save the dark frame float[,] averagedFrame = new float[modelConfig.FrameWidth, modelConfig.FrameHeight]; for (int x = 0; x < modelConfig.FrameWidth; x++) { for (int y = 0; y < modelConfig.FrameHeight; y++) { averagedFrame[x, y] = m_SimulatedDarkFrame[x, y]; } } InvokeSaveDarkFrame(modelConfig, averagedFrame); } } finally { InvokeUpdateUI(2, 100, false); } }
public void NextFrame(int frameNo, IAstroImage astroImage, IStarMap starMap, LeastSquareFittedAstrometry astrometricFit) { IsTrackedSuccessfully = false; ImagePixel centroid = AstrometryContext.Current.StarMap.GetCentroid( (int)TrackedObject.LastKnownX, (int)TrackedObject.LastKnownY, CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius); if (centroid != null) { PSFFit psfFit; AstrometryContext.Current.StarMap.GetPSFFit( centroid.X, centroid.Y, PSFFittingMethod.NonLinearFit, out psfFit); if (psfFit != null) { double ra, de; astrometricFit.GetRADEFromImageCoords(psfFit.XCenter, psfFit.YCenter, out ra, out de); double maxPosDiffArcSec = astrometricFit.GetDistanceInArcSec(astrometricFit.Image.CenterXImage, astrometricFit.Image.CenterYImage, astrometricFit.Image.CenterXImage + CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius, astrometricFit.Image.CenterYImage); if (!double.IsNaN(TrackedObject.RAHours)) { double posDif = 3600 * AngleUtility.Elongation(15 * TrackedObject.RAHours, TrackedObject.DEDeg, ra, de); if (posDif > maxPosDiffArcSec) { // NOTE: Not a valid measurement Trace.WriteLine(string.Format("The target position is too far from the last measured position", posDif)); return; } } TrackedObject.RAHours = ra / 15.0; TrackedObject.DEDeg = de; TrackedObject.LastKnownX = psfFit.XCenter; TrackedObject.LastKnownY = psfFit.YCenter; TrackedObject.PSFFit = psfFit; IsTrackedSuccessfully = true; } } }
internal AbsFluxSpectra(AbsFluxInputFile inputFile) { InputFile = inputFile; IsComplete = false; if (!string.IsNullOrEmpty(inputFile.Target)) { // First try to read the target from the export m_DisplayName = inputFile.Target; m_ExtractedStarName = null; } else { // Then try to parse the star from the file Match match = STAR_DESIGNATION_REGEX.Match(inputFile.FileName); if (match.Success && !string.IsNullOrEmpty(match.Value)) { m_ExtractedStarName = match.Value.Replace('_', ' ').Replace(" ", " ").Trim(); m_DisplayName = m_ExtractedStarName; } } HasObjectCoordinates = !float.IsNaN(inputFile.Latitude) && !float.IsNaN(inputFile.Longitude) && !float.IsNaN(inputFile.RAHours) && !float.IsNaN(inputFile.DEDeg); HasObservationTime = inputFile.Epoch != DateTime.MinValue; if (HasObservationTime && HasObjectCoordinates) { // If we have the center of the field saved in the export then identify the standard star by the position List <CalSpecStar> standardsInOneDegreeRadius = CalSpecDatabase.Instance.Stars.Where(x => AngleUtility.Elongation(x.RA_J2000_Hours * 15, x.DE_J2000_Deg, InputFile.RAHours * 15, InputFile.DEDeg) < 1).ToList(); if (standardsInOneDegreeRadius.Count == 1) { m_CalSpecStar = standardsInOneDegreeRadius[0]; m_DisplayName = m_CalSpecStar.AbsFluxStarId; IsComplete = true; PlotSpectra = true; } } if (inputFile.Epoch > DateTime.MinValue) { m_DisplayName += string.Format(" ({0} UT)", inputFile.Epoch.ToString("HH:mm")); } if (string.IsNullOrEmpty(m_DisplayName)) { m_DisplayName = Path.GetFileNameWithoutExtension(inputFile.FileName); } DataFromWavelength = (int)Math.Ceiling(inputFile.Wavelengths[0]); DataFromWavelength = (int)Math.Floor(inputFile.Wavelengths[inputFile.Wavelengths.Count - 1]); }
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 bool LeastSquareSolve(double ra0Deg, double de0Deg, int minNumberOfStars) { int[] NUM_CONSTANTS = new int[] { 3, 6, 10 }; SafeMatrix A = new SafeMatrix(m_StarPairs.Count, NUM_CONSTANTS[(int)m_FitOrder]); SafeMatrix X = new SafeMatrix(m_StarPairs.Count, 1); SafeMatrix Y = new SafeMatrix(m_StarPairs.Count, 1); SafeMatrix AReverse = new SafeMatrix(m_StarPairs.Count, NUM_CONSTANTS[(int)m_FitOrder]); SafeMatrix XReverse = new SafeMatrix(m_StarPairs.Count, 1); SafeMatrix YReverse = new SafeMatrix(m_StarPairs.Count, 1); int numStars = 0; for (int i = 0; i < m_StarPairs.Count; i++) { m_StarPairs[i].FitInfo.UsedInSolution = false; if (m_StarPairs[i].FitInfo.ExcludedForHighResidual) { continue; } numStars++; m_StarPairs[i].FitInfo.UsedInSolution = true; ConfigureObservation(A, AReverse, i); X[i, 0] = m_StarPairs[i].ExpectedXTang; Y[i, 0] = m_StarPairs[i].ExpectedYTang; XReverse[i, 0] = m_StarPairs[i].x; YReverse[i, 0] = m_StarPairs[i].y; } // Insufficient stars to solve the plate if (numStars < minNumberOfStars) { if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Debug.WriteLine(string.Format("Insufficient number of stars to do a fit. At least {0} stars requested.", minNumberOfStars)); } return(false); } SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; SafeMatrix by = (aa_inv * a_T) * Y; if (ReadSolvedConstants(bx, by)) { a_T = AReverse.Transpose(); aa = a_T * AReverse; aa_inv = aa.Inverse(); bx = (aa_inv * a_T) * XReverse; by = (aa_inv * a_T) * YReverse; ReadSolvedReversedConstants(bx, by); } double residualSum = 0; double residualSumArcSecRA = 0; double residualSumArcSecDE = 0; int numResiduals = 0; var absResRAArcSec = new List <double>(); var absResDEArcSec = new List <double>(); for (int i = 0; i < m_StarPairs.Count; i++) { double computedXTang, computedYTang; GetTangentCoordsFromImageCoords(m_StarPairs[i].x, m_StarPairs[i].y, out computedXTang, out computedYTang); m_StarPairs[i].FitInfo.ResidualXTang = m_StarPairs[i].ExpectedXTang - computedXTang; m_StarPairs[i].FitInfo.ResidualYTang = m_StarPairs[i].ExpectedYTang - computedYTang; double raComp, deComp; TangentPlane.TangentToCelestial(computedXTang, computedYTang, ra0Deg, de0Deg, out raComp, out deComp); m_StarPairs[i].FitInfo.ResidualRAArcSec = 3600.0 * AngleUtility.Elongation(m_StarPairs[i].RADeg, 0, raComp, 0); m_StarPairs[i].FitInfo.ResidualDEArcSec = 3600.0 * AngleUtility.Elongation(0, m_StarPairs[i].DEDeg, 0, deComp); if (!m_StarPairs[i].FitInfo.UsedInSolution) { continue; } numResiduals++; residualSum += Math.Abs(m_StarPairs[i].FitInfo.ResidualXTang * m_StarPairs[i].FitInfo.ResidualYTang); residualSumArcSecRA += m_StarPairs[i].FitInfo.ResidualRAArcSec * m_StarPairs[i].FitInfo.ResidualRAArcSec; residualSumArcSecDE += m_StarPairs[i].FitInfo.ResidualDEArcSec * m_StarPairs[i].FitInfo.ResidualDEArcSec; absResRAArcSec.Add(Math.Abs(m_StarPairs[i].FitInfo.ResidualRAArcSec)); absResDEArcSec.Add(Math.Abs(m_StarPairs[i].FitInfo.ResidualDEArcSec)); } Variance = residualSum / (numResiduals - 1); VarianceArcSecRA = residualSumArcSecRA / (numResiduals - 1); VarianceArcSecDE = residualSumArcSecDE / (numResiduals - 1); // Uncertainty based on Astrometrica's formula of median residual devided by SQRT(num stars) UncertaintyArcSecRA = absResRAArcSec.Median() / Math.Sqrt(numResiduals); UncertaintyArcSecDE = absResDEArcSec.Median() / Math.Sqrt(numResiduals); return(true); }
public void NextFrame(int frameNo, IAstroImage astroImage, IStarMap starMap, LeastSquareFittedAstrometry astrometricFit) { IsTrackedSuccessfully = false; int searchRadius = (int)Math.Ceiling(Math.Max(m_LastMovementPixels, CoreAstrometrySettings.Default.PreMeasureSearchCentroidRadius)); PSFFit psfFit = null; int startingX = (int)TrackedObject.LastKnownX; int startingY = (int)TrackedObject.LastKnownY; if (m_RepeatedIntergationPositions * 4 < m_PastFrameNos.Count) { var expectedPos = GetExpectedPosition(frameNo); if (expectedPos != null) { startingX = expectedPos.X; startingY = expectedPos.Y; } } var nearbyFeatures = starMap.GetFeaturesInRadius(startingX, startingY, searchRadius).ToArray(); var nonStarNearbyFeature = new List <StarMapFeature>(); foreach (var feature in nearbyFeatures) { var center = feature.GetCenter(); var referenceStarFeatures = astrometricFit.FitInfo.AllStarPairs.Where(x => x.FitInfo.UsedInSolution).ToList(); var refStar = referenceStarFeatures.FirstOrDefault(s => Math.Sqrt((s.x - center.X) * (s.x - center.X) + (s.y - center.Y) * (s.y - center.Y)) < 2); double raf, def; astrometricFit.GetRADEFromImageCoords(center.XDouble, center.YDouble, out raf, out def); var pastKnownStar = m_LastFrameStars.FirstOrDefault(s => AngleUtility.Elongation(s.RADeg, s.DEDeg, raf, def) * 3600.0 < 2); if (refStar == null && pastKnownStar == null) { nonStarNearbyFeature.Add(feature); } } if (nonStarNearbyFeature.Count > 0) { StarMapFeature closestFeature = nonStarNearbyFeature[0]; var lastKnownCenter = new ImagePixel(TrackedObject.LastKnownX, TrackedObject.LastKnownY); var smallestDistance = lastKnownCenter.DistanceTo(closestFeature.GetCenter()); for (int i = 1; i < nonStarNearbyFeature.Count; i++) { var distance = lastKnownCenter.DistanceTo(nonStarNearbyFeature[i].GetCenter()); if (distance < smallestDistance) { smallestDistance = distance; closestFeature = nonStarNearbyFeature[i]; } } if (closestFeature != null) { var center = closestFeature.GetCenter(); AstrometryContext.Current.StarMap.GetPSFFit(center.X, center.Y, PSFFittingMethod.NonLinearFit, out psfFit); } } if (psfFit == null) { // The expected location cannot be matched with any brighter feature so it is likely a faint object // with no brighter objects around. Lets find the brightest (faint) object in the are and use it ImagePixel centroid = AstrometryContext.Current.StarMap.GetCentroid(startingX, startingY, searchRadius); if (centroid != null) { AstrometryContext.Current.StarMap.GetPSFFit(centroid.X, centroid.Y, PSFFittingMethod.NonLinearFit, out psfFit); } } if (psfFit != null) { double ra, de; astrometricFit.GetRADEFromImageCoords(psfFit.XCenter, psfFit.YCenter, out ra, out de); double maxPosDiffArcSec = astrometricFit.GetDistanceInArcSec(astrometricFit.Image.CenterXImage, astrometricFit.Image.CenterYImage, astrometricFit.Image.CenterXImage + Math.Max(m_LastMovementPixels, CoreAstrometrySettings.Default.MaxAllowedDefaultMotionInPixels), astrometricFit.Image.CenterYImage); if (!double.IsNaN(TrackedObject.RAHours)) { double posDif = 3600 * AngleUtility.Elongation(15 * TrackedObject.RAHours, TrackedObject.DEDeg, ra, de); if (posDif > maxPosDiffArcSec) { // NOTE: Not a valid measurement Trace.WriteLine(string.Format("The target position is too far from the last measured position", posDif)); return; } } TrackedObject.RAHours = ra / 15.0; TrackedObject.DEDeg = de; if (TrackedObject.PSFFit != null) { m_LastMovementPixels = 1.2 * ImagePixel.ComputeDistance(TrackedObject.LastKnownX, psfFit.XCenter, TrackedObject.LastKnownY, psfFit.YCenter); } TrackedObject.LastKnownX = psfFit.XCenter; TrackedObject.LastKnownY = psfFit.YCenter; TrackedObject.PSFFit = psfFit; var lastKnownCenter = new ImagePixel(TrackedObject.LastKnownX, TrackedObject.LastKnownY); var thisFrameStars = astrometricFit.FitInfo.AllStarPairs.Where(x => lastKnownCenter.DistanceTo(x.x, x.y) > 2 * psfFit.FWHM).ToList(); if (thisFrameStars.Count > 0) { m_LastFrameStars = thisFrameStars.Select(x => new Star(x.StarNo, x.RADeg, x.DEDeg, x.Mag) as IStar).ToList(); } IsTrackedSuccessfully = true; } if (psfFit != null && psfFit.XCenter > 0 && psfFit.YCenter > 0) { m_PastFramePosX.Add(psfFit.XCenter); m_PastFramePosY.Add(psfFit.YCenter); m_PastFrameNos.Add(frameNo); } }
protected virtual void DrawEquatorialGrid(Graphics g) { // We want at least 5 but no more than 10 RA and DE lines to fit the diagonal double diagonalInArcSec = m_SolvedPlate.GetDistanceInArcSec(0, 0, m_Image.ImageWidth, m_Image.ImageHeight); double ra0, de0; m_SolvedPlate.GetRADEFromImageCoords(m_Image.CenterXImage, m_Image.CenterYImage, out ra0, out de0); Debug.Assert(Math.Abs(m_SolvedPlate.RA0Deg - ra0) < 1 / 3600.0); Debug.Assert(Math.Abs(m_SolvedPlate.DE0Deg - de0) < 1 / 3600.0); // We are not drawing lines when too close to the poles if (de0 + 2 * diagonalInArcSec / 3600.0 > 90) { return; } if (de0 - 2 * diagonalInArcSec / 3600.0 < -90) { return; } int MAX_GRID_LINES = 10; int MIN_GRID_LINES = 5; int[] intervals = new int[] { 1, 5, 10, 30, 60, 60 * 5, 60 * 10, 60 * 30, 60 * 60 }; double deFrom, deTo; #region Calculating the interval in declination double maxArcSec = diagonalInArcSec / MIN_GRID_LINES; double minArcSec = diagonalInArcSec / MAX_GRID_LINES; int deInterval = -1; for (int i = 0; i < intervals.Length; i++) { if (intervals[i] >= minArcSec && intervals[i] <= maxArcSec) { deInterval = intervals[i]; break; } else if (intervals[i] < minArcSec) { deInterval = intervals[i]; } } #endregion double raFrom, raTo; #region Calculating the interval in right accension double[] raArr = new double[4]; double[] deArr = new double[4]; m_SolvedPlate.GetRADEFromImageCoords(0, 0, out raArr[0], out deArr[0]); m_SolvedPlate.GetRADEFromImageCoords(0, m_Image.ImageHeight, out raArr[1], out deArr[1]); m_SolvedPlate.GetRADEFromImageCoords(m_Image.ImageWidth, 0, out raArr[2], out deArr[2]); m_SolvedPlate.GetRADEFromImageCoords(m_Image.ImageWidth, m_Image.ImageHeight, out raArr[3], out deArr[3]); // From the RA of the 4 corners we need to find the fromRA and toRA double raMin = double.MaxValue, raMax = double.MinValue; int minIdx = 0, maxIdx = 0; for (int i = 0; i < 4; i++) { if (raArr[i] > raMax) { raMax = raArr[i]; maxIdx = i; } if (raArr[i] < raMin) { raMin = raArr[i]; minIdx = i; } } double shortestDistance = AngleUtility.Elongation(raArr[minIdx], 0, raArr[maxIdx], 0); if (shortestDistance < (raArr[maxIdx] - raArr[minIdx]) - 10 / 3600.0 /* tolerance 10" */) { // We are going accross the 0 point Debug.Assert(false, "This is not implemented yet"); return; //raFrom = 0; //raTo = 0; //for (int i = 0; i < 4; i++) //{ // if (i == minIdx) continue; // if (i == maxIdx) continue; // if (raArr[0] > raMax) // { // raMax = raArr[0]; // maxIdx = 1; // } // if (raArr[0] < raMin) // { // raMin = raArr[0]; // minIdx = i; // } //} //raTo = raArr[maxIdx]; } else { raFrom = raArr[minIdx]; raTo = raArr[maxIdx]; } minArcSec = 3600.0 * (raTo - raFrom) / (15 * MAX_GRID_LINES); maxArcSec = 3600.0 * (raTo - raFrom) / (15 * MIN_GRID_LINES); int raInterval = -1; for (int i = 0; i < intervals.Length; i++) { if (intervals[i] >= minArcSec && intervals[i] <= maxArcSec) { raInterval = intervals[i]; break; } else if (intervals[i] < minArcSec) { raInterval = intervals[i]; } } #endregion #if DEBUG if (raInterval == -1 || deInterval == -1) { Debug.Assert(false, "Problem with raInterval or deInterval"); return; } #endif raFrom = (Math.Floor((raFrom * 3600.0) / (15 * raInterval)) - 1) * 15 * raInterval / 3600.0; raTo = (Math.Ceiling((raTo * 3600.0) / (15 * raInterval)) + 1) * 15 * raInterval / 3600.0; deFrom = (Math.Floor((de0 * 3600.0 - (diagonalInArcSec / 2)) / (deInterval)) - 1) * deInterval / 3600.0; deTo = (Math.Ceiling((de0 * 3600.0 + (diagonalInArcSec / 2)) / (deInterval)) + 1) * deInterval / 3600.0; //Debug.WriteLine(string.Format("Draw Grid -> C: ({0}, {1}) F:({2}, {3}) T:({4}, {5})", // AstroConvert.ToStringValue(ra0, "HH MM SS.T"), AstroConvert.ToStringValue(de0, "+DD MM SS.T"), // AstroConvert.ToStringValue(raFrom, "HH MM SS.T"), AstroConvert.ToStringValue(raTo, "HH MM SS.T"), // AstroConvert.ToStringValue(deFrom, "+DD MM SS.T"), AstroConvert.ToStringValue(deTo, "+DD MM SS.T"))); double x1, y1, x2, y2; double stepRA = (15 * raInterval) / 3600.0; double stepDE = deInterval / 3600.0; for (double ra = raFrom; ra <= raTo; ra += stepRA) { x1 = double.NaN; y1 = double.NaN; for (double de = deFrom; de < deTo; de += stepDE / 10.0) { m_SolvedPlate.GetImageCoordsFromRADE(ra, de, out x2, out y2); if (x2 >= 0 && x2 <= m_Image.ImageWidth && y2 >= 0 && y2 <= m_Image.ImageHeight) { if (!double.IsNaN(x1)) { g.DrawLine(Pens.Purple, (float)x1, (float)y1, (float)x2, (float)y2); } x1 = x2; y1 = y2; } } } for (double de = deFrom; de <= deTo; de += stepDE) { x1 = double.NaN; y1 = double.NaN; for (double ra = raFrom; ra < raTo; ra += stepRA / 10.0) { m_SolvedPlate.GetImageCoordsFromRADE(ra, de, out x2, out y2); if (x2 >= 0 && x2 <= m_Image.ImageWidth && y2 >= 0 && y2 <= m_Image.ImageHeight) { if (!double.IsNaN(x1)) { g.DrawLine(Pens.Purple, (float)x1, (float)y1, (float)x2, (float)y2); } x1 = x2; y1 = y2; } } } }
public AstrometricSolutionImpl(LeastSquareFittedAstrometry astrometry, StarMagnitudeFit photometry, AstrometricState state, FieldSolveContext fieldSolveContext, MeasurementContext measurementContext) { StarCatalog = fieldSolveContext.StarCatalogueFacade.CatalogNETCode; UtcTime = fieldSolveContext.UtcTime; FrameNoOfUtcTime = fieldSolveContext.FrameNoOfUtcTime; AutoLimitMagnitude = (float)fieldSolveContext.AutoLimitMagnitude; ResolvedFocalLength = (float)fieldSolveContext.FocalLength; if (astrometry != null) { ResolvedCenterRADeg = (float)astrometry.RA0Deg; ResolvedCenterDEDeg = (float)astrometry.DE0Deg; StdDevRAArcSec = (float)astrometry.StdDevRAArcSec; StdDevDEArcSec = (float)astrometry.StdDevDEArcSec; ArcSecsInPixel = 1 / astrometry.GetDistanceInPixels(1); } else { ResolvedCenterRADeg = float.NaN; ResolvedCenterDEDeg = float.NaN; StdDevRAArcSec = float.NaN; StdDevDEArcSec = float.NaN; ArcSecsInPixel = 0; } if (state.SelectedObject != null) { m_UserObject = new TangraUserObjectImpl(); m_UserObject.RADeg = (float)state.SelectedObject.RADeg; m_UserObject.DEDeg = (float)state.SelectedObject.DEDeg; m_UserObject.X = (float)state.SelectedObject.X0; m_UserObject.Y = (float)state.SelectedObject.Y0; if (state.IdentifiedObjects != null && state.IdentifiedObjects.Count == 1) { foreach (IIdentifiedObject idObj in state.IdentifiedObjects) { if (AngleUtility.Elongation(idObj.RAHours * 15.0, idObj.DEDeg, state.SelectedObject.RADeg, state.SelectedObject.DEDeg) * 3600 < 120) { m_UserObject.ResolvedName = idObj.ObjectName; break; } } } } InstrumentalDelay = measurementContext.InstrumentalDelay; InstrumentalDelayUnits = measurementContext.InstrumentalDelayUnits.ToString(); FrameTimeType = measurementContext.FrameTimeType.ToString(); IntegratedFramesCount = measurementContext.IntegratedFramesCount; IntegratedExposureSeconds = measurementContext.IntegratedExposureSeconds; AavIntegration = measurementContext.AavIntegration; AavStackedMode = measurementContext.AavStackedMode; VideoFileFormat = measurementContext.VideoFileFormat.ToString(); NativeVideoFormat = measurementContext.NativeVideoFormat; if (!string.IsNullOrEmpty(state.IdentifiedObjectToMeasure)) { ObjectDesignation = MPCObsLine.GetObjectCode(state.IdentifiedObjectToMeasure); } else if (state.IdentifiedObjects != null && state.IdentifiedObjects.Count == 1) { ObjectDesignation = MPCObsLine.GetObjectCode(state.IdentifiedObjects[0].ObjectName); } ObservatoryCode = fieldSolveContext.ObsCode; CatalogueCode = measurementContext.StarCatalogueFacade.CatalogNETCode; m_MeasurementsImpl = new List <TangraAstrometricMeasurementImpl>(); if (state.Measurements != null) { foreach (var mea in state.Measurements) { m_MeasurementsImpl.Add(new TangraAstrometricMeasurementImpl() { DEDeg = mea.DEDeg, RADeg = mea.RADeg, FrameNo = mea.FrameNo, SolutionUncertaintyRACosDEArcSec = mea.SolutionUncertaintyRACosDEArcSec, SolutionUncertaintyDEArcSec = mea.SolutionUncertaintyDEArcSec, FWHMArcSec = mea.FWHMArcSec, Detection = mea.Detection, SNR = mea.SNR, UncorrectedTimeStamp = mea.FrameTimeStamp, Mag = mea.Mag }); } } m_MatchedStarImpl = new List <TangraMatchedStarImpl>(); if (astrometry != null) { foreach (PlateConstStarPair pair in astrometry.FitInfo.AllStarPairs) { if (pair.FitInfo.UsedInSolution) { var star = new TangraMatchedStarImpl() { X = (float)pair.x, Y = (float)pair.y, RADeg = (float)pair.RADeg, DEDeg = (float)pair.DEDeg, StarNo = pair.StarNo, ExcludedForHighResidual = pair.FitInfo.ExcludedForHighResidual, ResidualRAArcSec = (float)pair.FitInfo.ResidualRAArcSec, ResidualDEArcSec = (float)pair.FitInfo.ResidualDEArcSec, DetectionCertainty = (float)pair.DetectionCertainty, PSFAmplitude = (int)pair.Intensity, IsSaturated = pair.IsSaturated, Mag = (float)pair.Mag }; TangraCatalogStarImpl catStar = null; IStar catalogStar = fieldSolveContext.CatalogueStars.Find(s => s.StarNo == pair.StarNo); if (catalogStar != null) { if (catalogStar is UCAC4Entry) { catStar = new TangraAPASSStar(); } else { catStar = new TangraCatalogStarImpl(); } catStar.StarNo = catalogStar.StarNo; catStar.MagR = (float)catalogStar.MagR; catStar.MagV = (float)catalogStar.MagV; catStar.MagB = (float)catalogStar.MagB; catStar.Mag = (float)catalogStar.Mag; if (catalogStar is UCAC3Entry) { UCAC3Entry ucac3Star = (UCAC3Entry)catalogStar; catStar.MagJ = (float)(ucac3Star.jmag * 0.001); catStar.MagK = (float)(ucac3Star.kmag * 0.001); catStar.RAJ2000Deg = (float)ucac3Star.RACat; catStar.DEJ2000Deg = (float)ucac3Star.DECat; } else if (catalogStar is UCAC2Entry) { UCAC2Entry ucac2Star = (UCAC2Entry)catalogStar; catStar.MagJ = (float)(ucac2Star._2m_J * 0.001); catStar.MagK = (float)(ucac2Star._2m_Ks * 0.001); catStar.RAJ2000Deg = (float)ucac2Star.RACat; catStar.DEJ2000Deg = (float)ucac2Star.DECat; } else if (catalogStar is NOMADEntry) { NOMADEntry nomadStar = (NOMADEntry)catalogStar; catStar.MagJ = (float)(nomadStar.m_J * 0.001); catStar.MagK = (float)(nomadStar.m_K * 0.001); catStar.RAJ2000Deg = (float)nomadStar.RACat; catStar.DEJ2000Deg = (float)nomadStar.DECat; } else if (catalogStar is UCAC4Entry) { UCAC4Entry ucac4Star = (UCAC4Entry)catalogStar; catStar.MagJ = (float)(ucac4Star.MagJ); catStar.MagK = (float)(ucac4Star.MagK); catStar.RAJ2000Deg = (float)ucac4Star.RACat; catStar.DEJ2000Deg = (float)ucac4Star.DECat; ((TangraAPASSStar)catStar).B = (float)ucac4Star.MagB; ((TangraAPASSStar)catStar).V = (float)ucac4Star.MagV; ((TangraAPASSStar)catStar).g = (float)ucac4Star.Mag_g; ((TangraAPASSStar)catStar).r = (float)ucac4Star.Mag_r; ((TangraAPASSStar)catStar).i = (float)ucac4Star.Mag_i; ((TangraAPASSStar)catStar).e_B = ucac4Star.apase_B * 0.001f; ((TangraAPASSStar)catStar).e_V = ucac4Star.apase_V * 0.001f; ((TangraAPASSStar)catStar).e_g = ucac4Star.apase_g * 0.001f; ((TangraAPASSStar)catStar).e_r = ucac4Star.apase_r * 0.001f; ((TangraAPASSStar)catStar).e_i = ucac4Star.apase_i * 0.001f; } } star.CatalogStar = catStar; if (photometry != null) { IStar photometryStar = photometry.StarNumbers.FirstOrDefault(s => s.StarNo == pair.StarNo); if (photometryStar != null) { int idx = photometry.StarNumbers.IndexOf(photometryStar); star.Intensity = (float)photometry.Intencities[idx]; star.IsSaturated = photometry.SaturatedFlags[idx]; star.MeaSignalMethod = ConvertSignalMethod(photometry.MeaSignalMethod); star.MeaBackgroundMethod = ConvertBackgroundMethod(photometry.MeaBackgroundMethod); star.MeaSingleApertureSize = photometry.MeaSingleAperture; star.MeaBackgroundPixelCount = photometry.MeaBackgroundPixelCount; star.MeaSaturationLevel = photometry.MeaSaturationLevel; } } m_MatchedStarImpl.Add(star); } } } }
public Bitmap ResolveObjects( TangraConfig.PhotometryReductionMethod photometryReductionMethod, TangraConfig.PsfQuadrature psfQuadrature, TangraConfig.PsfFittingMethod psfFittingMethod, TangraConfig.BackgroundMethod backgroundMethod, TangraConfig.PreProcessingFilter filter, Guid magnitudeBandId, Rectangle osdRectangleToExclude, Rectangle rectToInclude, bool limitByInclusion, IAstrometrySettings astrometrySettings, ObjectResolverSettings objectResolverSettings) { m_AstrometrySettings = astrometrySettings; StarMap starMap = new StarMap( astrometrySettings.PyramidRemoveNonStellarObject, astrometrySettings.MinReferenceStarFWHM, astrometrySettings.MaxReferenceStarFWHM, astrometrySettings.MaximumPSFElongation, astrometrySettings.LimitReferenceStarDetection); starMap.FindBestMap(StarMapInternalConfig.Default, m_Image, osdRectangleToExclude, rectToInclude, limitByInclusion); float r0 = 0; m_MagnitudeFit = StarMagnitudeFit.PerformFit( m_AstrometryController, m_VideoController, m_Image.Pixelmap.BitPixCamera, m_Image.Pixelmap.MaxSignalValue, m_Astrometry.FitInfo, photometryReductionMethod, psfQuadrature, psfFittingMethod, backgroundMethod, filter, m_Stars, magnitudeBandId, 1.0f, TangraConfig.KnownCameraResponse.Undefined, null, null, null, ref r0); m_BackgroundFlux = m_MagnitudeFit.GetBackgroundIntencity(); m_BackgroundMag = m_MagnitudeFit.GetMagnitudeForIntencity(m_BackgroundFlux); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("Plate FWHM: {0}", 2 * Math.Sqrt(Math.Log(2)) * r0)); } PeakPixelResolver resolver = new PeakPixelResolver(m_Image); resolver.ResolvePeakPixels(osdRectangleToExclude, rectToInclude, limitByInclusion, objectResolverSettings.ExcludeEdgeAreaPixels, objectResolverSettings.MinDistanceBetweenPeakPixels); List <double> identifiedMagnitudes = new List <double>(); List <double> identifiedR0s = new List <double>(); m_IdentifiedObjects.Clear(); m_UidentifiedObjects.Clear(); foreach (KeyValuePair <int, int> peakPixel in resolver.PeakPixels.Keys) { int x = peakPixel.Key; int y = peakPixel.Value; bool isSaturated; double intencity = m_MagnitudeFit.GetIntencity(new ImagePixel(255, x, y), out isSaturated); double magnitude = m_MagnitudeFit.GetMagnitudeForIntencity(intencity); if (magnitude < m_MaxMagForAstrometry) { double RADeg, DEDeg; PSFFit fit; starMap.GetPSFFit(x, y, PSFFittingMethod.NonLinearFit, out fit); if (fit.IMax < 0) { continue; } if (fit.IMax < fit.I0) { continue; } if (fit.Certainty < objectResolverSettings.MinCertainty) { continue; } if (fit.FWHM < objectResolverSettings.MinFWHM) { continue; } if (fit.IMax - fit.I0 < objectResolverSettings.MinAmplitude) { continue; } m_Astrometry.GetRADEFromImageCoords(fit.XCenter, fit.YCenter, out RADeg, out DEDeg); // All stars closer than 2 arcsec to this position List <IStar> matchingStars = m_Stars.Where(s => Math.Abs(AngleUtility.Elongation(s.RADeg, s.DEDeg, RADeg, DEDeg) * 3600.0) < objectResolverSettings.MaxStarMatchMagDif).ToList(); bool identified = false; if (matchingStars.Count >= 1) { foreach (IStar star in matchingStars) { if (objectResolverSettings.MaxStarMatchMagDif >= Math.Abs(magnitude - star.Mag)) { // The star is identified. Do we care more? if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("STAR ({0}, {1}) No -> {2}; Mag -> {3} (Expected: {4}); R0 = {5}", x, y, star.StarNo, magnitude.ToString("0.00"), star.Mag.ToString("0.00"), fit.R0.ToString("0.0"))); } identifiedMagnitudes.Add(magnitude); identifiedR0s.Add(fit.R0); m_IdentifiedObjects.Add(fit, star); identified = true; break; } } } if (matchingStars.Count == 0 || !identified) { // The object is not in the star database // TODO: Test for hot pixel. Match to hot pixel profile from the brightest pixel in the area m_UidentifiedObjects.Add(fit, magnitude); } } else { // Don't bother with too faint objects } } if (m_IdentifiedObjects.Count > 0) { double mean = identifiedR0s.Average(); double variance = 0; foreach (double rr0 in identifiedR0s) { variance += (rr0 - mean) * (rr0 - mean); } variance = Math.Sqrt(variance / (m_IdentifiedObjects.Count - 1)); double minR0 = mean - variance; double maxR0 = mean + variance; identifiedMagnitudes.Sort(); double maxStarMag = identifiedMagnitudes[Math.Max(0, (int)Math.Truncate(0.9 * identifiedMagnitudes.Count))]; if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { Trace.WriteLine(string.Format("Max Star Mag: {0}; R0 ({1}, {2})", maxStarMag.ToString("0.00"), minR0.ToString("0.0"), maxR0.ToString("0.0"))); } // NOTE: The R0 exclusion may ignore bright comets ! m_UnknownObjects = m_UidentifiedObjects .Where(p => p.Value < maxStarMag && p.Key.R0 >= minR0 && p.Key.R0 <= maxR0) .ToDictionary(p => p.Key, p => p.Value); if (TangraConfig.Settings.TraceLevels.PlateSolving.TraceVerbose()) { foreach (PSFFit obj in m_UnknownObjects.Keys) { Trace.WriteLine(string.Format("UNK: ({0}, {1}) Mag -> {2}; R0 = {3}", obj.XCenter.ToString("0.0"), obj.YCenter.ToString("0.0"), m_UnknownObjects[obj].ToString("0.00"), obj.R0.ToString("0.0"))); } } } Bitmap bitmap = m_Image.Pixelmap.CreateDisplayBitmapDoNotDispose(); using (Graphics g = Graphics.FromImage(bitmap)) { foreach (PSFFit star in m_IdentifiedObjects.Keys) { float x = (float)star.XCenter; float y = (float)star.YCenter; g.DrawEllipse(Pens.GreenYellow, x - 5, y - 5, 10, 10); } foreach (PSFFit star in m_UnknownObjects.Keys) { float x = (float)star.XCenter; float y = (float)star.YCenter; g.DrawEllipse(Pens.Tomato, x - 8, y - 8, 16, 16); } g.Save(); } return(bitmap); }
public FocalLengthFit ComputeFocalLengthFit() { if (m_FocalLengthFit != null) { return(m_FocalLengthFit); } List <DistSolveEntry> entries = new List <DistSolveEntry>(); for (int i = 0; i < m_Pairs.Count; i++) { if (!m_Pairs[i].FitInfo.UsedInSolution) { continue; } if (m_Pairs[i].FitInfo.ExcludedForHighResidual) { continue; } for (int j = 0; j < m_Pairs.Count; j++) { if (i == j) { continue; } if (!m_Pairs[j].FitInfo.UsedInSolution) { continue; } if (m_Pairs[j].FitInfo.ExcludedForHighResidual) { continue; } DistSolveEntry entry = new DistSolveEntry(); entry.DX = Math.Abs(m_Pairs[i].x - m_Pairs[j].x); entry.DY = Math.Abs(m_Pairs[i].y - m_Pairs[j].y); entry.StarNo1 = m_Pairs[i].StarNo; entry.StarNo2 = m_Pairs[j].StarNo; // NOTE: two ways of computing distances - by vx,vy,vz and Elongation() //entry.DistRadians = Math.Acos(m_Pairs[i].VX * m_Pairs[j].VX + m_Pairs[i].VY * m_Pairs[j].VY + m_Pairs[i].VZ * m_Pairs[j].VZ); double elong = AngleUtility.Elongation(m_Pairs[i].RADeg, m_Pairs[i].DEDeg, m_Pairs[j].RADeg, m_Pairs[j].DEDeg); entry.DistRadians = elong * Math.PI / 180.0; if (entry.DX == 0 || entry.DY == 0) { continue; } entries.Add(entry); } } SafeMatrix A = new SafeMatrix(entries.Count, 2); SafeMatrix X = new SafeMatrix(entries.Count, 1); int numStars = 0; foreach (DistSolveEntry entry in entries) { A[numStars, 0] = entry.DX * entry.DX; A[numStars, 1] = entry.DY * entry.DY; X[numStars, 0] = entry.DistRadians * entry.DistRadians; numStars++; } // Insufficient stars to solve the plate if (numStars < 3) { return(null); } SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; double a = bx[0, 0]; double b = bx[1, 0]; double residualSum = 0; int numResiduals = 0; foreach (DistSolveEntry entry in entries) { entry.ResidualRadians = entry.DistRadians - Math.Sqrt(a * entry.DX * entry.DX + b * entry.DY * entry.DY); entry.ResidualPercent = entry.ResidualRadians * 100.0 / entry.DistRadians; entry.ResidualArcSec = 3600.0 * entry.ResidualRadians * 180.0 / Math.PI; numResiduals++; residualSum += entry.ResidualRadians * entry.ResidualRadians; } double variance = Math.Sqrt(residualSum / (numResiduals - 1)); return(new FocalLengthFit(a, b, variance, entries)); }
public ThreeStarAstrometry(AstroPlate image, Dictionary <ImagePixel, IStar> userStarIdentification, int tolerance) { if (userStarIdentification.Count != 3) { throw new InvalidOperationException(); } Image = image; UserStars = userStarIdentification.ToDictionary(kvp => kvp.Key, kvp => kvp.Value); double a0 = userStarIdentification.Values.Average(x => x.RADeg) * DEG_TO_RAD; double d0 = userStarIdentification.Values.Average(x => x.DEDeg) * DEG_TO_RAD; double corr = double.MaxValue; int attempts = 0; do { SafeMatrix AX = new SafeMatrix(3, 3); SafeMatrix X = new SafeMatrix(3, 1); SafeMatrix AY = new SafeMatrix(3, 3); SafeMatrix Y = new SafeMatrix(3, 1); int i = 0; foreach (var pixel in userStarIdentification.Keys) { IStar star = userStarIdentification[pixel]; double a = star.RADeg * DEG_TO_RAD; double d = star.DEDeg * DEG_TO_RAD; AX[i, 0] = pixel.XDouble; AX[i, 1] = pixel.YDouble; AX[i, 2] = 1; AY[i, 0] = pixel.XDouble; AY[i, 1] = pixel.YDouble; AY[i, 2] = 1; X[i, 0] = Math.Cos(d) * Math.Sin(a - a0) / (Math.Cos(d0) * Math.Cos(d) * Math.Cos(a - a0) + Math.Sin(d0) * Math.Sin(d)); Y[i, 0] = (Math.Cos(d0) * Math.Sin(d) - Math.Cos(d) * Math.Sin(d0) * Math.Cos(a - a0)) / (Math.Sin(d0) * Math.Sin(d) + Math.Cos(d0) * Math.Cos(d) * Math.Cos(a - a0)); i++; } SafeMatrix a_T = AX.Transpose(); SafeMatrix aa = a_T * AX; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; m_A = bx[0, 0]; m_B = bx[1, 0]; m_C = bx[2, 0]; a_T = AY.Transpose(); aa = a_T * AY; aa_inv = aa.Inverse(); bx = (aa_inv * a_T) * Y; m_D = bx[0, 0]; m_E = bx[1, 0]; m_F = bx[2, 0]; m_A0Rad = a0; m_D0Rad = d0; double ra_c, de_c; GetRADEFromImageCoords(Image.CenterXImage, Image.CenterYImage, out ra_c, out de_c); corr = AngleUtility.Elongation(ra_c, de_c, a0 * RAD_TO_DEG, d0 * RAD_TO_DEG) * 3600; a0 = ra_c * DEG_TO_RAD; d0 = de_c * DEG_TO_RAD; attempts++; }while (corr > tolerance && attempts < MAX_ATTEMPTS); Success = corr <= tolerance; }