- Timestamp:
- Aug 15, 2023, 4:56:54 AM (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
branches/eam_branches/ipp-20230313/psLib/src/math/psMinimizePolyFit.c
r42491 r42492 48 48 /* DEFINE STATEMENTS */ 49 49 /*****************************************************************************/ 50 #define CZW 050 #define CZW 1 51 51 52 52 # define USE_GAUSS_JORDAN 1 … … 1030 1030 } 1031 1031 1032 // This function assumes the input vectors (f, fEval, fErr) all have the same type 1033 // This requirement is already enforced in the calling function (psVectorIRLSFitPolynomial1D) 1034 psVector *psVector_GetModifiedErrors_Caucy ( 1035 const psVector *f, 1036 const psVector *fEval, 1037 const psVector *fErr, 1038 const psVector *mask, 1039 psVectorMaskType maskValue) { 1040 1041 psVector *mErr = psVectorAlloc (f->n, f->type.type); 1042 1043 switch (f->type.type) { 1044 case PS_TYPE_F64: 1045 { 1046 psF64 *fPtr = f->data.F64; 1047 psF64 *fErrPtr = fErr->data.F64; 1048 psF64 *mErrPtr = mErr->data.F64; 1049 psF64 *fEvalPtr = fEval->data.F64; 1050 for (int i = 0; i < f->n; i++, fPtr++, fEvalPtr++, fErrPtr++, mErrPtr++) { 1051 if (mask && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) continue; 1052 double dF = (*fPtr - *fEvalPtr) / 2.385; 1053 double dV = PS_SQR(*fErrPtr) + PS_SQR(dF); 1054 *mErrPtr = sqrt(dV); 1055 } 1056 } 1057 break; 1058 case PS_TYPE_F32: 1059 { 1060 psF32 *fPtr = f->data.F32; 1061 psF32 *fErrPtr = fErr->data.F32; 1062 psF32 *mErrPtr = mErr->data.F32; 1063 psF32 *fEvalPtr = fEval->data.F32; 1064 for (int i = 0; i < f->n; i++, fPtr++, fEvalPtr++, fErrPtr++, mErrPtr++) { 1065 if (mask && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) continue; 1066 double dF = (*fPtr - *fEvalPtr) / 2.385; 1067 double dV = PS_SQR(*fErrPtr) + PS_SQR(dF); 1068 *mErrPtr = sqrt(dV); 1069 } 1070 } 1071 break; 1072 default: 1073 psError(PS_ERR_UNKNOWN, false, "invalid input data type.\n"); 1074 return NULL; 1075 } 1076 return mErr; 1077 } 1078 1032 1079 // These should probably be tunable: 1033 1080 # define FIT_TOLERANCE 1e-4 … … 1036 1083 1037 1084 // This function accepts F32 and F64 input vectors. 1085 // 1038 1086 bool psVectorIRLSFitPolynomial1D( 1039 1087 psPolynomial1D *poly, 1088 psStats *stats, 1040 1089 const psVector *mask, 1041 1090 psVectorMaskType maskValue, … … 1078 1127 } 1079 1128 1080 // IRLS fitting is performed by adjusting the total weights for each point based on 1081 // the distance of the value from the last fit. start with weights set to 1.0 (the 1082 // max) and adjust as needed. 1083 1084 psVector *weights = psVectorAlloc(f->n, PS_TYPE_F64); 1085 psVectorInit (weights, 1.0); 1086 1087 // initial fit with weights set to 1.0 1129 // initial fit with nominal errors 1088 1130 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, fErr, x)) { 1089 1131 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1090 1132 if (xIn == NULL) psFree(x); 1091 psFree (weights);1092 1133 return false; 1093 1134 } 1094 1135 1095 psVector *fEval = psPolynomial1DEvalVector (poly, x); 1096 1097 for (psS32 N = 0; N < stats->clipIter; N++) { 1136 // use polyOld to save the last fit 1137 psPolynomial1D *polyOld = NULL; 1138 1139 // use clipIter as max number of iterations 1140 bool converged = false; 1141 for (psS32 N = 0; !converged && (N < stats->clipIter); N++) { 1098 1142 psTrace("psLib.math", 6, "Loop iteration %d. Calling psVectorFitPolynomial1D()\n", N); 1099 psS32 Nkeep = 0; 1100 if (psTraceGetLevel("psLib.math") >= 6) { 1101 if (mask != NULL) { 1102 for (psS32 i = 0 ; i < mask->n ; i++) { 1103 psTrace("psLib.math", 6, "mask[%d] is %d\n", i, mask->data.PS_TYPE_VECTOR_MASK_DATA[i]); 1104 } 1105 } 1106 } 1107 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, fErr, x)) { 1143 1144 // evaluate the fit at the input positions 1145 psVector *fEval = psPolynomial1DEvalVector (poly, x); 1146 1147 // calculate modified errors based on the deviation from the fit 1148 psVector *modErr = psVector_GetModifiedErrors_Caucy (f, fEval, fErr, mask, maskValue); 1149 psFree (fEval); 1150 1151 // save the last fit (recycle the structure once allocated) 1152 polyOld = psPolynomial1DCopy (polyOld, poly); 1153 1154 // calculate a new fit with modified errors: 1155 if (!psVectorFitPolynomial1D(poly, mask, maskValue, f, modErr, x)) { 1108 1156 psError(PS_ERR_UNKNOWN, false, "Could not fit polynomial. Returning false.\n"); 1109 if (xIn == NULL) { 1110 psFree(x); 1111 } 1112 psFree(resid); 1113 1157 if (xIn == NULL) psFree(x); 1158 psFree(modErr); 1114 1159 return false; 1115 1160 } 1116 1161 1117 psVector *fit = psPolynomial1DEvalVector(poly, x); 1118 if (fit == NULL) { 1119 psError(PS_ERR_UNKNOWN, false, "Could not call psPolynomial3DEvalVector(). Returning false.\n"); 1120 if (xIn == NULL) { 1121 psFree(x); 1122 } 1123 psFree(resid); 1124 return false; 1125 } 1126 for (psS32 i = 0 ; i < f->n ; i++) { 1127 if (f->type.type == PS_TYPE_F64) { 1128 resid->data.F64[i] = f->data.F64[i] - fit->data.F64[i]; 1129 } else { 1130 resid->data.F64[i] = (psF64) (f->data.F32[i] - fit->data.F32[i]); 1131 } 1132 } 1133 if (psTraceGetLevel("psLib.math") >= 6) { 1134 if (mask != NULL) { 1135 for (psS32 i = 0 ; i < mask->n ; i++) { 1136 if (!((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue))) { 1137 psTrace("psLib.math", 6, "(f, fit)[%d] is (%f, %f). resid is (%f)\n", 1138 i, f->data.F32[i], fit->data.F32[i], resid->data.F64[i]); 1139 } 1140 } 1141 } 1142 } 1143 1144 if (!psVectorStats(stats, resid, NULL, mask, maskValue)) { 1145 psError(PS_ERR_UNKNOWN, false, "Could not compute statistics on the resid vector. Returning false.\n"); 1146 psFree(resid); 1147 psFree(fit); 1148 return false; 1149 } 1150 1151 double meanValue = psStatsGetValue (stats, meanOption); 1152 double stdevValue = psStatsGetValue (stats, stdevOption); 1153 1154 psTrace("psLib.math", 5, "Mean is %f\n", meanValue); 1155 psTrace("psLib.math", 5, "Stdev is %f\n", stdevValue); 1156 psF32 minClipValue = -minClipSigma*stdevValue; 1157 psF32 maxClipValue = +maxClipSigma*stdevValue; 1158 1159 // set mask if pts are not valid 1160 // we are masking out any point which is out of range 1161 // recovery is not allowed with this scheme 1162 for (psS32 i = 0; i < resid->n; i++) { 1163 if ((mask != NULL) && (mask->data.PS_TYPE_VECTOR_MASK_DATA[i] & maskValue)) { 1164 continue; 1165 } 1166 1167 if ((resid->data.F64[i] - meanValue > maxClipValue) || (resid->data.F64[i] - meanValue < minClipValue)) { 1168 if (f->type.type == PS_TYPE_F64) { 1169 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 1170 i, fit->data.F64[i], i, resid->data.F64[i]); 1171 } else { 1172 psTrace("psLib.math", 6, "Masking element %d (%f). resid->data.F64[%d] is %f\n", 1173 i, fit->data.F32[i], i, resid->data.F64[i]); 1174 } 1175 1176 if (mask != NULL) { 1177 mask->data.PS_TYPE_VECTOR_MASK_DATA[i] |= 0x01; 1178 } 1179 continue; 1180 } 1181 Nkeep++; 1182 } 1183 1184 // 1185 // We should probably exit this loop if no new elements were masked 1186 // since the polynomial fit won't change. 1187 // 1188 psTrace("psLib.math", 6, "keeping %d of %ld pts for fit\n", Nkeep, x->n); 1189 stats->clippedNvalues = Nkeep; 1190 psFree(fit); 1191 } 1192 1193 // Free psVectors that were created for NULL arguments. 1194 if (xIn == NULL) { 1195 psFree(x); 1196 } 1197 // Free other local temporary variables 1198 psFree(resid); 1162 // has the solution converged? 1163 converged = true; 1164 for (int ix = 0; ix <= poly->nX; ix++) { 1165 if ((fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FIT_TOLERANCE * fabs(poly->coeff[ix])) && 1166 (fabs(poly->coeff[ix] - polyOld->coeff[ix]) > FLT_TOLERANCE)) 1167 converged = false; 1168 } 1169 1170 psFree (modErr); 1171 } 1172 1173 // Free local temporary variables 1174 if (xIn == NULL) psFree(x); 1175 psFree(polyOld); 1199 1176 1200 1177 psTrace("psLib.math", 3, "---- %s() end ----\n", __func__);
Note:
See TracChangeset
for help on using the changeset viewer.
