请用C语言写一份完整的Savitzky-Golay filter算法


# Savitzky-Golay Filter in C Below is a complete implementation of the Savitzky-Golay filter in C. This implementation includes functions for calculating the filter coefficients and applying the filter to a data set. ```c #include <stdio.h> #include <stdlib.h> #include <math.h> // Function to calculate the Savitzky-Golay coefficients void savitzky_golay_coeff(int window_size, int poly_order, double* coeff) { int half_window = window_size / 2; double A[(2*poly_order+1) * window_size]; double AtA[(2*poly_order+1) * (2*poly_order+1)]; double invAtA[(2*poly_order+1) * (2*poly_order+1)]; // Construct the design matrix A for (int i = -half_window; i <= half_window; i++) { for (int j = 0; j <= poly_order; j++) { A[(i + half_window) * (poly_order + 1) + j] = pow(i, j); } } // Compute A^T * A for (int i = 0; i <= poly_order; i++) { for (int j = 0; j <= poly_order; j++) { AtA[i * (poly_order + 1) + j] = 0.0; for (int k = 0; k < window_size; k++) { AtA[i * (poly_order + 1) + j] += A[k * (poly_order + 1) + i] * A[k * (poly_order + 1) + j]; } } } // Compute inverse of A^T * A (using simple inversion for small matrices) double det = 0.0; if (poly_order == 2) { // For quadratic polynomial det = AtA[0]*(AtA[4]*AtA[8]-AtA[5]*AtA[7]) - AtA[1]*(AtA[3]*AtA[8]-AtA[5]*AtA[6]) + AtA[2]*(AtA[3]*AtA[7]-AtA[4]*AtA[6]); invAtA[0] = (AtA[4]*AtA[8] - AtA[5]*AtA[7]) / det; invAtA[1] = (AtA[2]*AtA[7] - AtA[1]*AtA[8]) / det; invAtA[2] = (AtA[1]*AtA[5] - AtA[2]*AtA[4]) / det; invAtA[3] = (AtA[5]*AtA[6] - AtA[3]*AtA[8]) / det; invAtA[4] = (AtA[0]*AtA[8] - AtA[2]*AtA[6]) / det; invAtA[5] = (AtA[2]*AtA[3] - AtA[0]*AtA[5]) / det; invAtA[6] = (AtA[3]*AtA[7] - AtA[4]*AtA[6]) / det; invAtA[7] = (AtA[1]*AtA[6] - AtA[0]*AtA[7]) / det; invAtA[8] = (AtA[0]*AtA[4] - AtA[1]*AtA[3]) / det; } else { // For linear polynomial (simpler case) det = AtA[0]*AtA[3] - AtA[1]*AtA[1]; invAtA[0] = AtA[3] / det; invAtA[1] = -AtA[1] / det; invAtA[2] = -AtA[1] / det; invAtA[3] = AtA[0] / det; } // Compute the coefficients for the middle point (smoothing) for (int i = 0; i < window_size; i++) { coeff[i] = 0.0; for (int j = 0; j <= poly_order; j++) { for (int k = 0; k <= poly_order; k++) { coeff[i] += A[i * (poly_order + 1) + k] * invAtA[k * (poly_order + 1) + j] * A[half_window * (poly_order + 1) + j]; } } } } // Function to apply Savitzky-Golay filter to data void apply_savitzky_golay(double* input, double* output, int data_size, int window_size, int poly_order) { double* coeff = (double*)malloc(window_size * sizeof(double)); savitzky_golay_coeff(window_size, poly_order, coeff); int half_window = window_size / 2; // Handle boundaries by simple copying (could be improved) for (int i = 0; i < half_window; i++) { output[i] = input[i]; output[data_size - 1 - i] = input[data_size - 1 - i]; } // Apply filter to middle points for (int i = half_window; i < data_size - half_window; i++) { output[i] = 0.0; for (int j = -half_window; j <= half_window; j++) { output[i] += coeff[j + half_window] * input[i + j]; } } free(coeff); } int main() { // Example usage const int data_size = 20; double input[data_size] = {1.2, 1.5, 1.7, 1.4, 1.6, 1.8, 2.0, 2.1, 2.3, 2.2, 2.0, 1.9, 1.7, 1.6, 1.5, 1.4, 1.3, 1.2, 1.1, 1.0}; double output[data_size]; int window_size = 5; // Must be odd int poly_order = 2; // Typically 2 (quadratic) or 3 (cubic) apply_savitzky_golay(input, output, data_size, window_size, poly_order); printf("Original Data\tSmoothed Data\n"); for (int i = 0; i < data_size; i++) { printf("%.2f\t\t%.2f\n", input[i], output[i]); } return 0; } ``` ## 代码说明 1. `savitzky_golay_coeff`函数计算Savitzky-Golay滤波器的系数矩阵 2. `apply_savitzky_golay`函数将滤波器应用于输入数据 3. 主函数演示了如何使用这些函数处理示例数据 ## 使用注意事项 1. 窗口大小(window_size)必须是奇数 2. 多项式阶数(poly_order)通常选择2(二次)或3(三次) 3. 边界处理采用了简单的复制方法,可以根据需要改进 4. 矩阵求逆部分目前只实现了线性和二次多项式的情况 ## 额外需要注意的逻辑点 1. 窗口大小和多项式阶数的选择会影响滤波效果,窗口越大平滑效果越强但可能丢失细节 2. 边界处理可以改进为使用较小的窗口或镜像数据等方法 3. 对于更高阶多项式,需要实现更通用的矩阵求逆算法 [2025-07-22 17:58:35 | AI写代码神器 | 1730点数解答]
- 采用 savitzky-golay 滤波方法对光谱曲线进行平滑滤波处理,消除毛刺噪声。对平滑处理后的光谱曲线进行一阶求导,根据一阶导数计算红边位置、红边幅值和红边面积。 红边位置 rep 为680~760nm波长范围内光谱一阶导数最大值对应的波长。 红边幅值为680~760nm波长范围内光谱一阶导数的最大值: dr=max┬(680≤λ≤760)〖ρ_λ^' 〗 式中,dr为红边幅值;ρ_λ^'为光谱一阶导数;λ为波长。 红边面积为680~760mm波长范围内光谱一阶导数的积分: sdr=∫_680^760▒〖ρ_λ^' dλ〗 式中,sdr为红边面积; ρ_λ^'为光谱一阶导数; λ为波长。 要求:计算所给光谱曲线的红边位置、红边幅值和红边面积。 提示: (1)savitzky-golay 滤波: result = savgol( nleft, nright, order, degree [, /double] ) 返回一个savitzky-golay平滑滤波器的系数,然后可以作为convol函数的卷积核,本实验中使用result = savgol( 5, 5, 0, 2 ) ((927点数解答 | 2024-11-13 13:10:27)542
- 采用 savitzky-golay 滤波方法对光谱曲线进行平滑滤波处理,使用verilog语言,使用二阶,7点的savitzky-golay 滤波器,输入数据是8bit,输出数据也是8bit,均为无符号数,计算过程也是无符号数 (404点数解答 | 2025-05-14 16:28:03)127
- savitzky-golay 实现的具体过程(319点数解答 | 2024-12-20 14:16:01)162
- 帮我做一款我的世界基岩版,c++完整 (182点数解答 | 2025-02-22 15:53:11)146
- VERILOG 写一个二次多项式 Savitzky-Golay滤波 (829点数解答 | 2025-07-29 09:52:39)69
- 请用“book”写几段示例英语日常用语句子,带翻译(229点数解答 | 2024-03-23 14:52:33)239
- 请用“applaud”写几段示例英语日常用语句子,统一格式输出:英文放第一行,翻译放第二行。(150点数解答 | 2024-03-23 15:23:55)206
- 请用“applaud”写几段示例英语日常用语句子,统一格式输出:英语句子放第一行,句子对应的翻译放第二行。(20点数解答 | 2024-03-23 15:24:42)212
- 请用“applaud”写几段示例英语日常用语句子,统一格式输出:英文放第一行,翻译放第二行。(215点数解答 | 2024-03-23 15:33:10)218
- 2 状态图 车辆行驶过程中有以下几种状态,如:启动、怠速、加速、减速、匀速、停止,请用 uml 状态图画出各种状态之间的转换关系。 使用环境为vsode下的plantuml(163点数解答 | 2024-08-13 13:57:14)361
- 车辆行驶过程中有以下几种状态,如:启动、怠速、加速、减速、匀速、停止,请用 uml 状态图画出各种状态之间的转换关系。(828点数解答 | 2024-08-14 23:18:48)360
- 车辆行驶过程中有以下几种状态,如:启动、怠速、加速、减速、匀速、停止,请用 uml 状态图画出各种状态之间的转换关系。(574点数解答 | 2024-08-14 23:19:19)319