public void Solve() { if (m_XValues.Count < 3) throw new InvalidOperationException("Cannot get a linear fit from less than 3 points."); SafeMatrix A = new SafeMatrix(m_XValues.Count, 2); SafeMatrix X = new SafeMatrix(m_XValues.Count, 1); for (int i = 0; i < m_XValues.Count; i++) { A[i, 0] = m_XValues[i]; A[i, 1] = 1; X[i, 0] = m_YValues[i]; } SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); SafeMatrix bx = (aa_inv * a_T) * X; m_A = bx[0, 0]; m_B = bx[1, 0]; }
// I(x, y) = IBackground + IStarMax * Exp ( -((x - X0)*(x - X0) + (y - Y0)*(y - Y0)) / (r0 * r0)) private void NonLinearFit(uint[,] intensity, bool useNativeMatrix) { m_IsSolved = false; try { int full_width = (int)Math.Round(Math.Sqrt(intensity.Length)); m_MatrixSize = full_width; int half_width = full_width / 2; m_HalfWidth = half_width; switch (DataRange) { case PSFFittingDataRange.DataRange8Bit: m_Saturation = Properties.Settings.Default.Saturation8Bit; break; case PSFFittingDataRange.DataRange12Bit: m_Saturation = Properties.Settings.Default.Saturation12Bit; break; case PSFFittingDataRange.DataRange14Bit: m_Saturation = Properties.Settings.Default.Saturation14Bit; break; default: m_Saturation = Properties.Settings.Default.Saturation8Bit; break; } int nonSaturatedPixels = 0; double IBackground = 0; double r0 = 4.0; double IStarMax = 0; double found_x = half_width; double found_y = half_width; for (int iter = NumberIterations; iter > 0; iter--) { if (iter == NumberIterations) { uint zval = 0; IBackground = 0.0; /* assume no backgnd intensity at first... */ for (int i = 0; i < full_width; i++) { for (int j = 0; j < full_width; j++) { if (intensity[i, j] > zval) zval = intensity[i, j]; if (intensity[i, j] < m_Saturation) nonSaturatedPixels++; } } IStarMax = (double)zval - IBackground; } double[] dx = new double[full_width]; double[] dy = new double[full_width]; double[] fx = new double[full_width]; double[] fy = new double[full_width]; double r0_squared = r0 * r0; for (int i = 0; i < full_width; i++) { dx[i] = (double)i - found_x; fx[i] = Math.Exp(-dx[i] * dx[i] / r0_squared); dy[i] = (double)i - found_y; fy[i] = Math.Exp(-dy[i] * dy[i] / r0_squared); } SafeMatrix A = new SafeMatrix(nonSaturatedPixels, 5); SafeMatrix X = new SafeMatrix(nonSaturatedPixels, 1); int index = -1; for (int i = 0; i < full_width; i++) { for (int j = 0; j < full_width; j++) { uint zval = intensity[i, j]; if (zval < m_Saturation) { index++; double exp_val = fx[i] * fy[j]; double residual = IBackground + IStarMax * exp_val - (double)zval; X[index, 0] = -residual; A[index, 0] = 1.0; /* slope in i0 */ A[index, 1] = exp_val; /* slope in a0 */ A[index, 2] = 2.0 * IStarMax * dx[i] * exp_val / r0_squared; A[index, 3] = 2.0 * IStarMax * dy[j] * exp_val / r0_squared; A[index, 4] = 2.0 * IStarMax * (dx[i] * dx[i] + dy[j] * dy[j]) * exp_val / (r0 * r0_squared); } } } SafeMatrix Y; if (useNativeMatrix) { Y = NativePSFFitting.SolveLinearSystemFast(A, X); } else { SafeMatrix a_T = A.Transpose(); SafeMatrix aa = a_T * A; SafeMatrix aa_inv = aa.Inverse(); Y = (aa_inv * a_T) * X; } /* we need at least 6 unsaturated pixels to solve 5 params */ if (nonSaturatedPixels > 6) /* Request all pixels to be good! */ { IBackground += Y[0, 0]; IStarMax += Y[1, 0]; for (int i = 2; i < 4; i++) { if (Y[i, 0] > 1.0) Y[i, 0] = 1.0; if (Y[i, 0] < -1.0) Y[i, 0] = -1.0; } found_x += Y[2, 0]; found_y += Y[3, 0]; if (Y[4, 0] > r0 / 10.0) Y[4, 0] = r0 / 10.0; if (Y[4, 0] < -r0 / 10.0) Y[4, 0] = -r0 / 10.0; r0 += Y[4, 0]; } else { m_IsSolved = false; return; } } m_IsSolved = true; m_IBackground = IBackground; m_IStarMax = IStarMax; m_X0 = found_x; m_Y0 = found_y; m_R0 = r0; m_Residuals = new double[full_width, full_width]; for (int x = 0; x < full_width; x++) for (int y = 0; y < full_width; y++) { m_Residuals[x, y] = intensity[x, y] - GetPSFValueInternal(x, y); } } catch (DivideByZeroException) { } }