private void LinearFitOfAveragedModel(uint[,] intensity) { // 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; } }
public static DateTime GetNetworkTimeFromMultipleServers(string[] ntpServers, out float latencyInMilliseconds, out int aliveServers, out bool timeUpdated) { latencyInMilliseconds = 0; aliveServers = 0; double asyncCoeff = 0; double referenceTimeError = 0; var deltaTicksList = new List<double>(); double[] serverLatencies = new double[ntpServers.Length]; int[] serverAttempts = new int[ntpServers.Length]; for (int packerIndex = 0; packerIndex < Settings.Default.NumberOfNTPRequestsPerUpdate; packerIndex++) { if (ntpServers.Length > 2) { var fit = new LinearRegression(); float latency = 0; for (int i = 0; i < ntpServers.Length; i++) { long startQPTicks = 0; long endQPTicks = 0; try { DateTime reference = GetSingleNetworkTimeReference(ntpServers[i], ref startQPTicks, ref endQPTicks); long startTicks = NTPTimeKeeper.GetUtcTimeTicksFromQPCTicksNoDrift(startQPTicks); long endTicks = NTPTimeKeeper.GetUtcTimeTicksFromQPCTicksNoDrift(endQPTicks); fit.AddDataPoint(endTicks - startTicks, reference.Ticks - startTicks); latency += (float)new TimeSpan(endTicks - startTicks).TotalMilliseconds; serverLatencies[i] += (float) new TimeSpan(endTicks - startTicks).TotalMilliseconds; serverAttempts[i]++; aliveServers++; } catch { } } fit.Solve(); asyncCoeff += fit.A; deltaTicksList.Add(fit.B); referenceTimeError += fit.StdDev; latencyInMilliseconds += (latency / fit.NumberOfDataPoints); } else { float latency = 0; float delta = 0; float stdDev = 0; aliveServers = 0; for (int i = 0; i < ntpServers.Length; i++) { long startQPTicks = 0; long endQPTicks = 0; try { DateTime reference = GetSingleNetworkTimeReference(ntpServers[i], ref startQPTicks, ref endQPTicks); long startTicks = NTPTimeKeeper.GetUtcTimeTicksFromQPCTicksNoDrift(startQPTicks); long endTicks = NTPTimeKeeper.GetUtcTimeTicksFromQPCTicksNoDrift(endQPTicks); DateTime currTime = new DateTime((startTicks + endTicks) / 2); latency += (float)new TimeSpan(endTicks - startTicks).TotalMilliseconds; delta += new TimeSpan(reference.Ticks - currTime.Ticks).Ticks; stdDev += (endTicks - startTicks) / 4; serverLatencies[i] += (float)new TimeSpan(endTicks - startTicks).TotalMilliseconds; serverAttempts[i]++; aliveServers++; } catch { } } asyncCoeff += 1; deltaTicksList.Add(delta / aliveServers); referenceTimeError += (stdDev / aliveServers); latencyInMilliseconds += (latency / aliveServers); } } asyncCoeff /= Settings.Default.NumberOfNTPRequestsPerUpdate; double deltaTicks = deltaTicksList.Average(); double deltaTicksOneSigma = deltaTicksList.Count > 1 ? Math.Sqrt(deltaTicksList.Sum(t => (t - deltaTicks) * (t - deltaTicks)) / (deltaTicksList.Count - 1)) : 0; referenceTimeError /= Settings.Default.NumberOfNTPRequestsPerUpdate; latencyInMilliseconds /= Settings.Default.NumberOfNTPRequestsPerUpdate; lock (s_SyncLock) { double averageLatency = 0; double fiveSigmaLatency = 0; const int SLIDING_INTERVAL = 3; // Update the time if // (1) This is one of the first 3 updates or // (2) The average latency in ms is within the Math.Max(5-sigma latency, 5 ms) from the average of last 5 measurements bool updateTimeReference = s_LastFiveNTPLatencies.Count < SLIDING_INTERVAL; if (!updateTimeReference) { averageLatency = s_LastFiveNTPLatencies.Average(); fiveSigmaLatency = 5 * Math.Sqrt(s_LastFiveNTPLatencies.Sum(t => (t - averageLatency) * (t - averageLatency)) / (SLIDING_INTERVAL - 1)); updateTimeReference = latencyInMilliseconds - averageLatency < Math.Max(fiveSigmaLatency, 5); if (!updateTimeReference) { if (s_LastFiveNTPLatenciesAlt.Count >= SLIDING_INTERVAL) { s_LastFiveNTPLatencies.Clear(); s_LastFiveNTPLatencies.AddRange(s_LastFiveNTPLatencies.Take(SLIDING_INTERVAL)); updateTimeReference = true; } else s_LastFiveNTPLatenciesAlt.Add(latencyInMilliseconds); } } if (updateTimeReference && !s_LastRequstedUpdateSkipped && s_LastFiveNTPLatencies.Count >= SLIDING_INTERVAL) { // One-time skip update if delta is bigger than the average latency OR if the latency error is bigger than half the latency if (new TimeSpan((long) deltaTicks).TotalMilliseconds > latencyInMilliseconds || new TimeSpan((long) referenceTimeError).TotalMilliseconds > 0.5*latencyInMilliseconds) { updateTimeReference = false; s_LastRequstedUpdateSkipped = true; Trace.WriteLine("One time skip update triggered"); } } if (updateTimeReference && !double.IsNaN(s_AverageAsyncCoeff) && !double.IsNaN(s_FiveSigmaAverageAsyncCoeff)) { double currCoeffDiff = Math.Abs(asyncCoeff - s_AverageAsyncCoeff); if (currCoeffDiff > s_FiveSigmaAverageAsyncCoeff && currCoeffDiff > s_AverageAsyncCoeff * 0.25) { updateTimeReference = false; Trace.WriteLine(string.Format("Ignoring async coefficient outlier of {0:F2}. Average coeff = {1:F2}; 5-sigma = {2:F2}; 25% coeff diff = {3:F2}", asyncCoeff, s_AverageAsyncCoeff, s_FiveSigmaAverageAsyncCoeff, s_AverageAsyncCoeff * 0.25)); } } if (updateTimeReference && Settings.Default.NTPOutlierIgnore && Math.Abs(new TimeSpan((long) deltaTicks).TotalMilliseconds) > Settings.Default.NTPOutlierValue) { updateTimeReference = false; Trace.WriteLine(string.Format("Ignoring outlier bigger than {0:F1} ms", Settings.Default.NTPOutlierValue)); } if (s_Last60AsyncCoefficients.Count > 1 && s_Last60AsyncCoefficients.Count < 10) { if (Math.Sign(asyncCoeff) != Math.Sign(s_Last60AsyncCoefficients.Average())) { updateTimeReference = false; Trace.WriteLine(string.Format("Ignoring value with async coeff of {0:F2} which has oposite direction than the current average coeff of {1:F2}", asyncCoeff, s_Last60AsyncCoefficients.Average())); } } long freq = 0; Profiler.QueryPerformanceFrequency(ref freq); var individualLatencies = new StringBuilder("(Latencies: "); for (int i = 0; i < ntpServers.Length; i++) { if (serverAttempts[i] > 0) individualLatencies.AppendFormat("{0:F1} ms;", serverLatencies[i]/(serverAttempts[i])); else individualLatencies.Append("...;"); if (!double.IsNaN(s_AverageAsyncCoeff) && !double.IsNaN(s_FiveSigmaAverageAsyncCoeff)) individualLatencies.AppendFormat("; AsyncCoeff: {0:F2} +/- {1:F2} (5-sigma)", s_AverageAsyncCoeff, s_FiveSigmaAverageAsyncCoeff); } individualLatencies.Append(")"); if (updateTimeReference) { while (s_LastFiveNTPLatencies.Count >= SLIDING_INTERVAL) s_LastFiveNTPLatencies.RemoveAt(0); s_LastFiveNTPLatencies.Add(latencyInMilliseconds); s_LastFiveNTPLatenciesAlt.Clear(); NTPTimeKeeper.ProcessUTCTimeOffset((long)deltaTicks, (long)referenceTimeError, latencyInMilliseconds, !double.IsNaN(s_AverageAsyncCoeff)); Trace.WriteLine(string.Format("Time Updated: Delta = {0} ms +/- {1} ms. AsyncCoeff = {2}, Latency = {3} ms +/- {4} ms (Average: {5} ms +/- {6} ms), QPC Frequency = {7} (Time: {8} UT) {9}.", new TimeSpan((long)deltaTicks).TotalMilliseconds.ToString("0.0"), new TimeSpan((long)deltaTicksOneSigma).TotalMilliseconds.ToString("0.00"), (1 / asyncCoeff).ToString("0.00"), latencyInMilliseconds.ToString("0.0"), new TimeSpan((long)referenceTimeError).TotalMilliseconds.ToString("0.0"), averageLatency.ToString("0.0"), fiveSigmaLatency.ToString("0.00"), freq, DateTime.UtcNow.ToString("HH:mm:ss"), individualLatencies.ToString())); s_LastRequstedUpdateSkipped = false; s_Last60AsyncCoefficients.Add(asyncCoeff); if (s_Last60AsyncCoefficients.Count > 60) s_Last60AsyncCoefficients.RemoveAt(0); if (s_Last60AsyncCoefficients.Count > 10) { s_AverageAsyncCoeff = s_Last60AsyncCoefficients.Average(); s_FiveSigmaAverageAsyncCoeff = 5 * Math.Sqrt(s_Last60AsyncCoefficients.Sum(t => (t - s_AverageAsyncCoeff) * (t - s_AverageAsyncCoeff)) / (s_Last60AsyncCoefficients.Count - 1)); } if (s_Last60AsyncCoefficients.Count < 10 && s_Last60AsyncCoefficients.Count >= 3) { // While still collecting up to 10 measurements for the async coefficients, we can reject everything which more than 50% away from the rest of the coefficients for (int i = s_Last60AsyncCoefficients.Count - 1; i >= 0; i--) { double averageOfRest = s_Last60AsyncCoefficients.Where((xx, idx) => idx != i).Average(); if (Math.Abs(s_Last60AsyncCoefficients[i] - averageOfRest) > 0.5 * averageOfRest) s_Last60AsyncCoefficients.RemoveAt(i); if (s_Last60AsyncCoefficients.Count <= 3) break; } } } else Trace.WriteLine(string.Format("Time *NOT* Updated: Delta = {0} ms +/- {1} ms. AsyncCoeff = {2}, Latency = {3} ms +/- {4} ms (Average: {5} ms +/- {6} ms), QPC Frequency = {7} (Time: {8} UT) {9}.", new TimeSpan((long)deltaTicks).TotalMilliseconds.ToString("0.0"), new TimeSpan((long)deltaTicksOneSigma).TotalMilliseconds.ToString("0.00"), (1 / asyncCoeff).ToString("0.00"), latencyInMilliseconds.ToString("0.0"), new TimeSpan((long)referenceTimeError).TotalMilliseconds.ToString("0.0"), averageLatency.ToString("0.0"), fiveSigmaLatency.ToString("0.00"), freq, DateTime.UtcNow.ToString("HH:mm:ss"), individualLatencies.ToString())); timeUpdated = updateTimeReference; } // If we are also timestamping with Window's time then we should update the system clock every time too if (timeUpdated && Settings.Default.RecordSecondaryTimeStampInAavFile) { DateTime currCorrectWindowsTime = DateTime.UtcNow.AddTicks((long)deltaTicks); NTPClient.SetTime(currCorrectWindowsTime); } double x, y, z; return NTPTimeKeeper.UtcNowNoDriftCorrection(out x, out y, out z); }