Warning, file /education/kstars/kstars/ekos/focus/focusstars.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 #include "focusstars.h" 0002 #include "ekos/guide/internalguide/starcorrespondence.h" 0003 #include <ekos_focus_debug.h> 0004 0005 namespace Ekos 0006 { 0007 0008 namespace 0009 { 0010 0011 using Ekos::FocusStars; 0012 0013 // Debug code to print out how well the star correspondence matched. 0014 // Compares the star correspondence offsets from the detected "guide star position" 0015 // with the actual detected stars. Note, those offsets were just taken from the 0016 // first star set's detected stars. 0017 // Move to star correspondence? 0018 double correspondenceRmsError(const StarCorrespondence &corr, const QList<Edge> &stars2, 0019 const QVector<int> &starMap, GuiderUtils::Vector gsPosition) 0020 { 0021 const int s2Size = starMap.size(); 0022 double sumSq2 = 0; 0023 int num = 0; 0024 for (int s2 = 0; s2 < s2Size; s2++) 0025 { 0026 const int s1 = starMap[s2]; 0027 if (s1 >= 0) 0028 { 0029 // Compute the RMS association distance. 0030 double x2 = stars2[s2].x; 0031 double y2 = stars2[s2].y; 0032 0033 QVector2D offset = corr.offset(s1); 0034 double x1 = gsPosition.x + offset.x(); 0035 double y1 = gsPosition.y + offset.y(); 0036 double dSq = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); 0037 sumSq2 += dSq; 0038 num++; 0039 } 0040 } 0041 return sqrt(sumSq2 / num); 0042 } 0043 0044 // Use StarCorrespondence to find a common set of stars between stars1 and stars2. 0045 // Use mainStar1 as the "guideStar" or really the central star. We look for the pattern 0046 // of stars around that star. It is an index into stars1. If this star is missing from stars2, 0047 // StarCorrespondence could recover, but ideally it exists in both. 0048 // Returns two FocusStars objects containing the sets of corresponding stars. 0049 int matchStars(const QList<Edge> &stars1, const QList<Edge> &stars2, int mainStar1, 0050 double maxDistance, FocusStars *stars1Filtered, FocusStars *stars2Filtered) 0051 { 0052 // minFraction is the fraction of the stars passed into StarCorrespondence (i.e. in stars1) 0053 // that must be found in stars2. Ideally, star1 would be a smaller list, but instead we simply 0054 // adjust minFraction. 0055 // Goal is to get 45% of the stars in the smaller star set (or more). 0056 int minStars = std::min(stars1.size(), stars2.size()); 0057 int desiredStars = 0.45 * minStars; 0058 const double minFraction = static_cast<double>(desiredStars) / stars1.size(); 0059 0060 // Do the star correspondence 0061 QVector<int> starMap; 0062 StarCorrespondence corr(stars1, mainStar1); 0063 corr.setAllowMissingGuideStar(true); 0064 Edge gStar = corr.find(stars2, maxDistance, &starMap, false, minFraction); 0065 GuiderUtils::Vector gsPosition(gStar.x, gStar.y, 0); 0066 0067 // Grab the two sets of stars. 0068 const int s2Size = starMap.size(); 0069 int numAssociated = 0; 0070 QList<Edge> edges1, edges2; 0071 for (int s2 = 0; s2 < s2Size; s2++) 0072 { 0073 const int s1 = starMap[s2]; 0074 if (s1 >= 0) 0075 { 0076 numAssociated++; 0077 edges1.append(stars1[s1]); 0078 edges2.append(stars2[s2]); 0079 } 0080 } 0081 *stars1Filtered = FocusStars(edges1); 0082 *stars2Filtered = FocusStars(edges2); 0083 0084 // debug 0085 double corrError = correspondenceRmsError(corr, stars2, starMap, gsPosition); 0086 QString debugStr = QString("matchStars: Inputs sized %1 %2 found %3 matches, RMS dist %4") 0087 .arg(stars1.size()).arg(stars2.size()).arg(numAssociated).arg(corrError, 0, 'f', 1); 0088 qCDebug(KSTARS_EKOS_FOCUS) << debugStr; 0089 0090 return numAssociated; 0091 } 0092 0093 bool filterFocusStars(const FocusStars &stars1, const FocusStars &stars2, double maxDistance, FocusStars *filtered1, 0094 FocusStars *filtered2) 0095 { 0096 int size1 = stars1.getStars().size(); 0097 int size2 = stars2.getStars().size(); 0098 0099 // This section limits the process to the first 100 stars, for computational reasons, 0100 // just in case there is an input with a large number of stars. 0101 constexpr int maxNumStars = 100; 0102 QList<Edge> s1; 0103 const QList<Edge> *s1ptr = &(stars1.getStars()); 0104 if (size1 > maxNumStars) 0105 { 0106 for (int i = 0; i < maxNumStars; i++) 0107 s1.append(stars1.getStars()[i]); 0108 s1ptr = &s1; 0109 size1 = maxNumStars; 0110 } 0111 QList<Edge> s2; 0112 const QList<Edge> *s2ptr = &(stars2.getStars()); 0113 if (size2 > maxNumStars) 0114 { 0115 for (int i = 0; i < maxNumStars; i++) 0116 s2.append(stars2.getStars()[i]); 0117 s2ptr = &s2; 0118 size2 = maxNumStars; 0119 } 0120 0121 // If we have at least 10 matching stars, or 45% of the smallest star set, that's fine. 0122 const int sufficientMatches = std::min(10, static_cast<int>(0.45 * std::min(size1, size2))); 0123 0124 // Pick upto 5 different seed stars, if we need them. 0125 // Those are the stars from stars1 that are used in the StarCorrespondence algorithm. 0126 int maxMatches = 0; 0127 srand(time(0)); 0128 FocusStars f1, f2; 0129 for (int i = 0; i < 5; ++i) 0130 { 0131 const int seed = rand() % size1; 0132 int numMatches = matchStars(*s1ptr, *s2ptr, seed, maxDistance, &f1, &f2); 0133 if (numMatches > maxMatches) 0134 { 0135 *filtered1 = f1; 0136 *filtered2 = f2; 0137 maxMatches = numMatches; 0138 if (numMatches >= sufficientMatches) break; 0139 } 0140 } 0141 return (maxMatches > 1); 0142 } 0143 0144 } // namespace 0145 0146 0147 FocusStars::FocusStars(const QList<Edge *> edges, double maxDist) 0148 : maxDistance(maxDist), initialized(true) 0149 { 0150 // Copy the memory--can't depend on it sticking around. 0151 for (const auto &edge : edges) 0152 stars.append(*edge); 0153 } 0154 0155 FocusStars::FocusStars(const QList<Edge> edges, double maxDist) 0156 : maxDistance(maxDist), initialized(true) 0157 { 0158 // Copy the memory--can't depend on it sticking around. 0159 for (const auto &edge : edges) 0160 stars.append(edge); 0161 } 0162 0163 // Fitsdata does a bit of processing, removing saturated stars, 0164 // removing extremes, but all this is now being done in stellarsolver. 0165 // Just computing the median HFR. 0166 double FocusStars::getHFR() const 0167 { 0168 if (!initialized) 0169 return -1; 0170 0171 if (computedHFR >= 0) 0172 return computedHFR; 0173 if (stars.size() == 0) return -1; 0174 std::vector<double> values; 0175 for (auto &star : stars) 0176 values.push_back(star.HFR); 0177 const int middle = values.size() / 2; 0178 std::nth_element(values.begin(), values.begin() + middle, values.end()); 0179 computedHFR = values[middle]; 0180 return computedHFR; 0181 } 0182 0183 bool FocusStars::commonHFR(const FocusStars &referenceStars, double *thisHFR, double *referenceHFR) const 0184 { 0185 if (!initialized) 0186 return -1; 0187 0188 FocusStars commonStars, commonReferenceStars; 0189 bool ok = filterFocusStars(*this, referenceStars, maxDistance, &commonStars, &commonReferenceStars); 0190 if (!ok) return false; 0191 *thisHFR = commonStars.getHFR(); 0192 *referenceHFR = commonReferenceStars.getHFR(); 0193 0194 if (*thisHFR < 0 || *referenceHFR < 0 || commonStars.getStars().size() == 0 || 0195 commonReferenceStars.getStars().size() == 0) 0196 return false; 0197 0198 return true; 0199 } 0200 0201 void FocusStars::printStars(const QString &label) const 0202 { 0203 if (label.size() > 0) fprintf(stderr, "%s\n{", label.toLatin1().data()); 0204 bool first = true; 0205 for (const auto &star : getStars()) 0206 { 0207 fprintf(stderr, "%s{%6.1f,%6.1f, %5.2f}", first ? "" : ", ", star.x, star.y, star.HFR); 0208 first = false; 0209 } 0210 fprintf(stderr, "}\n"); 0211 } 0212 0213 double FocusStars::relativeHFR(const FocusStars &referenceStars, double referenceHFR) const 0214 { 0215 if (!initialized) 0216 return -1; 0217 0218 double hfrCommon, refHfrCommon; 0219 if (!commonHFR(referenceStars, &hfrCommon, &refHfrCommon)) 0220 { 0221 qCDebug(KSTARS_EKOS_FOCUS) << "Couldn't get a relative HFR, punted!"; 0222 // Scale the reference hfr by the HFR ratio when we can't find common stars. 0223 return (getHFR() / referenceStars.getHFR()) * referenceHFR; 0224 } 0225 0226 if (hfrCommon < 0 || refHfrCommon < 0) return -1; 0227 0228 QString debugStr = QString("RelativeHFR: sizes: %7 %8 hfr: (%1 (%2) / %3 (%4)) * %5 = %6") 0229 .arg(hfrCommon, 0, 'f', 2).arg(getHFR(), 0, 'f', 2).arg(refHfrCommon, 0, 'f', 2) 0230 .arg(referenceStars.getHFR(), 0, 'f', 2).arg(referenceHFR, 0, 'f', 2) 0231 .arg((hfrCommon / refHfrCommon) * referenceHFR, 0, 'f', 2) 0232 .arg(getStars().size()).arg(referenceStars.getStars().size()); 0233 qCDebug(KSTARS_EKOS_FOCUS) << debugStr; 0234 0235 return (hfrCommon / refHfrCommon) * referenceHFR; 0236 } 0237 0238 } // namespace