File indexing completed on 2024-05-12 03:47:50
0001 /* 0002 File : nsl_diff.c 0003 Project : LabPlot 0004 Description : NSL numerical differentiation functions 0005 -------------------------------------------------------------------- 0006 SPDX-FileCopyrightText: 2016 Stefan Gerlach <stefan.gerlach@uni.kn> 0007 0008 SPDX-License-Identifier: GPL-2.0-or-later 0009 */ 0010 0011 /* TODO: 0012 * add more orders 0013 */ 0014 0015 #include "nsl_diff.h" 0016 #include "nsl_common.h" 0017 #include "nsl_sf_poly.h" 0018 0019 const char* nsl_diff_deriv_order_name[] = {i18n("First"), i18n("Second"), i18n("Third"), i18n("Fourth"), i18n("Fifth"), i18n("Sixth")}; 0020 0021 double nsl_diff_first_central(double xm, double fm, double xp, double fp) { 0022 return (fp - fm) / (xp - xm); 0023 } 0024 0025 int nsl_diff_deriv_first_equal(const double* x, double* y, const size_t n) { 0026 if (n < 3) 0027 return -1; 0028 0029 double dy = 0, oldy = 0, oldy2 = 0; 0030 size_t i; 0031 for (i = 0; i < n; i++) { 0032 if (i == 0) /* forward */ 0033 dy = (-y[2] + 4. * y[1] - 3. * y[0]) / (x[2] - x[0]); 0034 else if (i == n - 1) { /* backward */ 0035 y[i] = (3. * y[i] - 4. * y[i - 1] + y[i - 2]) / (x[i] - x[i - 2]); 0036 y[i - 1] = oldy; 0037 } else 0038 dy = (y[i + 1] - y[i - 1]) / (x[i + 1] - x[i - 1]); 0039 0040 if (i > 1) 0041 y[i - 2] = oldy2; 0042 if (i > 0 && i < n - 1) 0043 oldy2 = oldy; 0044 0045 oldy = dy; 0046 } 0047 0048 return 0; 0049 } 0050 0051 int nsl_diff_first_deriv(const double* x, double* y, const size_t n, int order) { 0052 switch (order) { 0053 case 2: 0054 return nsl_diff_first_deriv_second_order(x, y, n); 0055 case 4: 0056 return nsl_diff_first_deriv_fourth_order(x, y, n); 0057 /*TODO: higher order */ 0058 default: 0059 printf("nsl_diff_first_deriv() unsupported order %d\n", order); 0060 return -1; 0061 } 0062 } 0063 0064 int nsl_diff_first_deriv_second_order(const double* x, double* y, const size_t n) { 0065 if (n < 3) 0066 return -1; 0067 0068 double dy = 0, oldy = 0, oldy2 = 0, xdata[3], ydata[3]; 0069 size_t i, j; 0070 for (i = 0; i < n; i++) { 0071 if (i == 0) { 0072 /* 3-point forward */ 0073 for (j = 0; j < 3; j++) 0074 xdata[j] = x[j], ydata[j] = y[j]; 0075 dy = nsl_sf_poly_interp_lagrange_2_deriv(x[0], xdata, ydata); 0076 } else if (i < n - 1) { 0077 /* 3-point center */ 0078 for (j = 0; j < 3; j++) 0079 xdata[j] = x[i - 1 + j], ydata[j] = y[i - 1 + j]; 0080 dy = nsl_sf_poly_interp_lagrange_2_deriv(x[i], xdata, ydata); 0081 } else if (i == n - 1) { 0082 /* 3-point backward */ 0083 y[i] = nsl_sf_poly_interp_lagrange_2_deriv(x[i], xdata, ydata); 0084 y[i - 1] = oldy; 0085 } 0086 0087 if (i > 1) 0088 y[i - 2] = oldy2; 0089 if (i > 0 && i < n - 1) 0090 oldy2 = oldy; 0091 0092 oldy = dy; 0093 } 0094 0095 return 0; 0096 } 0097 0098 int nsl_diff_first_deriv_fourth_order(const double* x, double* y, const size_t n) { 0099 if (n < 5) 0100 return -1; 0101 0102 double dy[5] = {0}, xdata[5], ydata[5]; 0103 size_t i, j; 0104 for (i = 0; i < n; i++) { 0105 if (i == 0) 0106 for (j = 0; j < 5; j++) 0107 xdata[j] = x[j], ydata[j] = y[j]; 0108 else if (i > 1 && i < n - 2) 0109 for (j = 0; j < 5; j++) 0110 xdata[j] = x[i - 2 + j], ydata[j] = y[i - 2 + j]; 0111 0112 /* 5-point rule */ 0113 dy[0] = nsl_sf_poly_interp_lagrange_4_deriv(x[i], xdata, ydata); 0114 0115 if (i == n - 1) 0116 for (j = 0; j < 4; j++) 0117 y[i - j] = dy[j]; 0118 0119 if (i > 3) 0120 y[i - 4] = dy[4]; 0121 for (j = 4; j > 0; j--) 0122 if (i >= j - 1) 0123 dy[j] = dy[j - 1]; 0124 } 0125 0126 return 0; 0127 } 0128 0129 int nsl_diff_first_deriv_avg(const double* x, double* y, const size_t n) { 0130 if (n < 1) 0131 return -1; 0132 0133 size_t i; 0134 double dy = 0, oldy = 0; 0135 for (i = 0; i < n; i++) { 0136 if (i == 0) 0137 dy = (y[1] - y[0]) / (x[1] - x[0]); 0138 else if (i == n - 1) 0139 y[i] = (y[i] - y[i - 1]) / (x[i] - x[i - 1]); 0140 else 0141 dy = ((y[i + 1] - y[i]) / (x[i + 1] - x[i]) + (y[i] - y[i - 1]) / (x[i] - x[i - 1])) / 2.; 0142 0143 if (i > 0) 0144 y[i - 1] = oldy; 0145 0146 oldy = dy; 0147 } 0148 0149 return 0; 0150 } 0151 0152 int nsl_diff_second_deriv(const double* x, double* y, const size_t n, int order) { 0153 switch (order) { 0154 case 1: 0155 return nsl_diff_second_deriv_first_order(x, y, n); 0156 case 2: 0157 return nsl_diff_second_deriv_second_order(x, y, n); 0158 case 3: 0159 return nsl_diff_second_deriv_third_order(x, y, n); 0160 /*TODO: higher order */ 0161 default: 0162 printf("nsl_diff_second_deriv() unsupported order %d\n", order); 0163 return -1; 0164 } 0165 } 0166 0167 int nsl_diff_second_deriv_first_order(const double* x, double* y, const size_t n) { 0168 if (n < 3) 0169 return -1; 0170 0171 double dy[3] = {0}, xdata[3], ydata[3]; 0172 size_t i, j; 0173 for (i = 0; i < n; i++) { 0174 if (i == 0) 0175 for (j = 0; j < 3; j++) 0176 xdata[j] = x[j], ydata[j] = y[j]; 0177 else if (i > 1 && i < n - 1) 0178 for (j = 0; j < 3; j++) 0179 xdata[j] = x[i - 1 + j], ydata[j] = y[i - 1 + j]; 0180 0181 /* 3-point rule */ 0182 dy[0] = nsl_sf_poly_interp_lagrange_2_deriv2(xdata, ydata); 0183 0184 if (i == n - 1) { 0185 y[i] = dy[0]; 0186 y[i - 1] = dy[1]; 0187 } 0188 0189 if (i > 1) 0190 y[i - 2] = dy[2]; 0191 if (i > 0) 0192 dy[2] = dy[1]; 0193 0194 dy[1] = dy[0]; 0195 } 0196 0197 return 0; 0198 } 0199 0200 int nsl_diff_second_deriv_second_order(const double* x, double* y, const size_t n) { 0201 if (n < 4) 0202 return -1; 0203 0204 double dy[4] = {0}, xdata[4], ydata[4]; 0205 size_t i, j; 0206 for (i = 0; i < n; i++) { 0207 if (i == 0) { 0208 /* 4-point forward */ 0209 for (j = 0; j < 4; j++) 0210 xdata[j] = x[j], ydata[j] = y[j]; 0211 dy[0] = nsl_sf_poly_interp_lagrange_3_deriv2(x[i], xdata, ydata); 0212 } else if (i == n - 1) { 0213 /* 4-point backward */ 0214 for (j = 0; j < 4; j++) 0215 xdata[j] = x[i - 3 + j], ydata[j] = y[i - 3 + j]; 0216 y[i] = nsl_sf_poly_interp_lagrange_3_deriv2(x[i], xdata, ydata); 0217 y[i - 1] = dy[1]; 0218 y[i - 2] = dy[2]; 0219 } else { 0220 /* 3-point center */ 0221 for (j = 0; j < 3; j++) 0222 xdata[j] = x[i - 1 + j], ydata[j] = y[i - 1 + j]; 0223 dy[0] = nsl_sf_poly_interp_lagrange_2_deriv2(xdata, ydata); 0224 } 0225 0226 if (i > 2) 0227 y[i - 3] = dy[3]; 0228 for (j = 3; j > 0; j--) 0229 if (i >= j - 1) 0230 dy[j] = dy[j - 1]; 0231 } 0232 0233 return 0; 0234 } 0235 0236 int nsl_diff_second_deriv_third_order(const double* x, double* y, const size_t n) { 0237 if (n < 5) 0238 return -1; 0239 0240 double dy[5] = {0}, xdata[5], ydata[5]; 0241 size_t i, j; 0242 for (i = 0; i < n; i++) { 0243 if (i == 0) 0244 for (j = 0; j < 5; j++) 0245 xdata[j] = x[j], ydata[j] = y[j]; 0246 else if (i > 2 && i < n - 3) 0247 for (j = 0; j < 5; j++) 0248 xdata[j] = x[i - 2 + j], ydata[j] = y[i - 2 + j]; 0249 0250 /* 5-point rule */ 0251 dy[0] = nsl_sf_poly_interp_lagrange_4_deriv2(x[i], xdata, ydata); 0252 0253 if (i == n - 1) 0254 for (j = 0; j < 4; j++) 0255 y[i - j] = dy[j]; 0256 0257 if (i > 3) 0258 y[i - 4] = dy[4]; 0259 for (j = 4; j > 0; j--) 0260 if (i >= j - 1) 0261 dy[j] = dy[j - 1]; 0262 } 0263 0264 return 0; 0265 } 0266 0267 int nsl_diff_third_deriv(const double* x, double* y, const size_t n, int order) { 0268 switch (order) { 0269 case 2: 0270 return nsl_diff_third_deriv_second_order(x, y, n); 0271 /*TODO: higher order */ 0272 default: 0273 printf("nsl_diff_third_deriv() unsupported order %d\n", order); 0274 return -1; 0275 } 0276 } 0277 0278 int nsl_diff_third_deriv_second_order(const double* x, double* y, const size_t n) { 0279 if (n < 5) 0280 return -1; 0281 0282 double dy[5] = {0}, xdata[5], ydata[5]; 0283 size_t i, j; 0284 for (i = 0; i < n; i++) { 0285 if (i == 0) 0286 for (j = 0; j < 5; j++) 0287 xdata[j] = x[j], ydata[j] = y[j]; 0288 else if (i > 2 && i < n - 3) 0289 for (j = 0; j < 5; j++) 0290 xdata[j] = x[i - 2 + j], ydata[j] = y[i - 2 + j]; 0291 0292 /* 5-point rule */ 0293 dy[0] = nsl_sf_poly_interp_lagrange_4_deriv3(x[i], xdata, ydata); 0294 0295 if (i == n - 1) 0296 for (j = 0; j < 4; j++) 0297 y[i - j] = dy[j]; 0298 0299 if (i > 3) 0300 y[i - 4] = dy[4]; 0301 for (j = 4; j > 0; j--) 0302 if (i >= j - 1) 0303 dy[j] = dy[j - 1]; 0304 } 0305 0306 return 0; 0307 } 0308 0309 int nsl_diff_fourth_deriv(const double* x, double* y, const size_t n, int order) { 0310 switch (order) { 0311 case 1: 0312 return nsl_diff_fourth_deriv_first_order(x, y, n); 0313 case 3: 0314 return nsl_diff_fourth_deriv_third_order(x, y, n); 0315 /*TODO: higher order */ 0316 default: 0317 printf("nsl_diff_fourth_deriv() unsupported order %d\n", order); 0318 return -1; 0319 } 0320 } 0321 0322 int nsl_diff_fourth_deriv_first_order(const double* x, double* y, const size_t n) { 0323 if (n < 5) 0324 return -1; 0325 0326 double dy[5] = {0}, xdata[5], ydata[5]; 0327 size_t i, j; 0328 for (i = 0; i < n; i++) { 0329 if (i == 0) 0330 for (j = 0; j < 5; j++) 0331 xdata[j] = x[j], ydata[j] = y[j]; 0332 else if (i > 2 && i < n - 3) 0333 for (j = 0; j < 5; j++) 0334 xdata[j] = x[i - 2 + j], ydata[j] = y[i - 2 + j]; 0335 0336 /* 5-point rule */ 0337 dy[0] = nsl_sf_poly_interp_lagrange_4_deriv4(xdata, ydata); 0338 0339 if (i == n - 1) 0340 for (j = 0; j < 4; j++) 0341 y[i - j] = dy[j]; 0342 0343 if (i > 3) 0344 y[i - 4] = dy[4]; 0345 for (j = 4; j > 0; j--) 0346 if (i >= j - 1) 0347 dy[j] = dy[j - 1]; 0348 } 0349 0350 return 0; 0351 } 0352 0353 int nsl_diff_fourth_deriv_third_order(const double* x, double* y, const size_t n) { 0354 if (n < 7) 0355 return -1; 0356 0357 double dy[7] = {0}, xdata[7], ydata[7]; 0358 size_t i, j; 0359 for (i = 0; i < n; i++) { 0360 if (i == 0) 0361 for (j = 0; j < 7; j++) 0362 xdata[j] = x[j], ydata[j] = y[j]; 0363 else if (i > 3 && i < n - 4) 0364 for (j = 0; j < 7; j++) 0365 xdata[j] = x[i - 3 + j], ydata[j] = y[i - 3 + j]; 0366 0367 /* 7-point rule */ 0368 dy[0] = nsl_sf_poly_interp_lagrange_6_deriv4(x[i], xdata, ydata); 0369 0370 if (i == n - 1) 0371 for (j = 0; j < 6; j++) 0372 y[i - j] = dy[j]; 0373 0374 if (i > 5) 0375 y[i - 6] = dy[6]; 0376 for (j = 6; j > 0; j--) 0377 if (i >= j - 1) 0378 dy[j] = dy[j - 1]; 0379 } 0380 0381 return 0; 0382 } 0383 0384 int nsl_diff_fifth_deriv(const double* x, double* y, const size_t n, int order) { 0385 switch (order) { 0386 case 2: 0387 return nsl_diff_fifth_deriv_second_order(x, y, n); 0388 /*TODO: higher order */ 0389 default: 0390 printf("nsl_diff_fifth_deriv() unsupported order %d\n", order); 0391 return -1; 0392 } 0393 } 0394 0395 int nsl_diff_fifth_deriv_second_order(const double* x, double* y, const size_t n) { 0396 if (n < 7) 0397 return -1; 0398 0399 double dy[7] = {0}, xdata[7], ydata[7]; 0400 size_t i, j; 0401 for (i = 0; i < n; i++) { 0402 if (i == 0) 0403 for (j = 0; j < 7; j++) 0404 xdata[j] = x[j], ydata[j] = y[j]; 0405 else if (i > 3 && i < n - 4) 0406 for (j = 0; j < 7; j++) 0407 xdata[j] = x[i - 3 + j], ydata[j] = y[i - 3 + j]; 0408 0409 /* 7-point rule */ 0410 dy[0] = nsl_sf_poly_interp_lagrange_6_deriv5(x[i], xdata, ydata); 0411 0412 if (i == n - 1) 0413 for (j = 0; j < 6; j++) 0414 y[i - j] = dy[j]; 0415 0416 if (i > 5) 0417 y[i - 6] = dy[6]; 0418 for (j = 6; j > 0; j--) 0419 if (i >= j - 1) 0420 dy[j] = dy[j - 1]; 0421 } 0422 0423 return 0; 0424 } 0425 0426 int nsl_diff_sixth_deriv(const double* x, double* y, const size_t n, int order) { 0427 switch (order) { 0428 case 1: 0429 return nsl_diff_sixth_deriv_first_order(x, y, n); 0430 /*TODO: higher order */ 0431 default: 0432 printf("nsl_diff_sixth_deriv() unsupported order %d\n", order); 0433 return -1; 0434 } 0435 } 0436 0437 int nsl_diff_sixth_deriv_first_order(const double* x, double* y, const size_t n) { 0438 if (n < 7) 0439 return -1; 0440 0441 double dy[7] = {0}, xdata[7], ydata[7]; 0442 size_t i, j; 0443 for (i = 0; i < n; i++) { 0444 if (i == 0) 0445 for (j = 0; j < 7; j++) 0446 xdata[j] = x[j], ydata[j] = y[j]; 0447 else if (i > 3 && i < n - 4) 0448 for (j = 0; j < 7; j++) 0449 xdata[j] = x[i - 3 + j], ydata[j] = y[i - 3 + j]; 0450 0451 /* 7-point rule */ 0452 dy[0] = nsl_sf_poly_interp_lagrange_6_deriv6(xdata, ydata); 0453 0454 if (i == n - 1) 0455 for (j = 0; j < 6; j++) 0456 y[i - j] = dy[j]; 0457 0458 if (i > 5) 0459 y[i - 6] = dy[6]; 0460 for (j = 6; j > 0; j--) 0461 if (i >= j - 1) 0462 dy[j] = dy[j - 1]; 0463 } 0464 0465 return 0; 0466 }