diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000000000000000000000000000000000000..7d6b0fe0d26a0fc06129c48811a524b87dc050c3 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,22 @@ +{ + "configurations": [ + { + "name": "Win32", + "includePath": [ + "${default}", + "${workspaceFolder}", + "${workspaceFolder}/lib_bdsp" + ], + "defines": [ + "_DEBUG", + "UNICODE", + "_UNICODE" + ], + "compilerPath": "D:\\MinGW\\bin\\gcc.exe", + "cStandard": "c11", + "cppStandard": "gnu++14", + "intelliSenseMode": "windows-gcc-x86" + } + ], + "version": 4 +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000000000000000000000000000000000..83fe76a2c617b5634b7ebb3c8d835707388bd2af --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,9 @@ +{ + "files.associations": { + "mdsp_config.h": "c", + "dsp_common.h": "c", + "functional": "c", + "fft_tab.h": "c", + "fft.h": "c" + } +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/.vscode/tasks.json" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/.vscode/tasks.json" new file mode 100644 index 0000000000000000000000000000000000000000..6a9cf5639ab64bcbf72355b59104704fbd90f305 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/.vscode/tasks.json" @@ -0,0 +1,28 @@ +{ + "tasks": [ + { + "type": "cppbuild", + "label": "C/C++: gcc.exe 生成活动文件", + "command": "D:\\Tools\\MinGW\\bin\\gcc.exe", + "args": [ + "-fdiagnostics-color=always", + "-g", + "${file}", + "-o", + "${fileDirname}\\${fileBasenameNoExtension}.exe" + ], + "options": { + "cwd": "${fileDirname}" + }, + "problemMatcher": [ + "$gcc" + ], + "group": { + "kind": "build", + "isDefault": true + }, + "detail": "调试器生成的任务。" + } + ], + "version": "2.0.0" +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmp.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmp.c" new file mode 100644 index 0000000000000000000000000000000000000000..a85c7363ef644dd2f7ab06125098470b4a82cd86 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmp.c" @@ -0,0 +1,50 @@ +#include +#include + +/* DSP配置结构体定义 */ +typedef struct { + int windowType; // 窗函数类型 + // 可以添加其他DSP相关配置参数 +} DspConfig; + +/** + * 将FFT频谱转换为幅值谱 + * @param Spectrum 输入的FFT频谱数组指针 + * @param FFTAmp 输出的幅值谱数组指针 + * @param length 数组长度 + * @param config DSP配置结构体指针 + * @return 0:成功, -1:参数错误 + * + * 窗函数类型: + * 1: 汉宁窗 + * 2: 海明窗 + * 3: 黑曼窗 + * 4: 平顶窗 + * 5: 凯塞窗 + * 其他: 不加窗 + */ +int bdsp_ConvertFFTAmp(float *Spectrum, float *FFTAmp, int length, const DspConfig *config) { + // 参数检查 + if (Spectrum == NULL || FFTAmp == NULL || config == NULL || length <= 0) { + return -1; + } + + // 定义转换系数数组 + const float convertCoeff[] = {2.0f, 1.8516f, 2.3810f, 4.18f, 2.49f, 1.0f}; + + // 确定使用的窗函数系数 + int windowIndex; + if (config->windowType >= 1 && config->windowType <= 5) { + windowIndex = config->windowType - 1; + } else { + windowIndex = 6; // 不加窗 + } + + // 计算幅值谱 + float coeff = convertCoeff[windowIndex]; + for (int i = 0; i < length; i++) { + FFTAmp[i] = Spectrum[i] * coeff; + } + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmpDB.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmpDB.c" new file mode 100644 index 0000000000000000000000000000000000000000..c01b0ee256c61865f89ccbadc7f35d6a27f6118e --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTAmpDB.c" @@ -0,0 +1,21 @@ +/** + * 将FFT幅值转换为分贝值 + * + * @param FFTAmp 输入参数,FFT幅值数组指针 + * @param dBref 输入参数,分贝转换的参考值 + * @param FFTAmpDB 输出参数,转换后的分贝值数组指针 + * @param len 输入参数,数组长度 + * + * @return 返回0表示正常执行完成 + */ +int bdsp_ConvertFFTAmpDB(float *FFTAmp, float dBref, float *FFTAmpDB, int len) +{ + int i; + for(i = 0; i < len; i++) { + /* 将FFT幅值转换为分贝值 + * 计算公式: dB = 20 * log10(幅值/参考值) + */ + FFTAmpDB[i] = 20.0f * log10f(FFTAmp[i] / dBref); + } + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTPwr.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTPwr.c" new file mode 100644 index 0000000000000000000000000000000000000000..e7e6776211fc9e6c0f218bd60950bdfdf273fbf4 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_ConvertFFTPwr.c" @@ -0,0 +1,53 @@ +#include +/** + * FFT频谱转换为功率谱函数 + * + * @param Spectrum 输入FFT频谱数组 + * @param FFTPwr 输出功率谱数组 + * @param sampleLength 采样点数/FFT点数 + * @param sampleRate 采样率(Hz) + * @param windowType 窗函数类型: + * 1: 汉宁窗 + * 2: 海明窗 + * 3: 黑曼窗 + * 4: 平顶窗 + * 5: 凯塞窗 + * 其他: 不加窗 + * + * @return 0: 成功 + * -1: 无效的输入参数 + */ +int bdsp_ConvertFFTPwr(const float *Spectrum, float *FFTPwr, + int sampleLength, float sampleRate, int windowType) +{ + + // 参数有效性检查 + if (Spectrum == NULL || FFTPwr == NULL || + sampleLength <= 0 || sampleRate <= 0) + { + return -1; + } + + // 定义各种窗函数的转换系数 + const float convertCoeff[] = {1.6338f, 1.5863f, 1.8119f, 2.26f, 1.85f, 1.0f}; + + // 选择对应的转换系数 + float coeff; + if (windowType >= 1 && windowType <= 5) + { + coeff = convertCoeff[windowType - 1]; + } + else + { + coeff = convertCoeff[5]; // 不加窗系数 + } + + // 计算功率谱 + + for (int i = 0; i < sampleLength; i++) + { + FFTPwr[i] = pow(Spectrum[i] * coeff, 2.0); + } + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_DataRestore.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_DataRestore.c" new file mode 100644 index 0000000000000000000000000000000000000000..e964c36be433da37a0305c55d8f0b27f81e252b5 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_DataRestore.c" @@ -0,0 +1,42 @@ +#include + +/** + * @brief 通道数据恢复的系数结构体 + * 用于存储数据恢复计算所需的各项系数 + */ +struct ChannelRestoreCoefficient +{ + float adjustCoefficient; // 调整系数:用于线性校准,对原始数据进行比例调整 + float offsetValue; // 偏移值:修正零点偏移,进行加减运算调整 + float sensitivity; // 灵敏度:传感器的响应系数,将数字量转换为物理量 +}; + +/** + * @brief 数据恢复计算函数 + * 根据输入数据和恢复系数计算实际物理量 + * 计算公式: outputData = adjustCoefficient * inputdata / sensitivity + offsetValue + * + * @param inputdata 输入数据指针,指向原始采集数据 + * @param coefficient 系数结构体指针,包含计算所需的各项系数 + * @param outputData 输出数据指针,用于存储计算后的结果 + * + * @return int 返回执行状态 + * 0: 执行成功 + * -1: 参数错误(空指针) + */ +int bdsp_DataRestore(float *inputdata, struct ChannelRestoreCoefficient *coefficient, float *outputData) +{ + // 参数有效性检查 + if (inputdata == NULL || coefficient == NULL || outputData == NULL) + { + return -1; // 错误处理:任一指针为空时返回错误码 + } + + // 数据恢复计算 + // 1. 原始数据乘以调整系数 + // 2. 除以灵敏度得到物理量 + // 3. 加上偏移值进行零点修正 + *outputData = coefficient->adjustCoefficient * (*inputdata) / coefficient->sensitivity + coefficient->offsetValue; + + return 0; // 计算成功返回0 +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FFTWeighting.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FFTWeighting.c" new file mode 100644 index 0000000000000000000000000000000000000000..60555ae63f696dd3d57934dc76d7dd83be4e5f76 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FFTWeighting.c" @@ -0,0 +1,77 @@ +#include +#include + +/** + * FFT频域计权 + * @param FFTPwr 输入/输出的功率谱数组指针 + * @param freqSeq 频率序列数组指针 + * @param length 数组长度 + * @param weightingType 计权类型(1:A计权, 2:B计权, 3:C计权) + * @return 0:成功, -1:参数错误, -2:不支持的计权类型 + */ +int bdsp_FFTWeighting(double *FFTPwr, const double *freqSeq, int length, uint32_t weightingType) { + // 参数检查 + if (FFTPwr == NULL || freqSeq == NULL || length <= 0) { + return -1; + } + + if (weightingType < 1 || weightingType > 3) { + return -2; + } + + // 定义特征频率 + const double f[] = {20.6, 107.7, 737.9, 12194.0}; + const double f4_2 = f[3] * f[3]; + + for (int i = 0; i < length; i++) { + double freq2 = freqSeq[i] * freqSeq[i]; + double w = 0.0; + + // 根据不同计权类型计算权重 + switch (weightingType) { + case 1: // A计权 + w = 2.0 + 10.0 * log10( + pow(f4_2 * pow(freqSeq[i], 4) / + ((freq2 + f[0] * f[0]) * + sqrt(freq2 + f[1] * f[1]) * + sqrt(freq2 + f[2] * f[2]) * + (freq2 + f4_2)), 2)); + break; + + case 2: // B计权 + w = 0.17 + 10.0 * log10( + pow(f4_2 * pow(freqSeq[i], 4) / + ((freq2 + f[0] * f[0]) * + sqrt(freq2 + 158.5 * 158.5) * + (freq2 + f4_2)), 2)); + break; + + case 3: // C计权 + w = 0.062 + 10.0 * log10( + pow(f4_2 * pow(freqSeq[i], 4) / + ((freq2 + f[0] * f[0]) * + (freq2 + f4_2)), 2)); + break; + } + + // 应用权重 + FFTPwr[i] *= pow(10.0, w / 10.0); + } + + return 0; +} + +// 使用示例 +void example_usage() { + const int LENGTH = 5; + double FFTPwr[] = {1.0, 2.0, 3.0, 4.0, 5.0}; + double freqSeq[] = {0.0, 100.0, 200.0, 300.0, 400.0}; + uint32_t weightingType = 1; // A计权 + + if(bdsp_FFTWeighting(FFTPwr, freqSeq, LENGTH, weightingType) == 0) { + // 处理结果 + for(int i = 0; i < LENGTH; i++) { + printf("Freq %.1f Hz: %.6f\n", freqSeq[i], FFTPwr[i]); + } + } +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FindPeaks.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FindPeaks.c" new file mode 100644 index 0000000000000000000000000000000000000000..196005a406d2dfb5c05a15fb00433a34fbfb9f78 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FindPeaks.c" @@ -0,0 +1,116 @@ +#include +#include +#include + +struct FreqAmpPairs { + double* freq; // 频率数组 + double* amp; // 幅值数组 + int length; // 数组长度 +}; + +/** + * FFT幅值谱寻峰函数 + * + * @param FFTAmp 输入FFT幅值谱数组 + * @param freqSeq 频率序列数组 + * @param seqLength 序列长度 + * @param minPeakHeight 最小峰值高度阈值 + * @param minIntervalFreq 相邻峰值最小频率间隔 + * @param FreqAmpPair 输出的频率-幅值对结构体 + * + * @return 0: 成功 + * -1: 内存分配失败或无效参数 + */ +int bdsp_FindPeaks(const double *FFTAmp, const double *freqSeq, int seqLength, + double minPeakHeight, double minIntervalFreq, + struct FreqAmpPairs* FreqAmpPair) { + + if(FFTAmp == NULL || freqSeq == NULL || FreqAmpPair == NULL || + seqLength <= 0 || minIntervalFreq < 0) { + return -1; + } + + // 临时存储所有可能的峰值 + double* tempFreq = (double*)malloc(seqLength * sizeof(double)); + double* tempAmp = (double*)malloc(seqLength * sizeof(double)); + if(tempFreq == NULL || tempAmp == NULL) { + free(tempFreq); + free(tempAmp); + return -1; + } + + int peakCount = 0; + + // 寻找所有可能的峰值 + for(int i = 1; i < seqLength-1; i++) { + // 检查是否超过最小峰值高度 + if(FFTAmp[i] < minPeakHeight) { + continue; + } + + // 检查是否是局部最大值 + if(FFTAmp[i] > FFTAmp[i-1] && FFTAmp[i] > FFTAmp[i+1]) { + // 检查最小频率间隔 + int isValidPeak = 1; + for(int j = 0; j < peakCount; j++) { + if(fabs(freqSeq[i] - tempFreq[j]) < minIntervalFreq) { + // 如果在最小间隔内发现更高的峰值,替换它 + if(FFTAmp[i] > tempAmp[j]) { + tempFreq[j] = freqSeq[i]; + tempAmp[j] = FFTAmp[i]; + } + isValidPeak = 0; + break; + } + } + + if(isValidPeak) { + tempFreq[peakCount] = freqSeq[i]; + tempAmp[peakCount] = FFTAmp[i]; + peakCount++; + } + } + } + + // 分配输出结构体内存 + FreqAmpPair->freq = (double*)malloc(peakCount * sizeof(double)); + FreqAmpPair->amp = (double*)malloc(peakCount * sizeof(double)); + if(FreqAmpPair->freq == NULL || FreqAmpPair->amp == NULL) { + free(tempFreq); + free(tempAmp); + return -1; + } + + // 按频率排序并复制到输出结构体 + FreqAmpPair->length = peakCount; + memcpy(FreqAmpPair->freq, tempFreq, peakCount * sizeof(double)); + memcpy(FreqAmpPair->amp, tempAmp, peakCount * sizeof(double)); + + free(tempFreq); + free(tempAmp); + return 0; +} + +// // 使用示例 +// void example_usage() { +// double FFTAmp[] = {1.0, 2.0, 3.0, 2.0, 1.0, 4.0, 2.0}; +// double freqSeq[] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0}; +// int seqLength = 7; +// double minPeakHeight = 1.5; +// double minIntervalFreq = 2.0; + +// struct FreqAmpPairs result; + +// if(bdsp_FindPeaks(FFTAmp, freqSeq, seqLength, minPeakHeight, +// minIntervalFreq, &result) == 0) { +// // 处理结果 +// for(int i = 0; i < result.length; i++) { +// printf("Peak %d: Freq = %.2f, Amp = %.2f\n", +// i+1, result.freq[i], result.amp[i]); +// } + +// // 释放内存 +// free(result.freq); +// free(result.amp); +// } +// } \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FreqSeq.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FreqSeq.c" new file mode 100644 index 0000000000000000000000000000000000000000..7e47f21a5e8f4507a5ab9bcd6313ff9bf7786680 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_FreqSeq.c" @@ -0,0 +1,66 @@ +#include +#include + +/** + * @brief 生成频率数组。根据输入的样本长度和采样率,生成从0开始到不超过采样率一半的频率序列,并按规则截取前部分数据 + * + * @param sampleLength 样本长度,决定频率分辨率及数组长度 + * @param sampleRate 采样率,决定最大频率范围 + * @param out_length 输出参数,返回生成的频率数组的实际长度 + * @return double* 生成的频率数组指针,需要调用者负责内存释放 + */ +double* bdsp_FreqSeq(int sampleLength, int sampleRate, int* out_length) { + // 计算频率步长(频率分辨率) + double step = (double)sampleRate / (double)sampleLength; + + // 计算最大频率值(Nyquist频率),向下取整确保不超采样率一半 + double max_freq = floor((double)sampleRate / 2.0); + + // 计算原始数组元素个数:从0开始每次增加step,直到不超过max_freq的总点数 + int n_elements = (int)(max_freq / step) + 1; + + // 生成原始频率数组 + double* freqSeq_original = (double*)malloc(n_elements * sizeof(double)); + for (int i = 0; i < n_elements; ++i) { + freqSeq_original[i] = i * step; + } + + // 计算需要保留的元素个数(原MATLAB的ceil(sampleLength/2)操作) + int num_elements_to_keep = (int)ceil((double)sampleLength / 2.0); + + // 确定实际保留长度,防止数组越界 + int size_kept = (num_elements_to_keep < n_elements) ? num_elements_to_keep : n_elements; + + // 创建最终结果数组 + double* freqSeq = (double*)malloc(size_kept * sizeof(double)); + for (int i = 0; i < size_kept; ++i) { + freqSeq[i] = freqSeq_original[i]; + } + + // 清理临时数组内存 + free(freqSeq_original); + + // 通过输出参数返回数组长度 + *out_length = size_kept; + + return freqSeq; +} + +/* +示例用法: +int main() { + int sampleLength = 100; + int sampleRate = 1000; + int arr_length; + + double* freqArray = bdsp_FreqSeq(sampleLength, sampleRate, &arr_length); + + // 使用数组... (示例打印前10个元素) + for (int i = 0; i < (arr_length < 10 ? arr_length : 10); ++i) { + printf("%f\n", freqArray[i]); + } + + free(freqArray); // 最后记得释放内存 + return 0; +} +*/ \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter.exe" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter.exe" new file mode 100644 index 0000000000000000000000000000000000000000..6433b1dc759061f4cfd567a2baa32ff6bf987827 Binary files /dev/null and "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter.exe" differ diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter_NotRight.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter_NotRight.c" new file mode 100644 index 0000000000000000000000000000000000000000..24fa4515049c8cce50d74f0d9732a182173bbc6c --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_TimeFilter_NotRight.c" @@ -0,0 +1,659 @@ +#include +#include +#include +#include + +#define PI 3.14159265358979323846 + +double *binomial_mult(int n, double *p) +{ + int i, j; + double *a; + + a = (double *)calloc(2 * n, sizeof(double)); + if (a == NULL) + return (NULL); + + for (i = 0; i < n; ++i) + { + for (j = i; j > 0; --j) + { + a[2 * j] += p[2 * i] * a[2 * (j - 1)] - p[2 * i + 1] * a[2 * (j - 1) + 1]; + a[2 * j + 1] += p[2 * i] * a[2 * (j - 1) + 1] + p[2 * i + 1] * a[2 * (j - 1)]; + } + a[0] += p[2 * i]; + a[1] += p[2 * i + 1]; + } + return (a); +} + +double *trinomial_mult(int n, double *b, double *c) +{ + int i, j; + double *a; + + a = (double *)calloc(4 * n, sizeof(double)); + if (a == NULL) + return (NULL); + + a[2] = c[0]; + a[3] = c[1]; + a[0] = b[0]; + a[1] = b[1]; + + for (i = 1; i < n; ++i) + { + a[2 * (2 * i + 1)] += c[2 * i] * a[2 * (2 * i - 1)] - c[2 * i + 1] * a[2 * (2 * i - 1) + 1]; + a[2 * (2 * i + 1) + 1] += c[2 * i] * a[2 * (2 * i - 1) + 1] + c[2 * i + 1] * a[2 * (2 * i - 1)]; + + for (j = 2 * i; j > 1; --j) + { + a[2 * j] += b[2 * i] * a[2 * (j - 1)] - b[2 * i + 1] * a[2 * (j - 1) + 1] + + c[2 * i] * a[2 * (j - 2)] - c[2 * i + 1] * a[2 * (j - 2) + 1]; + a[2 * j + 1] += b[2 * i] * a[2 * (j - 1) + 1] + b[2 * i + 1] * a[2 * (j - 1)] + + c[2 * i] * a[2 * (j - 2) + 1] + c[2 * i + 1] * a[2 * (j - 2)]; + } + + a[2] += b[2 * i] * a[0] - b[2 * i + 1] * a[1] + c[2 * i]; + a[3] += b[2 * i] * a[1] + b[2 * i + 1] * a[0] + c[2 * i + 1]; + a[0] += b[2 * i]; + a[1] += b[2 * i + 1]; + } + + return (a); +} + +double *ccof_bwlp(int n) +{ + double *ccof; + int m; + int i; + + ccof = (double *)calloc(n + 1, sizeof(double)); + if (ccof == NULL) + return (NULL); + + ccof[0] = 1; + ccof[1] = n; + m = n / 2; + for (i = 2; i <= m; ++i) + { + ccof[i] = (n - i + 1) * ccof[i - 1] / i; + ccof[n - i] = ccof[i]; + } + ccof[n - 1] = n; + ccof[n] = 1; + + return (ccof); +} + +/********************************************************************** + ccof_bwhp - calculates the c coefficients for a butterworth highpass + filter. The coefficients are returned as an array of integers. + +*/ + +double *ccof_bwhp(int n) +{ + double *ccof; + int i; + + ccof = ccof_bwlp(n); + if (ccof == NULL) + return (NULL); + + for (i = 0; i <= n; ++i) + if (i % 2) + ccof[i] = -ccof[i]; + + return (ccof); +} + + +/********************************************************************** + dcof_bwbp - calculates the d coefficients for a butterworth bandpass + filter. The coefficients are returned as an array of doubles. + +*/ + +double *dcof_bwbp(int n, double f1f, double f2f) +{ + int k; // loop variables + double theta; // PI * (f2f - f1f) / 2.0 + double cp; // cosine of phi + double st; // sine of theta + double ct; // cosine of theta + double s2t; // sine of 2*theta + double c2t; // cosine 0f 2*theta + double *rcof; // z^-2 coefficients + double *tcof; // z^-1 coefficients + double *dcof; // dk coefficients + double parg; // pole angle + double sparg; // sine of pole angle + double cparg; // cosine of pole angle + double a; // workspace variables + + cp = cos(PI * (f2f + f1f) / 2.0); + theta = PI * (f2f - f1f) / 2.0; + st = sin(theta); + ct = cos(theta); + s2t = 2.0 * st * ct; // sine of 2*theta + c2t = 2.0 * ct * ct - 1.0; // cosine of 2*theta + + rcof = (double *)calloc(2 * n, sizeof(double)); + tcof = (double *)calloc(2 * n, sizeof(double)); + + for (k = 0; k < n; ++k) + { + parg = PI * (double)(2 * k + 1) / (double)(2 * n); + sparg = sin(parg); + cparg = cos(parg); + a = 1.0 + s2t * sparg; + rcof[2 * k] = c2t / a; + rcof[2 * k + 1] = s2t * cparg / a; + tcof[2 * k] = -2.0 * cp * (ct + st * sparg) / a; + tcof[2 * k + 1] = -2.0 * cp * st * cparg / a; + } + + dcof = trinomial_mult(n, tcof, rcof); + free(tcof); + free(rcof); + + dcof[1] = dcof[0]; + dcof[0] = 1.0; + // dcof[1] = dcof[0]; + for (k = 3; k <= 2 * n; ++k) + dcof[k] = dcof[2 * k - 2]; + return (dcof); +} + +/********************************************************************** + ccof_bwbp - calculates the c coefficients for a butterworth bandpass + filter. The coefficients are returned as an array of integers. + +*/ + +double *ccof_bwbp(int n) +{ + double *tcof; + double *ccof; + int i; + + ccof = (double *)calloc(2 * n + 1, sizeof(double)); + if (ccof == NULL) + return (NULL); + + tcof = ccof_bwhp(n); + if (tcof == NULL) + return (NULL); + + for (i = 0; i < n; ++i) + { + ccof[2 * i] = tcof[i]; + ccof[2 * i + 1] = 0.0; + } + ccof[2 * n] = tcof[n]; + + free(tcof); + return (ccof); +} + +/********************************************************************** + sf_bwbp - calculates the scaling factor for a butterworth bandpass filter. + The scaling factor is what the c coefficients must be multiplied by so + that the filter response has a maximum value of 1. + +*/ + +double sf_bwbp(int n, double f1f, double f2f) +{ + int k; // loop variables + double ctt; // cotangent of theta + double sfr, sfi; // real and imaginary parts of the scaling factor + double parg; // pole angle + double sparg; // sine of pole angle + double cparg; // cosine of pole angle + double a, b, c; // workspace variables + + ctt = 1.0 / tan(PI * (f2f - f1f) / 2.0); + sfr = 1.0; + sfi = 0.0; + + for (k = 0; k < n; ++k) + { + parg = PI * (double)(2 * k + 1) / (double)(2 * n); + sparg = ctt + sin(parg); + cparg = cos(parg); + a = (sfr + sfi) * (sparg - cparg); + b = sfr * sparg; + c = -sfi * cparg; + sfr = b - c; + sfi = a - b - c; + } + + return (1.0 / sfr); +} + +// 滤波器类型枚举 +enum FilterType +{ + HIGH_PASS = 1, + LOW_PASS = 2, + BAND_PASS = 3, + BAND_STOP = 4 +}; + +// 计算二阶滤波器系数 +void butter_coeff_2nd_order(double *b, double *a, double omega1, double omega2, int filterType) +{ + switch (filterType) + { + case HIGH_PASS: + { + double omega = omega2; + double c = tan(PI * omega / 2.0); + double c2 = c * c; + + b[0] = 1.0 / (1.0 + sqrt(2.0) * c + c2); + b[1] = -2.0 * b[0]; + b[2] = b[0]; + + a[0] = 1.0; + a[1] = 2.0 * (c2 - 1.0) * b[0]; + a[2] = (1.0 - sqrt(2.0) * c + c2) * b[0]; + break; + } + + case LOW_PASS: + { + double omega = omega1; + double c = tan(PI * omega / 2.0); + double c2 = c * c; + + b[0] = c2 / (1.0 + sqrt(2.0) * c + c2); + b[1] = 2.0 * b[0]; + b[2] = b[0]; + + a[0] = 1.0; + a[1] = 2.0 * (c2 - 1.0) / (1.0 + sqrt(2.0) * c + c2); + a[2] = (1.0 - sqrt(2.0) * c + c2) / (1.0 + sqrt(2.0) * c + c2); + break; + } + + case BAND_PASS: + { + b = ccof_bwbp(2); + a = dcof_bwbp(2, omega1, omega2); + double sf = sf_bwbp(2, omega1, omega2); + for (int i = 0; i < 5; i++) + { + b[i] *= sf; + } + break; + } + + case BAND_STOP: + { + double centerFreq = (omega1 + omega2) / 2.0; + double bandwidth = omega2 - omega1; + double c = tan(PI * bandwidth / 4.0); + double d = 2.0 * cos(PI * centerFreq); + + b[0] = 1.0; + b[1] = -d; + b[2] = 1.0; + + a[0] = 1.0 + c; + a[1] = -d * (1.0 - c); + a[2] = 1.0 - c; + + // 归一化 + b[0] /= a[0]; + b[1] /= a[0]; + b[2] /= a[0]; + a[1] /= a[0]; + a[2] /= a[0]; + a[0] = 1.0; + break; + } + } +} + +// 计算三阶滤波器系数 +void butter_coeff_3rd_order(double *b, double *a, double omega1, double omega2, int filterType) +{ + switch (filterType) + { + case HIGH_PASS: + case LOW_PASS: + { + double omega = (filterType == HIGH_PASS) ? omega2 : omega1; + double c = tan(PI * omega / 2.0); + double c2 = c * c; + double c3 = c2 * c; + + if (filterType == HIGH_PASS) + { + b[0] = 1.0; + b[1] = -3.0; + b[2] = 3.0; + b[3] = -1.0; + } + else + { + b[0] = c3; + b[1] = 3.0 * c3; + b[2] = 3.0 * c3; + b[3] = c3; + } + + double denom = 1.0 + 2.0 * c + 2.0 * c2 + c3; + a[0] = 1.0; + a[1] = (3.0 + 2.0 * c - 2.0 * c2 - 3.0 * c3) / denom; + a[2] = (3.0 - 2.0 * c - 2.0 * c2 + 3.0 * c3) / denom; + a[3] = (1.0 - 2.0 * c + 2.0 * c2 - c3) / denom; + + // 归一化b系数 + b[0] /= denom; + b[1] /= denom; + b[2] /= denom; + b[3] /= denom; + break; + } + + case BAND_PASS: + { + b = ccof_bwbp(3); + a = dcof_bwbp(3, omega1, omega2); + double sf = sf_bwbp(3, omega1, omega2); + for (int i = 0; i < 7; i++) + { + b[i] *= sf; + } + break; + } + case BAND_STOP: + { + // 三阶带通和带阻滤波器通过级联实现 + // 一个二阶段和一个一阶段 + double centerFreq = (omega1 + omega2) / 2.0; + double bandwidth = omega2 - omega1; + + // 二阶段系数 + double c = tan(PI * bandwidth / 4.0); + double d = 2.0 * cos(PI * centerFreq); + + if (filterType == BAND_PASS) + { + b[0] = c; + b[1] = 0.0; + b[2] = -c; + b[3] = 0.0; + } + else + { + b[0] = 1.0; + b[1] = -d; + b[2] = 1.0; + b[3] = 0.0; + } + + a[0] = 1.0 + c; + a[1] = -d * (1.0 - c); + a[2] = 1.0 - c; + a[3] = 0.0; + + // 归一化 + double a0 = a[0]; + for (int i = 0; i <= 3; i++) + { + b[i] /= a0; + a[i] /= a0; + } + break; + } + } +} + +// 计算四阶滤波器系数 +void butter_coeff_4th_order(double *b, double *a, double omega1, double omega2, int filterType) +{ + switch (filterType) + { + case HIGH_PASS: + case LOW_PASS: + { + double omega = (filterType == HIGH_PASS) ? omega2 : omega1; + double c = tan(PI * omega / 2.0); + double c2 = c * c; + double c4 = c2 * c2; + + if (filterType == HIGH_PASS) + { + b[0] = 1.0; + b[1] = -4.0; + b[2] = 6.0; + b[3] = -4.0; + b[4] = 1.0; + } + else + { + b[0] = c4; + b[1] = 4.0 * c4; + b[2] = 6.0 * c4; + b[3] = 4.0 * c4; + b[4] = c4; + } + + double k1 = 2.613125929752753; // 2 + sqrt(2) + double k2 = 3.414213562373095; // 2 + 2*sqrt(2) + + double denom = 1.0 + k1 * c + k2 * c2 + k1 * c2 * c + c4; + a[0] = 1.0; + a[1] = (4.0 + 2.0 * k1 * c - 2.0 * k2 * c2 - 4.0 * k1 * c2 * c - 4.0 * c4) / denom; + a[2] = (6.0 - 2.0 * k2 * c2 + 2.0 * k2 * c2 + 6.0 * c4) / denom; + a[3] = (4.0 - 2.0 * k1 * c - 2.0 * k2 * c2 + 4.0 * k1 * c2 * c - 4.0 * c4) / denom; + a[4] = (1.0 - k1 * c + k2 * c2 - k1 * c2 * c + c4) / denom; + + // 归一化b系数 + for (int i = 0; i <= 4; i++) + { + b[i] /= denom; + } + break; + } + + case BAND_PASS: + { + b = ccof_bwbp(4); + a = dcof_bwbp(4, omega1, omega2); + double sf = sf_bwbp(4, omega1, omega2); + for (int i = 0; i < 9; i++) + { + b[i] *= sf; + } + break; + } + case BAND_STOP: + { + // 四阶带通和带阻滤波器通过两个二阶段级联实现 + double centerFreq = (omega1 + omega2) / 2.0; + double bandwidth = omega2 - omega1; + + double c = tan(PI * bandwidth / 4.0); + double d = 2.0 * cos(PI * centerFreq); + + if (filterType == BAND_PASS) + { + b[0] = c * c; + b[1] = 0.0; + b[2] = -2.0 * c * c; + b[3] = 0.0; + b[4] = c * c; + } + else + { + b[0] = 1.0; + b[1] = -2.0 * d; + b[2] = 2.0 + 2.0 * d * d; + b[3] = -2.0 * d; + b[4] = 1.0; + } + + double q1 = 1.847759065022573; // 2 + sqrt(2) + double q2 = 0.765366864730179; // 2 - sqrt(2) + + a[0] = 1.0; + a[1] = -2.0 * d * (1.0 - c) / (1.0 + q1 * c + c * c); + a[2] = 2.0 * ((1.0 - c * c) / (1.0 + q1 * c + c * c)); + a[3] = -2.0 * d * (1.0 - c) / (1.0 + q2 * c + c * c); + a[4] = ((1.0 - q2 * c + c * c) * (1.0 - q1 * c + c * c)) / + ((1.0 + q2 * c + c * c) * (1.0 + q1 * c + c * c)); + + // 归一化 + double a0 = a[0]; + for (int i = 0; i <= 4; i++) + { + b[i] /= a0; + a[i] /= a0; + } + break; + } + } +} + +// 生成巴特沃斯滤波器系数的主函数 +void butter_coefficients(int order, double *wn, int filterType, + double *b, double *a, int *coeffLength) +{ + *coeffLength = order + 1; + + // 清零系数数组 + memset(b, 0, (*coeffLength) * sizeof(double)); + memset(a, 0, (*coeffLength) * sizeof(double)); + + // 根据阶数调用相应的系数计算函数 + switch (order) + { + case 2: + butter_coeff_2nd_order(b, a, wn[0], wn[1], filterType); + break; + case 3: + butter_coeff_3rd_order(b, a, wn[0], wn[1], filterType); + break; + case 4: + butter_coeff_4th_order(b, a, wn[0], wn[1], filterType); + break; + default: + printf("Error: Only support 2nd, 3rd and 4th order filters.\n"); + break; + } + + for(int i = 0; i < *coeffLength; i++){ + printf("%f ", b[i]); + printf("%f\n", a[i]); + } +} + +// 实现滤波器 +void filter(double *b, double *a, int coeffLength, + double *input, double *output, int dataLength) +{ + int i, j; + + // 分配延迟线内存 + double *x_delay = (double *)calloc(coeffLength, sizeof(double)); // 输入延迟线 + double *y_delay = (double *)calloc(coeffLength, sizeof(double)); // 输出延迟线 + + for (i = 0; i < dataLength; i++) + { + // 移动延迟线 + for (j = coeffLength - 1; j > 0; j--) + { + x_delay[j] = x_delay[j - 1]; + y_delay[j] = y_delay[j - 1]; + } + x_delay[0] = input[i]; + + // 计算输出 + output[i] = b[0] * x_delay[0]; + for (j = 1; j < coeffLength; j++) + { + output[i] += b[j] * x_delay[j] - a[j] * y_delay[j - 1]; + } + + y_delay[0] = output[i]; + } + + // 释放内存 + free(x_delay); + free(y_delay); +} + +// 主滤波函数 +void bdsp_TimeFilter(double *inputData, int dataLength, double sampleRate, + int filterOrder, double filterLowerFreq, double filterUpperFreq, + int filterType, double *outputData) +{ + + // 计算归一化频率 + double wn[2]; + wn[0] = filterLowerFreq / (sampleRate / 2); + wn[1] = filterUpperFreq / (sampleRate / 2); + + // 分配滤波器系数数组 + int coeffLength; + double *b = (double *)calloc(2*filterOrder + 1, sizeof(double)); + double *a = (double *)calloc(2*filterOrder + 1, sizeof(double)); + + // 生成滤波器系数 + butter_coefficients(filterOrder, wn, filterType, b, a, &coeffLength); + + // 应用滤波器 + filter(b, a, coeffLength, inputData, outputData, dataLength); + + // 释放内存 + free(b); + free(a); +} + +// 测试代码 +int main() +{ + int dataLength = 1000; + double sampleRate = 1000; + // 可以选择2、3、4阶 + int filterOrder = 4; + double filterLowerFreq = 10; + double filterUpperFreq = 100; + int filterType = BAND_PASS; + + double *inputData = (double *)malloc(dataLength * sizeof(double)); + double *outputData = (double *)malloc(dataLength * sizeof(double)); + + // 生成测试信号(包含多个频率成分) + for (int i = 0; i < dataLength; i++) + { + inputData[i] = sin(2 * PI * 5 * i / sampleRate) + // 5 Hz + sin(2 * PI * 50 * i / sampleRate) + // 50 Hz + sin(2 * PI * 200 * i / sampleRate); // 200 Hz + } + + // 应用滤波器 + bdsp_TimeFilter(inputData, dataLength, sampleRate, + filterOrder, filterLowerFreq, filterUpperFreq, + filterType, outputData); + + // 输出部分结果用于验证 + printf("First 10 samples of input and filtered output:\n"); + for (int i = 0; i < 10; i++) + { + printf("Input[%d]: %f, Output[%d]: %f\n", + i, inputData[i], i, outputData[i]); + } + + free(inputData); + free(outputData); + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_Windowed.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_Windowed.c" new file mode 100644 index 0000000000000000000000000000000000000000..227bc40beb472ce2f210a66c322b0533fcdd0396 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_Windowed.c" @@ -0,0 +1,21 @@ +#include + +double* bdsp_Windowed(const double* inputdata, const double* windowWeight, int length) { + // 检查输入是否有效 + if (inputdata == NULL || windowWeight == NULL || length <= 0) { + return NULL; + } + + // 分配内存用于存储结果 + double* Spectrum = (double*)malloc(length * sizeof(double)); + if (Spectrum == NULL) { + return NULL; // 内存分配失败 + } + + // 逐点相乘 + for (int i = 0; i < length; i++) { + Spectrum[i] = inputdata[i] * windowWeight[i]; + } + + return Spectrum; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Cepstrum.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Cepstrum.c" new file mode 100644 index 0000000000000000000000000000000000000000..4a19827ac8f903300d3e0ce56533c14a16c1967f --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Cepstrum.c" @@ -0,0 +1,76 @@ +#include +#include +#include // 需要安装FFTW库 + +/** + * @brief 计算倒谱。对输入的FFT幅度取对数后执行逆傅里叶变换,最后取绝对值 + * + * @param FFTAmp FFT幅度谱数组(实数输入) + * @param fft_size 数组长度(必须为2的幂次以保证FFT效率) + * @return double* 生成的倒谱数组指针,需调用者使用free释放 + * + * @note 需要链接FFTW3库(编译时添加 -lfftw3 -lm) + */ +double* bdsp_calc_Cepstrum(const double* FFTAmp, int fft_size) +{ + /*----------- 计算对数幅度谱 -----------*/ + double* logAmp = (double*)malloc(fft_size * sizeof(double)); + for (int i = 0; i < fft_size; ++i) { + // 施加对数运算(注意:输入应保证>0) + logAmp[i] = log10(FFTAmp[i]); + } + + /*----------- 准备FFTW变换 -----------*/ + fftw_complex *in = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size); + fftw_complex *out = (fftw_complex*)fftw_malloc(sizeof(fftw_complex) * fft_size); + + // 将实数幅度转换为复数格式(虚部置零) + for (int i = 0; i < fft_size; ++i) { + in[i][0] = logAmp[i]; // 实部 + in[i][1] = 0.0; // 虚部 + } + + /*----------- 执行逆FFT变换 -----------*/ + fftw_plan plan = fftw_plan_dft_1d(fft_size, in, out, FFTW_BACKWARD, FFTW_ESTIMATE); + fftw_execute(plan); // 执行变换 + + /*----------- 计算幅度并归一化 -----------*/ + double* cepstrum = (double*)malloc(fft_size * sizeof(double)); + const double scale = 1.0 / fft_size; // 归一化因子(匹配MATLAB的ifft行为) + + for (int i = 0; i < fft_size; ++i) { + // 应用归一化因子 + double real = out[i][0] * scale; + double imag = out[i][1] * scale; + + // 计算复数模值(绝对值) + cepstrum[i] = sqrt(real * real + imag * imag); + } + + /*----------- 资源清理 -----------*/ + fftw_destroy_plan(plan); + fftw_free(in); + fftw_free(out); + free(logAmp); + + return cepstrum; +} + +/* +示例用法: +int main() { + // 生成测试数据(示例为20点正弦波幅度谱) + const int N = 8; + double ffthamp[N] = {0.1, 0.5, 1.0, 0.7, 0.3, 0.7, 1.0, 0.5}; + + double* ceps = bdsp_calc_Cepstrum(ffthamp, N); + + // 打印结果 + for (int i = 0; i < N; ++i) { + printf("Cepstrum[%d] = %f\n", i, ceps[i]); + } + + free(ceps); // 释放内存 + return 0; +} +*/ \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_EigenFreqAmp.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_EigenFreqAmp.c" new file mode 100644 index 0000000000000000000000000000000000000000..06e0e4310d58ce40fe8919dd2fa785e86529aa6e --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_EigenFreqAmp.c" @@ -0,0 +1,87 @@ +#include +#include +#include + +struct FreqAmpPairs { + double* freq; // 频率数组,改用double提高精度 + double* amp; // 对应的幅值数组 + int length; // 数组长度 +}; + +/** + * @brief 计算特征频率对应的幅值 + * @param FFTAmp FFT幅值谱数组 + * @param eigenFreq 特征频率数组 + * @param freqSeq 频率序列数组 + * @param N 特征频率数组长度 + * @param freqLength 频率序列长度 + * @param bandWidth 带宽,在特征频率上下bandWidth/2范围内寻找最大幅值 + * @param FreqAmpPair 特征频率-幅值对结构体 + * @return 0:成功, -1:内存分配失败 + */ +int bdsp_calc_EigenFreqAmp(double* FFTAmp, double* eigenFreq, double* freqSeq, + int N, int freqLength, double bandWidth, + struct FreqAmpPairs* FreqAmpPair) { + + // 为输出结构体分配内存 + FreqAmpPair->freq = (double*)malloc(N * sizeof(double)); + FreqAmpPair->amp = (double*)malloc(N * sizeof(double)); + if(FreqAmpPair->freq == NULL || FreqAmpPair->amp == NULL) { + return -1; + } + FreqAmpPair->length = N; + + // 拷贝特征频率数组到输出结构体 + memcpy(FreqAmpPair->freq, eigenFreq, N * sizeof(double)); + + // 对每个特征频率寻找对应的最大幅值 + for(int i = 0; i < N; i++) { + // 如果特征频率超出最大频率,置幅值为0 + if(eigenFreq[i] > freqSeq[freqLength-1]) { + FreqAmpPair->amp[i] = 0; + continue; + } + + // 计算查找范围的上下限 + double lowerBound = eigenFreq[i] - bandWidth / 2; + double upperBound = eigenFreq[i] + bandWidth / 2; + + // 在频带范围内查找最大幅值 + double maxAmp = 0; + int found = 0; + + for(int j = 0; j < freqLength; j++) { + if(freqSeq[j] >= lowerBound && freqSeq[j] <= upperBound) { + if(!found || FFTAmp[j] > maxAmp) { + maxAmp = FFTAmp[j]; + found = 1; + } + } + } + + // 如果在带宽范围内找到了频率点,则记录最大幅值 + // 否则记录为0 + FreqAmpPair->amp[i] = found ? maxAmp : 0; + } + + return 0; +} + +// // 使用示例 +// void example_usage() { +// double FFTAmp[] = {1.0, 2.0, 1.5, 3.0, 2.5}; +// double eigenFreq[] = {1.0, 2.0}; +// double freqSeq[] = {0.0, 1.0, 2.0, 3.0, 4.0}; +// int N = 2; +// int freqLength = 5; +// double bandWidth = 1.0; + +// struct FreqAmpPairs result; + +// if(bdsp_calc_EigenFreqAmp(FFTAmp, eigenFreq, freqSeq, N, freqLength, +// bandWidth, &result) == 0) { +// // 使用完后释放内存 +// free(result.freq); +// free(result.amp); +// } +// } \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue.c" new file mode 100644 index 0000000000000000000000000000000000000000..8550bd86be782cf182e5c0900e7f1051908fc1a5 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue.c" @@ -0,0 +1,125 @@ +// 各频域特征值命名 +struct bdsp_FreqEigenValue { + double Ampavg; // 幅值均值 + double fc; // 重心频率 + double Msf; // 均方频率 + double Ampvar; // 幅值方差 + double Ampstd; // 幅值标准差 + double Ampskewness; // 幅值偏度 + double Ampkurtosis; // 幅值峭度 + double rmsf; // 均方根频率 + double vf; // 频率方差 + double rvf; // 频率标准差 + double sigma; // 频率分布系数 + double fskewness; // 频率偏度 + double fkurtosis; // 频率峭度 + double sqrtf; // 平方根比率 +}; + +int bdsp_calc_FreqEigenValue(double *FFTAmp, double *FFTPwr, double *freqSeq, int N, struct bdsp_FreqEigenValue *TimeEigen) { + if (!FFTAmp || !FFTPwr || !freqSeq || !TimeEigen || N <= 0) { + return -1; // 错误检查 + } + + // 计算FFTPwr归一化的和 + double sum_FFTPwr = 0.0; + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + // 01 幅值均值 + TimeEigen->Ampavg = 0.0; + for (int i = 0; i < N; i++) { + TimeEigen->Ampavg += FFTAmp[i]; + } + TimeEigen->Ampavg /= N; + + // 02 重心频率 + TimeEigen->fc = 0.0; + for (int i = 0; i < N; i++) { + TimeEigen->fc += freqSeq[i] * FFTPwr[i]; + } + TimeEigen->fc /= sum_FFTPwr; + + // 03 均方频率 + TimeEigen->Msf = 0.0; + for (int i = 0; i < N; i++) { + TimeEigen->Msf += freqSeq[i] * freqSeq[i] * FFTPwr[i]; + } + TimeEigen->Msf /= sum_FFTPwr; + + // 04 幅值方差 + TimeEigen->Ampvar = 0.0; + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampvar += diff * diff; + } + TimeEigen->Ampvar /= N; + + // 05 幅值标准差 + TimeEigen->Ampstd = sqrt(TimeEigen->Ampvar); + + // 06 幅值偏度 + TimeEigen->Ampskewness = 0.0; + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampskewness += diff * diff * diff; + } + TimeEigen->Ampskewness /= (N * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd); + + // 07 幅值峭度 + TimeEigen->Ampkurtosis = 0.0; + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampkurtosis += diff * diff * diff * diff; + } + TimeEigen->Ampkurtosis /= (N * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd); + + // 08 均方根频率 + TimeEigen->rmsf = sqrt(TimeEigen->Msf); + + // 09 频率方差 + TimeEigen->vf = 0.0; + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - TimeEigen->fc; + TimeEigen->vf += diff * diff * FFTPwr[i]; + } + TimeEigen->vf /= sum_FFTPwr; + + // 10 频率标准差 + TimeEigen->rvf = sqrt(TimeEigen->vf); + + // 11 频率分布系数 + TimeEigen->sigma = 0.0; + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - TimeEigen->fc; + TimeEigen->sigma += diff * diff * FFTPwr[i]; + } + TimeEigen->sigma /= N; + + // 12 频率偏度 + TimeEigen->fskewness = 0.0; + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - TimeEigen->fc; + TimeEigen->fskewness += diff * diff * diff * FFTPwr[i]; + } + TimeEigen->fskewness /= (N * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma); + + // 13 频率峭度 + TimeEigen->fkurtosis = 0.0; + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - TimeEigen->fc; + TimeEigen->fkurtosis += diff * diff * diff * diff * FFTPwr[i]; + } + TimeEigen->fkurtosis /= (N * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma); + + // 14 平方根比率 + TimeEigen->sqrtf = 0.0; + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - TimeEigen->fc; + TimeEigen->sqrtf += sqrt(fabs(diff)) * FFTPwr[i]; + } + TimeEigen->sqrtf /= (sqrt(TimeEigen->sigma) * N); + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampavg.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampavg.c" new file mode 100644 index 0000000000000000000000000000000000000000..4ee7c608974181a07befca603fd3d8294a7df405 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampavg.c" @@ -0,0 +1,14 @@ +#include + +// 计算频域特征值-幅值均值 +double bdsp_calc_Ampavg(double *FFTAmp, int N) +{ + if (!FFTAmp || N <= 0) return 0.0; + + double sum = 0.0; + for (int i = 0; i < N; i++) + { + sum += FFTAmp[i]; + } + return sum / N; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampkurtosis.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampkurtosis.c" new file mode 100644 index 0000000000000000000000000000000000000000..00895e00ff37c186981ecb92f4233daf5276dece --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampkurtosis.c" @@ -0,0 +1,30 @@ +#include +#include + +// 幅值峭度 +double bdsp_calc_Ampkurtosis(double *FFTAmp, int N) +{ + if (!FFTAmp || N <= 0) return 0.0; + + double mean = 0.0; + double var = 0.0; + double kurtosis = 0.0; + + for (int i = 0; i < N; i++) { + mean += FFTAmp[i]; + } + mean /= N; + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + var += diff * diff; + } + var /= N; + double std = sqrt(var); + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + kurtosis += diff * diff * diff * diff; + } + return kurtosis / (N * std * std * std * std); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampskewness.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampskewness.c" new file mode 100644 index 0000000000000000000000000000000000000000..f37d5e9318eb55a51a1b8259ed6a4751fcc62252 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampskewness.c" @@ -0,0 +1,30 @@ +#include +#include + +//幅值偏度 +double bdsp_calc_Ampskewness(double *FFTAmp, int N) +{ + if (!FFTAmp || N <= 0) return 0.0; + + double mean = 0.0; + double var = 0.0; + double skewness = 0.0; + + for (int i = 0; i < N; i++) { + mean += FFTAmp[i]; + } + mean /= N; + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + var += diff * diff; + } + var /= N; + double std = sqrt(var); + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + skewness += diff * diff * diff; + } + return skewness / (N * std * std * std); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampstd.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampstd.c" new file mode 100644 index 0000000000000000000000000000000000000000..c2cd06e5ec22f4de3e9b0aab36afe0e3d17aab17 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampstd.c" @@ -0,0 +1,22 @@ +#include +#include + +// 幅值标准差 +double bdsp_calc_Ampstd(double *FFTAmp, int N) +{ + if (!FFTAmp || N <= 0) return 0.0; + + double mean = 0.0; + double var = 0.0; + + for (int i = 0; i < N; i++) { + mean += FFTAmp[i]; + } + mean /= N; + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + var += diff * diff; + } + return sqrt(var / N); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampvar.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampvar.c" new file mode 100644 index 0000000000000000000000000000000000000000..fbdda8e3cf7a9967f3ff0a7630c92623c07ee9dd --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Ampvar.c" @@ -0,0 +1,21 @@ +#include + +// 幅值方差 +double bdsp_calc_Ampvar(double *FFTAmp, int N) +{ + if (!FFTAmp || N <= 0) return 0.0; + + double mean = 0.0; + double var = 0.0; + + for (int i = 0; i < N; i++) { + mean += FFTAmp[i]; + } + mean /= N; + + for (int i = 0; i < N; i++) { + double diff = FFTAmp[i] - mean; + var += diff * diff; + } + return var / N; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Msf.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Msf.c" new file mode 100644 index 0000000000000000000000000000000000000000..fc4367c10fe4ca5b1c5f790893eb144ac49b87f6 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_Msf.c" @@ -0,0 +1,19 @@ +#include + +// 计算频域特征值-均方频率 +double bdsp_calc_Msf(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double Msf = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + Msf += freqSeq[i] * freqSeq[i] * FFTPwr[i]; + } + return Msf / sum_FFTPwr; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fc.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fc.c" new file mode 100644 index 0000000000000000000000000000000000000000..dbf372e7a13e1937db5e391ed86847f8c1d3b885 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fc.c" @@ -0,0 +1,19 @@ +#include + +// 计算频域特征值-重心频率 +double bdsp_calc_fc(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + return fc / sum_FFTPwr; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fkurtosis.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fkurtosis.c" new file mode 100644 index 0000000000000000000000000000000000000000..7a0347e79a3ed756b26a0b1c87820c99e19ac4b7 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fkurtosis.c" @@ -0,0 +1,34 @@ +#include +#include + +// 频率峭度 +double bdsp_calc_fkurtosis(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double sigma = 0.0; + double kurtosis = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + sigma += diff * diff * FFTPwr[i]; + } + sigma /= N; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + kurtosis += diff * diff * diff * diff * FFTPwr[i]; + } + return kurtosis / (N * sigma * sigma * sigma * sigma); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fskewness.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fskewness.c" new file mode 100644 index 0000000000000000000000000000000000000000..ec172f226dd9c6d6d7b66cc34cf4ac8e72e688d1 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_fskewness.c" @@ -0,0 +1,34 @@ +#include +#include + +// 频率偏度 +double bdsp_calc_fskewness(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double sigma = 0.0; + double skewness = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + sigma += diff * diff * FFTPwr[i]; + } + sigma /= N; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + skewness += diff * diff * diff * FFTPwr[i]; + } + return skewness / (N * sigma * sigma * sigma); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rmsf.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rmsf.c" new file mode 100644 index 0000000000000000000000000000000000000000..e9d209687bfb45ce30f1e4c7dbab8919fae39201 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rmsf.c" @@ -0,0 +1,20 @@ +#include +#include + +// 均方根频率 +double bdsp_calc_rmsf(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double Msf = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + Msf += freqSeq[i] * freqSeq[i] * FFTPwr[i]; + } + return sqrt(Msf / sum_FFTPwr); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rvf.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rvf.c" new file mode 100644 index 0000000000000000000000000000000000000000..40fb8769619bc01eceb16d9615dfcc8d694d1a94 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_rvf.c" @@ -0,0 +1,27 @@ +#include +#include + +// 频率标准差 +double bdsp_calc_rvf(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double vf = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + vf += diff * diff * FFTPwr[i]; + } + return sqrt(vf / sum_FFTPwr); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sigma.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sigma.c" new file mode 100644 index 0000000000000000000000000000000000000000..c3e5160e295b20863f669fc10f5985746e828cd7 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sigma.c" @@ -0,0 +1,26 @@ +#include + +// 频率分布系数 +double bdsp_calc_sigma(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double sigma = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + sigma += diff * diff * FFTPwr[i]; + } + return sigma / N; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sqrtf.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sqrtf.c" new file mode 100644 index 0000000000000000000000000000000000000000..0dfd3435fba21f6a8beb718e6a83fc9edea52562 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_sqrtf.c" @@ -0,0 +1,34 @@ +#include +#include + +// 平方根比率 +double bdsp_calc_sqrtf(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double sigma = 0.0; + double sqrtf = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + sigma += diff * diff * FFTPwr[i]; + } + sigma /= N; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + sqrtf += sqrt(fabs(diff)) * FFTPwr[i]; + } + return sqrtf / (sqrt(sigma) * N); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_vf.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_vf.c" new file mode 100644 index 0000000000000000000000000000000000000000..921d3251a3d2f1f9a008f2815c53251a63db31e9 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqEigenValue/bdsp_calc_vf.c" @@ -0,0 +1,26 @@ +#include + +// 频率方差 +double bdsp_calc_vf(double *FFTPwr, double *freqSeq, int N) +{ + if (!FFTPwr || !freqSeq || N <= 0) return 0.0; + + double sum_FFTPwr = 0.0; + double fc = 0.0; + double vf = 0.0; + + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + for (int i = 0; i < N; i++) { + fc += freqSeq[i] * FFTPwr[i]; + } + fc /= sum_FFTPwr; + + for (int i = 0; i < N; i++) { + double diff = freqSeq[i] - fc; + vf += diff * diff * FFTPwr[i]; + } + return vf / sum_FFTPwr; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqIntegration.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqIntegration.c" new file mode 100644 index 0000000000000000000000000000000000000000..ab47506c678abd73867e3fba481a87f5616709a4 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_FreqIntegration.c" @@ -0,0 +1,46 @@ +#include +#include + +#define M_PI 3.14159265358979323846 + +/** + * FFT频域积分 - 将加速度谱转换为速度谱 + * @param FFTPwr 输入的功率谱数组指针 + * @param freqSeq 频率序列数组指针 + * @param length 数组长度 + * @param integratedData 输出的速度谱数组指针 + * @return 0:成功, -1:参数错误 + */ +int bdsp_calc_FreqIntegration(const double *FFTPwr, const double *freqSeq, + int length, double *integratedData) { + // 参数检查 + if (FFTPwr == NULL || freqSeq == NULL || + integratedData == NULL || length <= 1) { + return -1; + } + + // 设置第一个点为0 + integratedData[0] = 0.0; + + // 从第二个点开始进行积分计算 + for (int i = 1; i < length; i++) { + integratedData[i] = FFTPwr[i] / (2.0 * M_PI * freqSeq[i]); + } + + return 0; +} + +// // 使用示例 +// void example_usage() { +// const int LENGTH = 5; +// double FFTPwr[] = {1.0, 2.0, 3.0, 4.0, 5.0}; +// double freqSeq[] = {0.0, 1.0, 2.0, 3.0, 4.0}; +// double integratedData[LENGTH]; + +// if(bdsp_calc_FreqIntegration(FFTPwr, freqSeq, LENGTH, integratedData) == 0) { +// // 处理结果 +// for(int i = 0; i < LENGTH; i++) { +// printf("Freq %.1f Hz: %.6f\n", freqSeq[i], integratedData[i]); +// } +// } +// } \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Spectrum.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Spectrum.c" new file mode 100644 index 0000000000000000000000000000000000000000..4ef25c56e1b14703d72a90a67732ef32c812a261 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_Spectrum.c" @@ -0,0 +1,197 @@ +#include +#include +#include +#include + +#define M_PI 3.14159265358979323846 + +/* +* FFT相关结构体定义 +*/ +typedef struct { + double real; + double imag; +} Complex; + +/* +* 函数名: bdsp_calc_Spectrum +* 功能: 对已加窗的输入数据进行FFT变换并输出频谱 +* 参数: +* input: 输入数据数组(已加窗) +* N: 数据长度(必须是2的整数次幂) +* spectrum: 输出频谱数组(长度为N/2) +* 返回值: +* 0 - 成功 +* -1 - 失败 +*/ +int bdsp_calc_Spectrum(const double *input, int N, float *spectrum) +{ + // 参数检查 + if(input == NULL || spectrum == NULL || N <= 0) + return -1; + + // 检查N是否为2的整数次幂 + int temp = N; + while(temp > 1) { + if(temp % 2 != 0) + return -1; + temp /= 2; + } + + // 分配内存 + Complex *fftData = (Complex *)malloc(N * sizeof(Complex)); + if(fftData == NULL) { + return -1; + } + + // 将数据转换为复数形式 + for(int i = 0; i < N; i++) { + fftData[i].real = input[i]; + fftData[i].imag = 0.0; + } + + // 执行FFT + fft(fftData, N); + + // 计算频谱(幅值谱) + for(int i = 0; i < N/2; i++) { + double magnitude = sqrt(fftData[i].real * fftData[i].real + + fftData[i].imag * fftData[i].imag); + // 将双精度结果转换为单精度输出 + spectrum[i] = (float)(magnitude * 2.0 / N); // 2/N是FFT的幅值校正因子 + } + + // 释放内存 + free(fftData); + return 0; +} + +/* +* 位反转函数 +*/ +void bit_reverse(Complex *data, int N) { + int j = 0; + for(int i = 0; i < N - 1; i++) { + if(i < j) { + Complex temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } + int k = N >> 1; + while(k <= j) { + j -= k; + k >>= 1; + } + j += k; + } +} + +/* +* FFT核心算法实现 +*/ +void fft(Complex *data, int N) { + bit_reverse(data, N); + + // 蝶形运算 + for(int step = 1; step < N; step <<= 1) { + double theta = M_PI / step; + Complex wp = {cos(theta), -sin(theta)}; + + for(int group = 0; group < N; group += (step << 1)) { + Complex w = {1.0, 0.0}; + + for(int k = 0; k < step; k++) { + Complex t = { + w.real * data[group + k + step].real - w.imag * data[group + k + step].imag, + w.real * data[group + k + step].imag + w.imag * data[group + k + step].real + }; + + data[group + k + step].real = data[group + k].real - t.real; + data[group + k + step].imag = data[group + k].imag - t.imag; + data[group + k].real += t.real; + data[group + k].imag += t.imag; + + // 更新旋转因子 + double temp = w.real; + w.real = w.real * wp.real - w.imag * wp.imag; + w.imag = temp * wp.imag + w.imag * wp.real; + } + } + } +} + +// 使用示例 + +/* +* 窗函数参数结构体 +* winAmpCompesationPara: 幅值补偿系数 +* winEnergyCompesationPara: 能量补偿系数 +* 说明: +* 1. 幅值补偿系数用于补偿窗函数对信号幅值的衰减 +* 2. 能量补偿系数用于补偿窗函数对信号能量的衰减 +*/ +struct windowParameter { + double winAmpCompesationPara; // 幅值补偿系数 + double winEnergyCompesationPara; // 能量补偿系数 +}; + +// 声明外部窗函数 +int bdsp_Windowed(double *tempBuffer, int type, struct windowParameter *windowPara, int dataLength); + +int main() { + const int N = 1024; // 必须是2的整数次幂 + double *input = (double *)malloc(N * sizeof(double)); + double *windowedData = (double *)malloc(N * sizeof(double)); + float *spectrum = (float *)malloc((N / 2) * sizeof(float)); + + if (input == NULL || windowedData == NULL || spectrum == NULL) { + printf("内存分配失败\n"); + free(input); + free(windowedData); + free(spectrum); + return -1; + } + + // 生成测试信号 + double f1 = 10.0; // 10Hz + double f2 = 50.0; // 50Hz + double fs = 1000.0; // 采样频率1000Hz + for(int i = 0; i < N; i++) { + double t = (double)i / fs; + input[i] = sin(2 * M_PI * f1 * t) + 0.5 * sin(2 * M_PI * f2 * t); + } + + // 复制数据用于加窗 + memcpy(windowedData, input, N * sizeof(double)); + + // 对数据进行加窗处理 + struct windowParameter winPara; + if(bdsp_Windowed(windowedData, 1, &winPara, N) != 0) { // 使用汉宁窗(type=1) + printf("加窗处理失败\n"); + free(input); + free(windowedData); + free(spectrum); + return -1; + } + + // 执行FFT + if(bdsp_calc_Spectrum(windowedData, N, spectrum) == 0) { + // 输出频谱结果 + printf("频谱结果(前10个点):\n"); + for(int i = 0; i < 10; i++) { + double freq = (double)i * fs / N; + // 应用窗函数的幅值补偿 + printf("频率:%.1f Hz, 幅值:%.6f\n", + freq, spectrum[i] * winPara.winAmpCompesationPara); + } + } else { + printf("FFT计算失败\n"); + } + + // 释放内存 + free(input); + free(windowedData); + free(spectrum); + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAve.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAve.c" new file mode 100644 index 0000000000000000000000000000000000000000..3ae1d57ac38161e134d2293cf3e1f909f97e1f46 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAve.c" @@ -0,0 +1,15 @@ +#include +#include + +// 计算时域特征值-均值绝对值 +double bdsp_calc_AbsAve(float *inputdata, int length) +{ + double sum = 0.0; + + for (int i = 0; i < length; i++) + { + sum += inputdata[i]; + } + + return fabs(sum / length); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAveAmp.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAveAmp.c" new file mode 100644 index 0000000000000000000000000000000000000000..663138ccbafe3959a71f3d719e177b517ebb53b8 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_AbsAveAmp.c" @@ -0,0 +1,15 @@ +#include +#include + +// 计算时域特征值-绝对平均幅值 +double bdsp_calc_AbsAveAmp(float *inputdata, int length) +{ + double sum = 0.0; + + for (int i = 0; i < length; i++) + { + sum += fabs(inputdata[i]); + } + + return sum / length; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Ave.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Ave.c" new file mode 100644 index 0000000000000000000000000000000000000000..cc784e8b2fb92c1a32f15a6fb401794dc140718d --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Ave.c" @@ -0,0 +1,15 @@ +#include +#include + +// 计算时域特征值-平均值 +double bdsp_calc_Ave(float *inputdata, int length) +{ + double sum = 0.0; + + for (int i = 0; i < length; i++) + { + sum += inputdata[i]; + } + + return sum / length; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosis.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosis.c" new file mode 100644 index 0000000000000000000000000000000000000000..61e03035910a27d31eeccc89fbbee7c1b45f93ba --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosis.c" @@ -0,0 +1,27 @@ +#include +#include + +// 计算时域特征值-峭度 +double bdsp_calc_Kurtosis(float *inputdata, int length) +{ + // 计算平均值 + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + // 计算四阶矩和二阶矩 + double m4 = 0.0; + double m2 = 0.0; + for (int i = 0; i < length; i++) + { + m4 += pow(inputdata[i] - mean, 4); + m2 += pow(inputdata[i] - mean, 2); + } + m2 /= length; + m4 /= length; + + return m4 / (m2 * m2) - 3.0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosisfactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosisfactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..f4bdf419dc5ca0d1b6e04b9fb5d9a3a2fcf110e8 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Kurtosisfactor.c" @@ -0,0 +1,26 @@ +#include +#include + +// 计算时域特征值-峭度因子 +double bdsp_calc_Kurtosisfactor(float *inputdata, int length) +{ + // 计算峭度 + double kurtosis = bdsp_calc_Kurtosis(inputdata, length); + + // 计算标准差 + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += pow(inputdata[i] - mean, 2); + } + double std = sqrt(sum / (length - 1)); + + return kurtosis / pow(std, 4); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Marginfactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Marginfactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..81617c2cce971f56c6295ac421eee9f4fd71df3b --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Marginfactor.c" @@ -0,0 +1,26 @@ +#include +#include + +// 计算时域特征值-裕度因子 +double bdsp_calc_Marginfactor(float *inputdata, int length) +{ + // 计算最大值 + double max = inputdata[0]; + for (int i = 0; i < length; i++) + { + if (inputdata[i] > max) + { + max = inputdata[i]; + } + } + + // 计算方根幅值 + double root_sum = 0.0; + for (int i = 0; i < length; i++) + { + root_sum += pow(fabs(inputdata[i]), 2); + } + double xfg = sqrt(root_sum / length); + + return max / xfg; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Max.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Max.c" new file mode 100644 index 0000000000000000000000000000000000000000..2e36d47ed5e816e9ad2ea2f4b359dc85f1dfc291 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Max.c" @@ -0,0 +1,18 @@ +#include +#include + +// 计算时域特征值-最大值 +double bdsp_calc_Max(float *inputdata, int length) +{ + double Max = inputdata[0]; + + for (int i = 0; i < length; i++) + { + if (inputdata[i] > Max) + { + Max = inputdata[i]; + } + } + + return Max; +} diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Min.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Min.c" new file mode 100644 index 0000000000000000000000000000000000000000..061761f5bcccd009744582ae288bd3459799a384 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Min.c" @@ -0,0 +1,18 @@ +#include +#include + +// 计算时域特征值-最小值 +double bdsp_calc_Min(float *inputdata, int length) +{ + double Min = inputdata[0]; + + for (int i = 0; i < length; i++) + { + if (inputdata[i] < Min) + { + Min = inputdata[i]; + } + } + + return Min; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peak2Valley.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peak2Valley.c" new file mode 100644 index 0000000000000000000000000000000000000000..7e2def44bf5f8ef7ca7443ad8789251fd095aefe --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peak2Valley.c" @@ -0,0 +1,23 @@ +#include +#include + +// 计算时域特征值-峰峰值 +double bdsp_calc_Peak2Valley(float *inputdata, int length) +{ + double max = inputdata[0]; + double min = inputdata[0]; + + for (int i = 0; i < length; i++) + { + if (inputdata[i] > max) + { + max = inputdata[i]; + } + if (inputdata[i] < min) + { + min = inputdata[i]; + } + } + + return max - min; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peakfactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peakfactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..39f76a523406ec78d7215297e60076b2b6691892 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Peakfactor.c" @@ -0,0 +1,26 @@ +#include +#include + +// 计算时域特征值-峰值因子 +double bdsp_calc_Peakfactor(float *inputdata, int length) +{ + // 计算最大值 + double max = inputdata[0]; + for (int i = 0; i < length; i++) + { + if (inputdata[i] > max) + { + max = inputdata[i]; + } + } + + // 计算均方根 + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += inputdata[i] * inputdata[i]; + } + double rms = sqrt(sum / length); + + return max / rms; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Pulsefactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Pulsefactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..efc417ef3a05a4bc123cf6c7720edcd349971823 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Pulsefactor.c" @@ -0,0 +1,26 @@ +#include +#include + +// 计算时域特征值-脉冲因子 +double bdsp_calc_Pulsefactor(float *inputdata, int length) +{ + // 计算最大值 + double max = inputdata[0]; + for (int i = 0; i < length; i++) + { + if (inputdata[i] > max) + { + max = inputdata[i]; + } + } + + // 计算绝对平均幅值 + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += fabs(inputdata[i]); + } + double absAveAmp = sum / length; + + return max / absAveAmp; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Rms.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Rms.c" new file mode 100644 index 0000000000000000000000000000000000000000..d5e78c5c29811ac9a3849ff1a4a17dea27401265 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Rms.c" @@ -0,0 +1,15 @@ +#include +#include + +// 计算时域特征值-均方根 +double bdsp_calc_Rms(float *inputdata, int length) +{ + double sum = 0.0; + + for (int i = 0; i < length; i++) + { + sum += inputdata[i] * inputdata[i]; + } + + return sqrt(sum / length); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewness.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewness.c" new file mode 100644 index 0000000000000000000000000000000000000000..8da703f5390d6c4cdf6bf014820ec952b496e624 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewness.c" @@ -0,0 +1,27 @@ +#include +#include + +// 计算时域特征值-偏度 +double bdsp_calc_Skewness(float *inputdata, int length) +{ + // 计算平均值 + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + // 计算三阶矩和二阶矩 + double m3 = 0.0; + double m2 = 0.0; + for (int i = 0; i < length; i++) + { + m3 += pow(inputdata[i] - mean, 3); + m2 += pow(inputdata[i] - mean, 2); + } + m2 /= length; + m3 /= length; + + return m3 / pow(m2, 1.5); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewnessfactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewnessfactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..0bf145801133dc6aabd61cd02350d88638fafd79 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Skewnessfactor.c" @@ -0,0 +1,26 @@ +#include +#include + +// 计算时域特征值-偏度因子 +double bdsp_calc_Skewnessfactor(float *inputdata, int length) +{ + // 计算偏度 + double skewness = bdsp_calc_Skewness(inputdata, length); + + // 计算标准差 + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += pow(inputdata[i] - mean, 2); + } + double std = sqrt(sum / (length - 1)); + + return skewness / pow(std, 3); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Std.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Std.c" new file mode 100644 index 0000000000000000000000000000000000000000..2d55ffae3f74a5416f6d29a90c1c538f5f7667a8 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Std.c" @@ -0,0 +1,21 @@ +#include +#include + +// 计算时域特征值-标准差 +double bdsp_calc_Std(float *inputdata, int length) +{ + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += (inputdata[i] - mean) * (inputdata[i] - mean); + } + + return sqrt(sum / (length - 1)); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Var.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Var.c" new file mode 100644 index 0000000000000000000000000000000000000000..c684917a23044d2474dc6aa66ff040332f2418f7 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Var.c" @@ -0,0 +1,21 @@ +#include +#include + +// 计算时域特征值-方差 +double bdsp_calc_Var(float *inputdata, int length) +{ + double mean = 0.0; + for (int i = 0; i < length; i++) + { + mean += inputdata[i]; + } + mean /= length; + + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += (inputdata[i] - mean) * (inputdata[i] - mean); + } + + return sum / (length - 1); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Wavefactor.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Wavefactor.c" new file mode 100644 index 0000000000000000000000000000000000000000..ca37bccd6508d4f3dfe52a7fca206cb56434def6 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_Wavefactor.c" @@ -0,0 +1,24 @@ +#include +#include + +// 计算时域特征值-波形因子 +double bdsp_calc_Wavefactor(float *inputdata, int length) +{ + // 计算均方根 + double sum_rms = 0.0; + for (int i = 0; i < length; i++) + { + sum_rms += inputdata[i] * inputdata[i]; + } + double rms = sqrt(sum_rms / length); + + // 计算绝对平均幅值 + double sum = 0.0; + for (int i = 0; i < length; i++) + { + sum += fabs(inputdata[i]); + } + double absAveAmp = sum / length; + + return rms / absAveAmp; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_XFG.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_XFG.c" new file mode 100644 index 0000000000000000000000000000000000000000..d7eb5a6f7da56910ff2f02c6ccfa3d0acc65c297 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeEigenValue/bdsp_calc_XFG.c" @@ -0,0 +1,15 @@ +#include +#include + +// 计算时域特征值-方根幅值 +double bdsp_calc_XFG(float *inputdata, int length) +{ + double root_sum = 0.0; + + for (int i = 0; i < length; i++) + { + root_sum += pow(fabs(inputdata[i]), 2); + } + + return sqrt(root_sum / length); +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeIntegration.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeIntegration.c" new file mode 100644 index 0000000000000000000000000000000000000000..04f676ec90608da157971e1f76d485a16d845c15 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_TimeIntegration.c" @@ -0,0 +1,30 @@ +#include + +/** + * 时域单次积分函数 + * @param inputData 输入数据数组指针 + * @param outputData 输出积分结果数组指针 + * @param dataLength 数据长度 + * @param sampleRate 采样率(Hz) + * @return 0:成功, -1:失败 + * 说明:使用梯形积分法计算时域积分 + */ +int bdsp_calc_TimeIntegration(const float* inputData, float* outputData, int dataLength, float sampleRate) { + // 参数检查 + if (inputData == NULL || outputData == NULL || dataLength <= 1 || sampleRate <= 0) { + return -1; + } + + // 计算采样时间间隔 + float interval = 1.0f / sampleRate; + + // 设置初始值为0 + outputData[0] = 0.0f; + + // 使用梯形法则计算积分值 + for (int i = 1; i < dataLength; i++) { + outputData[i] = outputData[i-1] + 0.5f * interval * (inputData[i-1] + inputData[i]); + } + + return 0; +} diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_dB.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_dB.c" new file mode 100644 index 0000000000000000000000000000000000000000..66eeafba954294f50c5669c7efc1abbb99d2bce2 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_dB.c" @@ -0,0 +1,73 @@ +#include + +/** + * 计算指定频率范围内的dB值 + * @param FFTPwr 输入的功率谱数据数组 + * @param freqSeq 频率序列数组 + * @param length 数组长度 + * @param lowerFreq 频段下限频率 + * @param upperFreq 频段上限频率 + * @param dBref dB参考值 + * @param dB 输出的dB值指针 + * @return 0:成功, -1:参数错误 + */ +int bdsp_calc_dB(const double *FFTPwr, const double *freqSeq, int length, + double lowerFreq, double upperFreq, double dBref, double *dB) { + // 参数检查 + if (FFTPwr == NULL || freqSeq == NULL || dB == NULL || + length <= 0 || lowerFreq > upperFreq || dBref <= 0.0) { + return -1; + } + + // 找到频率范围内的索引 + int startIdx = -1; + int endIdx = -1; + + for (int i = 0; i < length; i++) { + if (startIdx == -1 && freqSeq[i] >= lowerFreq) { + startIdx = i; + } + if (freqSeq[i] <= upperFreq) { + endIdx = i; + } + } + + // 检查是否找到有效范围 + if (startIdx == -1 || endIdx == -1 || startIdx > endIdx) { + *dB = -INFINITY; // 如果没有找到有效范围,返回负无穷 + return 0; + } + + // 计算能量(使用梯形法则) + double energy = 0.0; + + // 首尾点权重0.25 + energy += 0.25 * FFTPwr[startIdx]; + energy += 0.25 * FFTPwr[endIdx]; + + // 中间点权重0.5 + for (int i = startIdx + 1; i < endIdx; i++) { + energy += 0.5 * FFTPwr[i]; + } + + // 计算dB值 + *dB = 10.0 * log10(energy / (dBref * dBref)); + + return 0; +} + +// // 使用示例 +// void example_usage() { +// const int LENGTH = 5; +// double FFTPwr[] = {1.0, 2.0, 3.0, 4.0, 5.0}; +// double freqSeq[] = {0.0, 100.0, 200.0, 300.0, 400.0}; +// double lowerFreq = 100.0; +// double upperFreq = 300.0; +// double dBref = 1e-6; // 常用的参考值,如1微伏 +// double dB; + +// if(bdsp_calc_dB(FFTPwr, freqSeq, LENGTH, lowerFreq, upperFreq, dBref, &dB) == 0) { +// printf("dB value in range %.1f-%.1f Hz: %.2f dB\n", +// lowerFreq, upperFreq, dB); +// } +// } \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octave.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octave.c" new file mode 100644 index 0000000000000000000000000000000000000000..4f847b309df59a5e60efccd060170d335da74757 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octave.c" @@ -0,0 +1,45 @@ +#include +#include +#include + +/* +* 函数名: bdsp_calc_octave +* 功能: 计算指定频率范围下的dB值 +* 参数: +* FFTPwr: 功率谱 +* lowerFreq: 频率下限数组 +* upperFreq: 频率上限数组 +* freqSeq: 频率序列 +* freqLen: 频率序列长度 +* N : 频率上下限数组长度 +* dBref : 频率参考值 +* dB : 分贝值 +* 返回值: +* 0 - 成功 +* -1 - 失败 +*/ +int bdsp_calc_octave(double *FFTPwr, double *lowerFreq, double *upperFreq, + double *freqSeq, int freqLen, int N, double dBref, double *dB) { + for (int i = 0; i < N; i++) { + double energy = 0.0; + int found = 0; // 标记是否找到符合条件的频率点 + + for (int j = 0; j < freqLen; j++) { + if (freqSeq[j] >= lowerFreq[i] && freqSeq[j] <= upperFreq[i]) { + found = 1; + if (j == 0 || j == freqLen - 1) { + energy += 0.25 * FFTPwr[j]; + } else { + energy += 0.5 * FFTPwr[j]; + } + } + } + + if (!found) { + dB[i] = 0.0; // 如果没有找到匹配的频率范围,直接设为 0 + } else { + dB[i] = 10.0 * log10(energy / (dBref * dBref)); + } + } + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octaveFreq.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octaveFreq.c" new file mode 100644 index 0000000000000000000000000000000000000000..84baa2d592cc7022a982d9321c2ef9a854ae350a --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_octaveFreq.c" @@ -0,0 +1,83 @@ +#include +#include +#include +#include + +/** + * @brief 计算倍频程频带上下限频率 + * @param octaveType 倍频程类型(1-4) + * @param lowerFreq 输出参数,存储下限频率的数组指针 + * @param upperFreq 输出参数,存储上限频率的数组指针 + * @return int 返回数组长度,-1表示输入错误 + * + * @note 需调用者负责释放lowerFreq和upperFreq的内存 + */ +int bdsp_calc_octaveFreq(int octaveType, double** lowerFreq, double** upperFreq) +{ + // 验证输入有效性 + if (octaveType < 1 || octaveType > 4) { + fprintf(stderr, "错误:无效的octaveType参数(允许值1-4)\n"); + return -1; + } + + // 定义带宽参数和数组长度 + const double bandWidth[] = {1.0/6, 1.0/12, 1.0/24, 0.5}; + const int N[] = {31, 61, 121, 11}; // 各类型对应的频带数 + + // 确保索引转换为0-based + int type_index = octaveType - 1; + int array_size = N[type_index]; + + // 分配内存 + *lowerFreq = (double*)malloc(array_size * sizeof(double)); + *upperFreq = (double*)malloc(array_size * sizeof(double)); + + if (octaveType != 4) { // 处理1/3,1/6,1/12倍频程 + double bw = bandWidth[type_index]; + + for (int i = 0; i < array_size; ++i) { + // 计算公共指数项 + double exponent = 1.0 + 3.0/5.0 * bw * i; + + // 计算基数项 + double base = pow(10.0, exponent); + + // 计算上下限频率 + (*lowerFreq)[i] = base / pow(2.0, bw); + (*upperFreq)[i] = base * pow(2.0, bw); + } + } + else { // 处理1倍频程特殊情况 + // 预定义中心频率数组(MATLAB原数据) + const double Freq[] = {11,22,44,88,177,355,710,1420,2840,5680,11360,22720}; + + // 生成上下限(数组长度为11) + for (int i = 0; i < array_size; ++i) { // array_size=11 + (*lowerFreq)[i] = Freq[i]; + (*upperFreq)[i] = Freq[i+1]; + } + } + + return array_size; +} + +/* +示例用法: +int main() +{ + double *lower, *upper; + int type = 1; // 测试1/3倍频程 + + int len = bdsp_calc_octaveFreq(type, &lower, &upper); + + if (len > 0) { + printf("类型%d倍频程频带(显示前5组):\n", type); + for (int i = 0; i < 5; ++i) { + printf("[%.2f Hz, %.2f Hz]\n", lower[i], upper[i]); + } + free(lower); + free(upper); + } + return 0; +} +*/ \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_windowWeight.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_windowWeight.c" new file mode 100644 index 0000000000000000000000000000000000000000..c8d0d7233f624abe391da0168f70ca3f66d82911 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/bdsp_calc_windowWeight.c" @@ -0,0 +1,117 @@ +#include +#include + +#define M_PI 3.14159265358979323846 + +static double i0(double x) { + // 计算零阶修正贝塞尔函数 + double ax = fabs(x); + double ans; + double y; + + if (ax < 3.75) { + y = x / 3.75; + y *= y; + ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492 + + y * (0.2659732 + y * (0.0360768 + y * 0.0045813))))); + } else { + y = 3.75 / ax; + ans = (exp(ax) / sqrt(ax)) * (0.39894228 + y * (0.01328592 + + y * (0.00225319 + y * (-0.00157565 + y * (0.00916281 + + y * (-0.02057706 + y * (0.02635537 + y * (-0.01647633 + + y * 0.00392377)))))))); + } + return ans; +} + +double* bdsp_calc_WindowWeight(int sampleLength, int windowType, double windowPara) { + if (sampleLength <= 0) { + return NULL; + } + + double* windowWeight = (double*)malloc(sampleLength * sizeof(double)); + if (!windowWeight) { + return NULL; + } + + // 处理长度为1的特殊情况 + if (sampleLength == 1) { + windowWeight[0] = 1.0; + return windowWeight; + } + + // 校验窗口类型有效性 + if (windowType < 1 || windowType > 5) { + windowType = 6; + } + + switch (windowType) { + case 1: { // 汉宁窗 + for (int i = 0; i < sampleLength; i++) { + double angle = 2 * M_PI * i / (sampleLength - 1); + windowWeight[i] = 0.5 * (1 - cos(angle)); + } + break; + } + case 2: { // 海明窗 + for (int i = 0; i < sampleLength; i++) { + double angle = 2 * M_PI * i / (sampleLength - 1); + windowWeight[i] = 0.54 - 0.46 * cos(angle); + } + break; + } + case 3: { // 布莱克曼窗 + for (int i = 0; i < sampleLength; i++) { + double angle = 2 * M_PI * i / (sampleLength - 1); + windowWeight[i] = 0.42 - 0.5 * cos(angle) + 0.08 * cos(2 * angle); + } + break; + } + case 4: { // 平顶窗 + const double a[5] = {0.21557895, 0.41663158, 0.277263158, + 0.083578947, 0.006947368}; + for (int i = 0; i < sampleLength; i++) { + double angle = 2 * M_PI * i / (sampleLength - 1); + windowWeight[i] = a[0] + - a[1] * cos(angle) + + a[2] * cos(2 * angle) + - a[3] * cos(3 * angle) + + a[4] * cos(4 * angle); + } + break; + } + case 5: { // 凯塞窗 + double beta = windowPara; + double denominator = i0(beta); + double alpha = (sampleLength - 1) / 2.0; + + for (int i = 0; i < sampleLength; i++) { + double x = (i - alpha) / alpha; + x = 1 - x * x; // 1 - ((i-alpha)/alpha)^2 + x = (x > 0) ? sqrt(x) : 0; // 防止负值 + double numerator = i0(beta * x); + windowWeight[i] = numerator / denominator; + } + break; + } + default: { // 矩形窗 + for (int i = 0; i < sampleLength; i++) { + windowWeight[i] = 1.0; + } + break; + } + } + + return windowWeight; +} + +//example +// int main() { +// // 生成1024点汉宁窗系数 +// double* window = bdsp_calc_WindowWeight(1024, 1, 0); + +// // 使用窗函数数据... + +// free(window); // 释放内存 +// return 0; +// } \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/fftw3.h" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/fftw3.h" new file mode 100644 index 0000000000000000000000000000000000000000..39661d226163178bb82b3642cc487155fa370dbe --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/fftw3.h" @@ -0,0 +1,415 @@ +/* + * Copyright (c) 2003, 2007-14 Matteo Frigo + * Copyright (c) 2003, 2007-14 Massachusetts Institute of Technology + * + * The following statement of license applies *only* to this header file, + * and *not* to the other files distributed with FFTW or derived therefrom: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************** NOTE TO USERS ********************************* + * + * THIS IS A HEADER FILE, NOT A MANUAL + * + * If you want to know how to use FFTW, please read the manual, + * online at http://www.fftw.org/doc/ and also included with FFTW. + * For a quick start, see the manual's tutorial section. + * + * (Reading header files to learn how to use a library is a habit + * stemming from code lacking a proper manual. Arguably, it's a + * *bad* habit in most cases, because header files can contain + * interfaces that are not part of the public, stable API.) + * + ****************************************************************************/ + +#ifndef FFTW3_H +#define FFTW3_H + +#include + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* If is included, use the C99 complex type. Otherwise + define a type bit-compatible with C99 complex */ +#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) +# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C +#else +# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2] +#endif + +#define FFTW_CONCAT(prefix, name) prefix ## name +#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name) +#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name) +#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name) +#define FFTW_MANGLE_QUAD(name) FFTW_CONCAT(fftwq_, name) + +/* IMPORTANT: for Windows compilers, you should add a line +*/ +#define FFTW_DLL +/* + here and in kernel/ifftw.h if you are compiling/using FFTW as a + DLL, in order to do the proper importing/exporting, or + alternatively compile with -DFFTW_DLL or the equivalent + command-line flag. This is not necessary under MinGW/Cygwin, where + libtool does the imports/exports automatically. */ +#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__)) + /* annoying Windows syntax for shared-library declarations */ +# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */ +# define FFTW_EXTERN extern __declspec(dllexport) +# else /* user is calling FFTW; import symbol */ +# define FFTW_EXTERN extern __declspec(dllimport) +# endif +#else +# define FFTW_EXTERN extern +#endif + +enum fftw_r2r_kind_do_not_use_me { + FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, + FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, + FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 +}; + +struct fftw_iodim_do_not_use_me { + int n; /* dimension size */ + int is; /* input stride */ + int os; /* output stride */ +}; + +#include /* for ptrdiff_t */ +struct fftw_iodim64_do_not_use_me { + ptrdiff_t n; /* dimension size */ + ptrdiff_t is; /* input stride */ + ptrdiff_t os; /* output stride */ +}; + +typedef void (*fftw_write_char_func_do_not_use_me)(char c, void *); +typedef int (*fftw_read_char_func_do_not_use_me)(void *); + +/* + huge second-order macro that defines prototypes for all API + functions. We expand this macro for each supported precision + + X: name-mangling macro + R: real data type + C: complex data type +*/ + +#define FFTW_DEFINE_API(X, R, C) \ + \ +FFTW_DEFINE_COMPLEX(R, C); \ + \ +typedef struct X(plan_s) *X(plan); \ + \ +typedef struct fftw_iodim_do_not_use_me X(iodim); \ +typedef struct fftw_iodim64_do_not_use_me X(iodim64); \ + \ +typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \ + \ +typedef fftw_write_char_func_do_not_use_me X(write_char_func); \ +typedef fftw_read_char_func_do_not_use_me X(read_char_func); \ + \ +FFTW_EXTERN void X(execute)(const X(plan) p); \ + \ +FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \ + C *in, C *out, int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \ +FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \ + R *ro, R *io); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \ + R *in, C *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \ + R *in, C *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \ + int n2, \ + R *in, C *out, unsigned flags); \ + \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \ + C *in, R *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \ + int n2, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \ +FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \ + \ +FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \ + R *in, R *ro, R *io); \ +FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \ + R *ri, R *ii, R *out); \ + \ +FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \ + X(r2r_kind) kind, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \ + X(r2r_kind) kind0, X(r2r_kind) kind1, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \ + R *in, R *out, X(r2r_kind) kind0, \ + X(r2r_kind) kind1, X(r2r_kind) kind2, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \ + \ +FFTW_EXTERN void X(destroy_plan)(X(plan) p); \ +FFTW_EXTERN void X(forget_wisdom)(void); \ +FFTW_EXTERN void X(cleanup)(void); \ + \ +FFTW_EXTERN void X(set_timelimit)(double t); \ + \ +FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \ +FFTW_EXTERN int X(init_threads)(void); \ +FFTW_EXTERN void X(cleanup_threads)(void); \ +FFTW_EXTERN void X(make_planner_thread_safe)(void); \ + \ +FFTW_EXTERN int X(export_wisdom_to_filename)(const char *filename); \ +FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \ +FFTW_EXTERN char *X(export_wisdom_to_string)(void); \ +FFTW_EXTERN void X(export_wisdom)(X(write_char_func) write_char, \ + void *data); \ +FFTW_EXTERN int X(import_system_wisdom)(void); \ +FFTW_EXTERN int X(import_wisdom_from_filename)(const char *filename); \ +FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \ +FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \ +FFTW_EXTERN int X(import_wisdom)(X(read_char_func) read_char, void *data); \ + \ +FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \ +FFTW_EXTERN void X(print_plan)(const X(plan) p); \ +FFTW_EXTERN char *X(sprint_plan)(const X(plan) p); \ + \ +FFTW_EXTERN void *X(malloc)(size_t n); \ +FFTW_EXTERN R *X(alloc_real)(size_t n); \ +FFTW_EXTERN C *X(alloc_complex)(size_t n); \ +FFTW_EXTERN void X(free)(void *p); \ + \ +FFTW_EXTERN void X(flops)(const X(plan) p, \ + double *add, double *mul, double *fmas); \ +FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \ +FFTW_EXTERN double X(cost)(const X(plan) p); \ + \ +FFTW_EXTERN int X(alignment_of)(R *p); \ +FFTW_EXTERN const char X(version)[]; \ +FFTW_EXTERN const char X(cc)[]; \ +FFTW_EXTERN const char X(codelet_optim)[]; + + +/* end of FFTW_DEFINE_API macro */ + +FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex) +FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex) +FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex) + +/* __float128 (quad precision) is a gcc extension on i386, x86_64, and ia64 + for gcc >= 4.6 (compiled in FFTW with --enable-quad-precision) */ +#if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) \ + && !(defined(__ICC) || defined(__INTEL_COMPILER) || defined(__CUDACC__) || defined(__PGI)) \ + && (defined(__i386__) || defined(__x86_64__) || defined(__ia64__)) +# if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) +/* note: __float128 is a typedef, which is not supported with the _Complex + keyword in gcc, so instead we use this ugly __attribute__ version. + However, we can't simply pass the __attribute__ version to + FFTW_DEFINE_API because the __attribute__ confuses gcc in pointer + types. Hence redefining FFTW_DEFINE_COMPLEX. Ugh. */ +# undef FFTW_DEFINE_COMPLEX +# define FFTW_DEFINE_COMPLEX(R, C) typedef _Complex float __attribute__((mode(TC))) C +# endif +FFTW_DEFINE_API(FFTW_MANGLE_QUAD, __float128, fftwq_complex) +#endif + +#define FFTW_FORWARD (-1) +#define FFTW_BACKWARD (+1) + +#define FFTW_NO_TIMELIMIT (-1.0) + +/* documented flags */ +#define FFTW_MEASURE (0U) +#define FFTW_DESTROY_INPUT (1U << 0) +#define FFTW_UNALIGNED (1U << 1) +#define FFTW_CONSERVE_MEMORY (1U << 2) +#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ +#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ +#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ +#define FFTW_ESTIMATE (1U << 6) +#define FFTW_WISDOM_ONLY (1U << 21) + +/* undocumented beyond-guru flags */ +#define FFTW_ESTIMATE_PATIENT (1U << 7) +#define FFTW_BELIEVE_PCOST (1U << 8) +#define FFTW_NO_DFT_R2HC (1U << 9) +#define FFTW_NO_NONTHREADED (1U << 10) +#define FFTW_NO_BUFFERING (1U << 11) +#define FFTW_NO_INDIRECT_OP (1U << 12) +#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */ +#define FFTW_NO_RANK_SPLITS (1U << 14) +#define FFTW_NO_VRANK_SPLITS (1U << 15) +#define FFTW_NO_VRECURSE (1U << 16) +#define FFTW_NO_SIMD (1U << 17) +#define FFTW_NO_SLOW (1U << 18) +#define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19) +#define FFTW_ALLOW_PRUNING (1U << 20) + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FFTW3_H */ diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/butter.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/butter.c" new file mode 100644 index 0000000000000000000000000000000000000000..457739996f499a1ff8c8aa20ec67e5a5faa8203b --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/butter.c" @@ -0,0 +1,301 @@ + +#include +#include +#include +#include +#include "../header/butter.h" +#define M_PI 3.14159265358979323846 // pi + /********************************************************************** + binomial_mult - multiplies a series of binomials together and returns + the coefficients of the resulting polynomial. + + The multiplication has the following form: + + (x+p[0])*(x+p[1])*...*(x+p[n-1]) + + The p[i] coefficients are assumed to be complex and are passed to the + function as a pointer to an array of doubles of length 2n. + + The resulting polynomial has the following form: + + x^n + a[0]*x^n-1 + a[1]*x^n-2 + ... +a[n-2]*x + a[n-1] + + The a[i] coefficients can in general be complex but should in most + cases turn out to be real. The a[i] coefficients are returned by the + function as a pointer to an array of doubles of length 2n. Storage + for the array is allocated by the function and should be freed by the + calling program when no longer needed. + + Function arguments: + + n - The number of binomials to multiply + p - Pointer to an array of doubles where p[2i] (i=0...n-1) is + assumed to be the real part of the coefficient of the ith binomial + and p[2i+1] is assumed to be the imaginary part. The overall size + of the array is then 2n. + */ + +float *binomial_mult(int n, float *p) +{ + int i, j; + float *a; + + a = (float *)calloc(2 * n, sizeof(float)); + if (a == NULL) + return (NULL); + + for (i = 0; i < n; ++i) + { + for (j = i; j > 0; --j) + { + a[2 * j] += p[2 * i] * a[2 * (j - 1)] - p[2 * i + 1] * a[2 * (j - 1) + 1]; + a[2 * j + 1] += p[2 * i] * a[2 * (j - 1) + 1] + p[2 * i + 1] * a[2 * (j - 1)]; + } + a[0] += p[2 * i]; + a[1] += p[2 * i + 1]; + } + return (a); +} + +/********************************************************************** + trinomial_mult - multiplies a series of trinomials together and returns + the coefficients of the resulting polynomial. + + The multiplication has the following form: + + (x^2 + b[0]x + c[0])*(x^2 + b[1]x + c[1])*...*(x^2 + b[n-1]x + c[n-1]) + + The b[i] and c[i] coefficients are assumed to be complex and are passed + to the function as a pointers to arrays of doubles of length 2n. The real + part of the coefficients are stored in the even numbered elements of the + array and the imaginary parts are stored in the odd numbered elements. + + The resulting polynomial has the following form: + + x^2n + a[0]*x^2n-1 + a[1]*x^2n-2 + ... +a[2n-2]*x + a[2n-1] + + The a[i] coefficients can in general be complex but should in most cases + turn out to be real. The a[i] coefficients are returned by the function as + a pointer to an array of doubles of length 4n. The real and imaginary + parts are stored, respectively, in the even and odd elements of the array. + Storage for the array is allocated by the function and should be freed by + the calling program when no longer needed. + + Function arguments: + + n - The number of trinomials to multiply + b - Pointer to an array of doubles of length 2n. + c - Pointer to an array of doubles of length 2n. +*/ + +float *trinomial_mult(int n, float *b, float *c) +{ + int i, j; + float *a; + + a = (float *)calloc(4 * n, sizeof(float)); + if (a == NULL) + return (NULL); + + a[2] = c[0]; + a[3] = c[1]; + a[0] = b[0]; + a[1] = b[1]; + + for (i = 1; i < n; ++i) + { + a[2 * (2 * i + 1)] += c[2 * i] * a[2 * (2 * i - 1)] - c[2 * i + 1] * a[2 * (2 * i - 1) + 1]; + a[2 * (2 * i + 1) + 1] += c[2 * i] * a[2 * (2 * i - 1) + 1] + c[2 * i + 1] * a[2 * (2 * i - 1)]; + + for (j = 2 * i; j > 1; --j) + { + a[2 * j] += b[2 * i] * a[2 * (j - 1)] - b[2 * i + 1] * a[2 * (j - 1) + 1] + + c[2 * i] * a[2 * (j - 2)] - c[2 * i + 1] * a[2 * (j - 2) + 1]; + a[2 * j + 1] += b[2 * i] * a[2 * (j - 1) + 1] + b[2 * i + 1] * a[2 * (j - 1)] + + c[2 * i] * a[2 * (j - 2) + 1] + c[2 * i + 1] * a[2 * (j - 2)]; + } + + a[2] += b[2 * i] * a[0] - b[2 * i + 1] * a[1] + c[2 * i]; + a[3] += b[2 * i] * a[1] + b[2 * i + 1] * a[0] + c[2 * i + 1]; + a[0] += b[2 * i]; + a[1] += b[2 * i + 1]; + } + + return (a); +} + +/********************************************************************** + dcof_bwbp - calculates the d coefficients for a butterworth bandpass + filter. The coefficients are returned as an array of doubles. + +*/ + +float *dcof_bwbp(int n, float f1f, float f2f) +{ + int k; // loop variables + float theta; // M_PI * (f2f - f1f) / 2.0 + float cp; // cosine of phi + float st; // sine of theta + float ct; // cosine of theta + float s2t; // sine of 2*theta + float c2t; // cosine 0f 2*theta + float *rcof; // z^-2 coefficients + float *tcof; // z^-1 coefficients + float *dcof; // dk coefficients + float parg; // pole angle + float sparg; // sine of pole angle + float cparg; // cosine of pole angle + float a; // workspace variables + + cp = cos(M_PI * (f2f + f1f) / 2.0); + theta = M_PI * (f2f - f1f) / 2.0; + st = sin(theta); + ct = cos(theta); + s2t = 2.0 * st * ct; // sine of 2*theta + c2t = 2.0 * ct * ct - 1.0; // cosine of 2*theta + + rcof = (float *)calloc(2 * n, sizeof(float)); + tcof = (float *)calloc(2 * n, sizeof(float)); + + for (k = 0; k < n; ++k) + { + parg = M_PI * (float)(2 * k + 1) / (float)(2 * n); + sparg = sin(parg); + cparg = cos(parg); + a = 1.0 + s2t * sparg; + rcof[2 * k] = c2t / a; + rcof[2 * k + 1] = s2t * cparg / a; + tcof[2 * k] = -2.0 * cp * (ct + st * sparg) / a; + tcof[2 * k + 1] = -2.0 * cp * st * cparg / a; + } + + dcof = trinomial_mult(n, tcof, rcof); + free(tcof); + free(rcof); + + dcof[1] = dcof[0]; + dcof[0] = 1.0; + //dcof[1] = dcof[0]; + for (k = 3; k <= 2 * n; ++k) + dcof[k] = dcof[2 * k - 2]; + return (dcof); +} + +/********************************************************************** + ccof_bwlp - calculates the c coefficients for a butterworth lowpass + filter. The coefficients are returned as an array of integers. + +*/ + +float *ccof_bwlp(int n) +{ + float *ccof; + int m; + int i; + + ccof = (float *)calloc(n + 1, sizeof(float)); + if (ccof == NULL) + return (NULL); + + ccof[0] = 1; + ccof[1] = n; + m = n / 2; + for (i = 2; i <= m; ++i) + { + ccof[i] = (n - i + 1) * ccof[i - 1] / i; + ccof[n - i] = ccof[i]; + } + ccof[n - 1] = n; + ccof[n] = 1; + + return (ccof); +} + +/********************************************************************** + ccof_bwhp - calculates the c coefficients for a butterworth highpass + filter. The coefficients are returned as an array of integers. + +*/ + +float *ccof_bwhp(int n) +{ + float *ccof; + int i; + + ccof = ccof_bwlp(n); + if (ccof == NULL) + return (NULL); + + for (i = 0; i <= n; ++i) + if (i % 2) + ccof[i] = -ccof[i]; + + return (ccof); +} + +/********************************************************************** + ccof_bwbp - calculates the c coefficients for a butterworth bandpass + filter. The coefficients are returned as an array of integers. + +*/ + +float *ccof_bwbp(int n) +{ + float *tcof; + float *ccof; + int i; + + ccof = (float *)calloc(2 * n + 1, sizeof(float)); + if (ccof == NULL) + return (NULL); + + tcof = ccof_bwhp(n); + if (tcof == NULL) + return (NULL); + + for (i = 0; i < n; ++i) + { + ccof[2 * i] = tcof[i]; + ccof[2 * i + 1] = 0.0; + } + ccof[2 * n] = tcof[n]; + + free(tcof); + return (ccof); +} + +/********************************************************************** + sf_bwbp - calculates the scaling factor for a butterworth bandpass filter. + The scaling factor is what the c coefficients must be multiplied by so + that the filter response has a maximum value of 1. + +*/ + +float sf_bwbp(int n, float f1f, float f2f) +{ + int k; // loop variables + float ctt; // cotangent of theta + float sfr, sfi; // real and imaginary parts of the scaling factor + float parg; // pole angle + float sparg; // sine of pole angle + float cparg; // cosine of pole angle + float a, b, c; // workspace variables + + ctt = 1.0 / tan(M_PI * (f2f - f1f) / 2.0); + sfr = 1.0; + sfi = 0.0; + + for (k = 0; k < n; ++k) + { + parg = M_PI * (double)(2 * k + 1) / (double)(2 * n); + sparg = ctt + sin(parg); + cparg = cos(parg); + a = (sfr + sfi) * (sparg - cparg); + b = sfr * sparg; + c = -sfi * cparg; + sfr = b - c; + sfi = a - b - c; + } + + return (1.0 / sfr); +} diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/filter.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/filter.c" new file mode 100644 index 0000000000000000000000000000000000000000..d91986bf75dd8195b229133eea2204606dd161d9 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/C/tong/filter.c" @@ -0,0 +1,247 @@ +#include "../header/libVibrationDSP.h" +#include +#include +#include +#include +#include "../header/butter.h" +#include +#include + +//#include "utils.h" +#define M_PI 3.14159265358979323846 +typedef unsigned int UI32; +#define INTAD_MAX 8388607 + + +float sf_bwhp(int n, float fcf); +float* dcof_bwhp(int n, float fcf); +float* dcof_bwlp(int n, float fcf); +//float* trinomial_mult(int n, float* b, float* c); +//float* binomial_mult(int n, float* p); +void buttordhp(int order, float fcf, float sf, float* a, float* b); +void butterworthhighp(float* a, float* b, int order, float* datainput, int siglength, float* dataoutput); + + +float* dcof_bwlp(int n, float fcf)//n 滤波阶数 fcf 截止频率=手持下限频率*2/fs +{ + int k; // loop variables + float theta; // M_PI * fcf / 2.0 + float st; // sine of theta + float ct; // cosine of theta + float parg; // pole angle + float sparg; // sine of the pole angle + float cparg; // cosine of the pole angle + float a; // workspace variable + float* rcof; // binomial coefficients + float* dcof; // dk coefficients + + rcof = (float*)calloc(2 * n, sizeof(float)); + if (rcof == NULL) return(NULL); + + theta = M_PI * fcf; + st = sin(theta); + ct = cos(theta); + + for (k = 0; k < n; ++k) + { + parg = M_PI * (float)(2 * k + 1) / (float)(2 * n); + sparg = sin(parg); + cparg = cos(parg); + a = 1.0 + st * sparg; + rcof[2 * k] = -ct / a; + rcof[2 * k + 1] = -st * cparg / a; + } + + dcof = binomial_mult(n, rcof); + free(rcof); + + dcof[1] = dcof[0]; + dcof[0] = 1.0; + for (k = 3; k <= n; ++k) + dcof[k] = dcof[2 * k - 2]; + return(dcof);//返回滤波系数 +} + +float* dcof_bwhp(int n, float fcf)//n 滤波阶数 fcf 截止频率 * 2/采样频率 +{ + return(dcof_bwlp(n, fcf)); +} + +float sf_bwhp(int n, float fcf)//n 滤波阶数 fcf 截止频率 * 2/采样频率 +{ + int m, k; // loop variables + float omega; // M_PI * fcf + float fomega; // function of omega + float parg0; // zeroth pole angle + float sf; // scaling factor + + omega = M_PI * fcf; + fomega = sin(omega); + parg0 = M_PI / (float)(2 * n); + + m = n / 2; + sf = 1.0; + for (k = 0; k < n / 2; ++k) + sf *= 1.0 + fomega * sin((float)(2 * k + 1) * parg0); + + fomega = cos(omega / 2.0); + + if (n % 2) sf *= fomega + sin(omega / 2.0); + sf = pow(fomega, n) / sf; + + return(sf); +} + + +//datainput 输入数据 +//siglength 输入数据长度//点数 +//dataoutput 输出数据 +//void butterworthhp(float * datainput,int siglength, int sigfs, float* dataoutput) +//{ +// dataoutput[0] = datainput[0]; +// dataoutput[1] = datainput[1]; +// for (int i = 2; i < siglength; i++) +// { +// dataoutput[i] = 0.99459123911164726 * datainput[i] +// +(-1.9891824782232945 * datainput[i - 1]) +// + 0.99459123911164726 * datainput[i - 2] +// - (-1.9891532233149847) * dataoutput[i - 1] +// - 0.98921173313160426 * dataoutput[i - 2]; +// } +//} + + +//order 阶数 +// fcf 截止频率 * 2/fs +// fs 采样频率 +// sf 归一化系数为1 +//datainput 输入数据 +//siglength 输入数据长度//点数 +//dataoutput 输出数据 +//a 高通滤波分母系数 +//b 高通滤波分子系数 +void buttordhp(int order, float fcf, float sf, float* a, float* b) +{ + float *aa;//白噪声 + aa = (float*)calloc(order + 1, sizeof(float)); + float* c; + c= (float*)calloc(order+1, sizeof(float)); + float d; + aa = dcof_bwhp(order,fcf); + c = ccof_bwhp(order); + d = sf_bwhp(order, fcf); + float* bb; + bb = (float*)calloc(order+1, sizeof(float)); + int i; + for (i = 0; i < order+1; i++) + { + bb[i] = d * c[i]; + } + //filter(order, a, b, size, x, y); // ˹ ͨ ˲ + //saveArray(aa, order+1, "10171a.txt"); + //saveArray(bb, order + 1, "10171b.txt"); + //cout << aa[0] << endl; + //printf("================"); + //cout << aa[1] << endl; + //printf("================"); + //cout << aa[2] << endl; + //printf("================"); + memcpy(a, aa, (order+1) * sizeof(float)); + memcpy(b, bb, (order+1) * sizeof(float)); + //saveArray(c, 9, "10171c.txt"); + //return *a, b; + free(aa); + free(c); + free(bb); +} + + +//datainput 输入数据 +//siglength 输入数据长度//点数 +//dataoutput 输出数据 +//a 高通滤波分母系数 +//b 高通滤波分子系数 +void butterworthhighp(float* a, float* b,int order,float* datainput, int siglength,float * dataoutput) +{ + //float* dataoutput; + //dataoutput = (float*)calloc(siglength, sizeof(float)); + //cout << a[0] << endl; + //printf("================"); + //cout << a[1] << endl; + //printf("================"); + //cout << a[2] << endl; + //printf("================"); + int i; + if (order == 2) + { + dataoutput[0] = datainput[0] * b[0]; + dataoutput[1] = datainput[1] * b[0] + (float)(b[1] * datainput[0]) - (float)(a[1] * dataoutput[0]); + for (i = order; i < siglength; i++) + { + dataoutput[i] = (float)(b[0] * datainput[i]) + (float)(b[1] * datainput[i - 1]) + (float)(b[2] * datainput[i - 2]) - (float)(a[1] * dataoutput[i - 1]) - (float)(a[2] * dataoutput[i - 2]); + } + } + else if (order == 4) + { + dataoutput[0] = datainput[0] * b[0]; + dataoutput[1] = datainput[1] * b[0] + (float)(b[1] * datainput[0]) - (float)(a[1] * dataoutput[0]); + dataoutput[2] = datainput[2] * b[0] + (float)(b[1] * datainput[1]) + (float)(b[2] * datainput[0]) - (float)(a[1] * dataoutput[1]) - (float)(a[2] * dataoutput[0]); + dataoutput[3] = datainput[3] * b[0] + (float)(b[1] * datainput[2]) + (float)(b[2] * datainput[1]) + (float)(b[3] * datainput[0]) - (float)(a[1] * dataoutput[2]) - (float)(a[2] * dataoutput[1]) - (float)(a[3] * dataoutput[0]); + + for (i = order; i < siglength; i++) + { + dataoutput[i] = (float)(b[0] * datainput[i]) + (float)(b[1] * datainput[i - 1]) + (float)(b[2] * datainput[i - 2]) + (float)(b[3] * datainput[i - 3]) + (float)(b[4] * datainput[i - 4]) - (float)(a[1] * dataoutput[i - 1]) - (float)(a[2] * dataoutput[i - 2]) - (float)(a[3] * dataoutput[i - 3]) - (float)(a[4] * dataoutput[i - 4]); + } + } + else if (order == 6) + { + dataoutput[0] = datainput[0]; + dataoutput[1] = datainput[1]; + dataoutput[2] = datainput[2]; + dataoutput[3] = datainput[3]; + dataoutput[4] = datainput[4]; + dataoutput[5] = datainput[5]; + for (i = order; i < siglength; i++) + { + dataoutput[i] = (float)(b[0] * datainput[i]) + (float)(b[1] * datainput[i - 1]) + (float)(b[2] * datainput[i - 2]) + (float)(b[3] * datainput[i - 3]) + (float)(b[4] * datainput[i - 4]) + (float)(b[5] * datainput[i - 5]) + (float)(b[6] * datainput[i - 6]) - (float)(a[1] * dataoutput[i - 1]) - (float)(a[2] * dataoutput[i - 2]) - (float)(a[3] * dataoutput[i - 3]) - (float)(a[4] * dataoutput[i - 4]) - (float)(a[5] * dataoutput[i - 5]) - (float)(a[6] * dataoutput[i - 6]); + } + } + else if (order == 8) + { + dataoutput[0] = datainput[0]; + dataoutput[1] = datainput[1]; + dataoutput[2] = datainput[2]; + dataoutput[3] = datainput[3]; + dataoutput[4] = datainput[4]; + dataoutput[5] = datainput[5]; + dataoutput[6] = datainput[6]; + dataoutput[7] = datainput[7]; + for (i = order; i < siglength; i++) + { + dataoutput[i] = (float)(b[0] * datainput[i]) + (float)(b[1] * datainput[i - 1]) + (float)(b[2] * datainput[i - 2]) + (float)(b[3] * datainput[i - 3]) + (float)(b[4] * datainput[i - 4]) + (float)(b[5] * datainput[i - 5]) + (float)(b[6] * datainput[i - 6]) + (float)(b[7] * datainput[i - 7]) + (float)(b[8] * datainput[i - 8]) - (float)(a[1] * dataoutput[i - 1]) - (float)(a[2] * dataoutput[i - 2]) - (float)(a[3] * dataoutput[i - 3]) - (float)(a[4] * dataoutput[i - 4]) - (float)(a[5] * dataoutput[i - 5]) - (float)(a[6] * dataoutput[i - 6]) - (float)(a[7] * dataoutput[i - 7]) - (float)(a[8] * dataoutput[i - 8]); + } + } + else + return; + //cout << dataoutput[2] << endl; + //printf("================================================="); +} + + +void BTHPFilter(float LowLimitFreq,float fs,int order,int DataLength,float *DataOutput,float *DataInput) +{ + printf("****BTHPFilter V1.0-20230706------aarch64****/n"); + float fcf=LowLimitFreq*2/fs; //算法的截止频率; + float *ParaA; //分子参数 + ParaA = (float*)calloc(order + 1, sizeof(float)); + float *ParaB; //分母参数 + ParaB = (float*)calloc(order + 1, sizeof(float)); + //float *tempInputdata=(float*)calloc(DataLength,sizeof(DataLength)); + //tempInputdata=(float*)DataInput; + buttordhp(order,fcf,1,ParaA,ParaB); + //float *tempOutputdata=(float*)calloc(DataLength,sizeof(DataLength)); + butterworthhighp(ParaA,ParaB,order,DataInput,DataLength,DataOutput); + //DataOutput=(UI32*)tempOutputdata; + free(ParaA); + free(ParaB); +} diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmp.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmp.m" new file mode 100644 index 0000000000000000000000000000000000000000..f15495b68091a4079f44823d25bbbcfa0602f7ba --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmp.m" @@ -0,0 +1,14 @@ + function FFTAmp = bdsp_ConvertFFTAmp(Spectrum,windowType) + % windowType - 窗函数类型(正整数) + % 1: 汉宁窗 + % 2: 海明窗 + % 3: 黑曼窗 + % 4: 平顶窗 + % 5: 凯塞窗(需要 beta) + % Others: 不加窗 + if ~ismember(windowType, [1, 2, 3, 4, 5]) + windowType = 6; + end + convertCoeff = [2,1.8516,2.3810,4.18,2.49,1]; + FFTAmp = Spectrum*convertCoeff(windowType); +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmpDB.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmpDB.m" new file mode 100644 index 0000000000000000000000000000000000000000..d33e43c28e0cbff6603c0dcd3c2934b569c17b6e --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTAmpDB.m" @@ -0,0 +1,5 @@ +function FFTAmpDB = bdsp_ConvertFFTAmpDB(FFTAmp,dBref) + FFTAmpDB = 20*log10(FFTAmp./dBref); +end + + diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTPwr.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTPwr.m" new file mode 100644 index 0000000000000000000000000000000000000000..6a93e55f1f1bf6f23fc1c0da1fd96dc49411b1cf --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_ConvertFFTPwr.m" @@ -0,0 +1,14 @@ +function FFTPwr = bdsp_ConvertFFTPwr(Spectrum,windowType) + % windowType - 窗函数类型(正整数) + % 1: 汉宁窗 + % 2: 海明窗 + % 3: 黑曼窗 + % 4: 平顶窗 + % 5: 凯塞窗(需要 beta) + % Others: 不加窗 + if ~ismember(windowType, [1, 2, 3, 4, 5]) + windowType = 6; + end + convertCoeff = [1.6338,1.5863,1.8119,2.26,1.85,1]; + FFTPwr = (convertCoeff(windowType)*Spectrum).^2; +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_DataRestore.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_DataRestore.m" new file mode 100644 index 0000000000000000000000000000000000000000..f5d84f3772aa49ce2f0b41208aea8790fef5778b --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_DataRestore.m" @@ -0,0 +1,3 @@ +function outputdata= bdsp_DataRestore(inputdata,adjustCoefficient,offsetValue,sensitivity) + outputdata = adjustCoefficient*inputdata/sensitivity+offsetValue; +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FFTWeighting.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FFTWeighting.m" new file mode 100644 index 0000000000000000000000000000000000000000..b5c8b965ddf9e3c9b9bdf6f13740e58db6e41336 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FFTWeighting.m" @@ -0,0 +1,17 @@ +function FFTPwr = bdsp_FFTWeighting(FFTPwr,weightingType,freqSeq) + % weightingType - 计权类型 + % 1: A (GB/T 3785.1-2023) + % 2: B (https://blog.csdn.net/xinshuwei/article/details/134411160) + % 3: C (GB/T 3785.1-2023) + + f = [20.6,107.7,737.9,12194]; + switch weightingType + case 1 + w = 10*log10(((f(4)^2.*(freqSeq.^4))./((freqSeq.^2+f(1)^2).*(freqSeq.^2+f(2)^2).^0.5.*(freqSeq.^2+f(3)^2).^0.5.*(freqSeq.^2+f(4)^2))).^2)+2; + case 2 + w = 10*log10(((f(4)^2.*(freqSeq.^4))./((freqSeq.^2+f(1)^2).*(freqSeq.^2+158.5^2).^0.5.*(freqSeq.^2+f(4)^2))).^2)+0.17; + case 3 + w = 10*log10(((f(4)^2.*(freqSeq.^4))./((freqSeq.^2+f(1)^2).*(freqSeq.^2+f(4)^2))).^2)+0.062; + end + FFTPwr = FFTPwr.*10.^(w/10); +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FindPeaks.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FindPeaks.m" new file mode 100644 index 0000000000000000000000000000000000000000..240baabb5709be851899acd9181b43b05466c6a9 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FindPeaks.m" @@ -0,0 +1,6 @@ +function FreqAmpPair = bdsp_FindPeaks(FFTAmp,minPeakHeight,minIntervalFreq,freqSeq) + sampleRes = sampleRate/sampleLength; + minPeakDistance = ceil(minIntervalFreq/sampleRes); + [peaks, locs] = findpeaks(FFTAmp, 'MinPeakHeight', minPeakHeight, 'MinPeakDistance', minPeakDistance); + FreqAmpPair = [freqSeq(locs)' peaks]; +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FreqSeq.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FreqSeq.m" new file mode 100644 index 0000000000000000000000000000000000000000..0f16c6e2aaa0fe0d3e00eb1fb10d8a8ec6be0221 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_FreqSeq.m" @@ -0,0 +1,3 @@ +function freqSeq = bdsp_FreqSeq(sampleLength,sampleRate) + freqSeq = 0:sampleRate/sampleLength:(floor(sampleRate/2)); + freqSeq = freqSeq(1:ceil(sampleLength/2))'; \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_TimeFilter.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_TimeFilter.m" new file mode 100644 index 0000000000000000000000000000000000000000..9d5fc73d6bf269ca5e0679eb4abb83096612da39 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_TimeFilter.m" @@ -0,0 +1,20 @@ +function filteredData = bdsp_TimeFilter(inputdata,sampleRate,~,filterOrder,filterLowerFreq,filterUpperFreq,filterType) + % filterType - 滤波种类 + % 1 - 高通 + % 2 - 低通 + % 3 - 带通 + % 4 - 带阻 + Wn = [filterLowerFreq,filterUpperFreq]; + switch filterType + case 1 + [b,a] = butter(filterOrder,filterUpperFreq/(sampleRate/2),"high"); + case 2 + [b,a] = butter(filterOrder,filterLowerFreq/(sampleRate/2),"low"); + case 3 + [b,a] = butter(filterOrder,Wn/(sampleRate/2),"bandpass"); + case 4 + [b,a] = butter(filterOrder,Wn/(sampleRate/2),"stop"); + end + filteredData = filter(b,a,inputdata); + % freqz(b, a, 65536, 65536); +end diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_Windowed.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_Windowed.m" new file mode 100644 index 0000000000000000000000000000000000000000..5910d44817591a93a2ee23f06cb0082243c13f65 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_Windowed.m" @@ -0,0 +1,3 @@ +function Spectrum= bdsp_Windowed(inputdata,windowWeight) + Spectrum = inputdata .* windowWeight; +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Cepstrum.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Cepstrum.m" new file mode 100644 index 0000000000000000000000000000000000000000..5c729fb7c363a2913f09ce7b911abce06fd21dd0 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Cepstrum.m" @@ -0,0 +1,3 @@ +function Cepstrum = bdsp_calc_Cepstrum(FFTAmp) + Cepstrum = abs(ifft(log10(FFTAmp))); +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_EigenFreqAmp.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_EigenFreqAmp.m" new file mode 100644 index 0000000000000000000000000000000000000000..46f76967b67cba3ea760a6f7632fef9ce6dadc49 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_EigenFreqAmp.m" @@ -0,0 +1,30 @@ +function FreqAmpPair = bdsp_calc_EigenFreqAmp(FFTAmp,eigenFreq,freqSeq,bandWidth) + + % eigenFreq - 特征频率列表 + % bandWidth - 在特征频率上下bandWitdth/2的范围内找幅值最大谱线 + % FreqAmpPair - N*2列表,第一列为输入的特征频率列表,第二列为对应的幅值 + + + N = length(eigenFreq); + eigenAmp = zeros(1,N); + for i = 1:N + if eigenFreq(i)>max(freqSeq) + eigenAmp(i)=0; + continue + end + lowerBound = eigenFreq(i) - bandWidth / 2; + upperBound = eigenFreq(i) + bandWidth / 2; + indices = find(freqSeq >= lowerBound & freqSeq <= upperBound); + + if isempty(indices) + eigenAmp(i) = 0; + else + eigenAmp(i) = max(FFTAmp(indices)); + end + end + FreqAmpPair = [eigenFreq' eigenAmp']; + +end + + + \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqEigenValue.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqEigenValue.m" new file mode 100644 index 0000000000000000000000000000000000000000..4f84733f37907ddcf27ce55a802f34dc36a000fb --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqEigenValue.m" @@ -0,0 +1,19 @@ +function TimeEigen = bdsp_calc_FreqEigenValue(FFTAmp,FFTPwr,freqSeq) + N = length(FFTAmp); + + TimeEigen.Ampavg = mean(FFTAmp); %01 幅值均值 + TimeEigen.fc = sum(freqSeq.*FFTPwr)/sum(FFTPwr); %02 重心频率 + TimeEigen.Msf = sum((freqSeq.^2).*FFTPwr)/sum(FFTPwr); %03 均方频率 + TimeEigen.Ampvar = sum((FFTAmp-TimeEigen.Ampavg).^2)/N; %04 幅值方差 + TimeEigen.Ampstd = sqrt(TimeEigen.Ampvar); %05 幅值标准差 + TimeEigen.Ampskewness = sum((FFTAmp-TimeEigen.Ampavg).^3)/(N*TimeEigen.Ampstd^3); %06 幅值偏度 + TimeEigen.Ampkurtosis = sum((FFTAmp-TimeEigen.Ampavg).^4)/(N*TimeEigen.Ampstd^4); %07 幅值峭度 + + TimeEigen.rmsf = sqrt(TimeEigen.Msf); %08 均方根频率 + TimeEigen.vf = sum((freqSeq-TimeEigen.fc).^2.*FFTPwr)/sum(FFTPwr); %09 频率方差 + TimeEigen.rvf = sqrt(TimeEigen.vf); %10 频率标准差 + TimeEigen.sigma = sum((freqSeq-TimeEigen.fc).^2.*FFTPwr)/N; %11 频率分布系数 + TimeEigen.fskewness = sum((freqSeq-TimeEigen.fc).^3.*FFTPwr)/(N*TimeEigen.sigma.^3); %12 频率偏度 + TimeEigen.fkurtosis = sum((freqSeq-TimeEigen.fc).^4.*FFTPwr)/(N*TimeEigen.sigma.^4); %13 频率峭度 + TimeEigen.sqrtf = sum(sqrt(abs(freqSeq-TimeEigen.fc)).*FFTPwr)/(sqrt(TimeEigen.sigma)*N); %14 平方根比率 +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqIntergration.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqIntergration.m" new file mode 100644 index 0000000000000000000000000000000000000000..490244bc8f9eb45fb670115e231050c180887b91 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_FreqIntergration.m" @@ -0,0 +1,5 @@ +function intergratedData = bdsp_calc_FreqIntergration(FFTPwr,freqSeq) + intergratedData = FFTPwr(2:end)./(2*pi*freqSeq(2:end)); + intergratedData = [0 intergratedData]; +end + \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Spectrum.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Spectrum.m" new file mode 100644 index 0000000000000000000000000000000000000000..a2cab1a3820ae73b0e92ed96df44c12e312e5c08 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_Spectrum.m" @@ -0,0 +1,6 @@ +function spectrum= bdsp_calc_Spectrum(inputdata) + N = length(inputdata); + spectrum = fft(inputdata); + spectrum = abs(spectrum(1:round(N/2)))*2/N; + spectrum(1) = spectrum(1)/2; +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeEigenValue.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeEigenValue.m" new file mode 100644 index 0000000000000000000000000000000000000000..4cde889b0dac08bb32fa5603fc4accaaef2ceca3 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeEigenValue.m" @@ -0,0 +1,26 @@ +function TimeEigen = bdsp_calc_TimeEigenValue(inputdata) + TimeEigen.Max = max(inputdata); %01 最大值 + TimeEigen.Min = min(inputdata); %02 最小值 + TimeEigen.Ave = mean(inputdata); %03 平均值 + TimeEigen.AbsAve = abs(TimeEigen.Ave); %04 均值绝对值 + TimeEigen.AbsAveAmp = mean(abs(inputdata)); %05 绝对平均幅值 + TimeEigen.XFG = mean(sqrt(abs(inputdata)))^2; %06 方根幅值 + TimeEigen.Rms = rms(inputdata); %07 均方根 + TimeEigen.Std = std(inputdata,1); %08 标准差 + TimeEigen.Var = var(inputdata,1); %09 方差 + TimeEigen.Peak2Valley = max(inputdata)-min(inputdata); %10 峰峰值 + TimeEigen.Peakfactor = TimeEigen.Max./TimeEigen.Rms; %11 峰值因子 + TimeEigen.Pulsefactor = TimeEigen.Max./TimeEigen.AbsAveAmp; %12 脉冲因子 + TimeEigen.Marginfactor = TimeEigen.Max./TimeEigen.XFG; %13 裕度因子 + TimeEigen.Wavefactor = TimeEigen.Rms./TimeEigen.AbsAveAmp; %14 波形因子 + TimeEigen.Skewnessfactor = skewness(inputdata,1); %17 偏度因子 + TimeEigen.Kurtosisfactor = kurtosis(inputdata,1); %18 峭度因子 + TimeEigen.Skewness = TimeEigen.Skewnessfactor.*TimeEigen.Std.^3; %15 偏度 + TimeEigen.Kurtosis = TimeEigen.Kurtosisfactor.*TimeEigen.Std.^4; %16 峭度 + +end + + + + + diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeIntergration.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeIntergration.m" new file mode 100644 index 0000000000000000000000000000000000000000..38de312fc93c6eed012454fc513429548a587c7b --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_TimeIntergration.m" @@ -0,0 +1,10 @@ +function intergratedData = bdsp_calc_TimeIntergration(inputData,sampleRate) + interval = 1/sampleRate; + N = length(inputData); + intergratedData = zeros(1,N); + intergratedData(1) = 0; + intergratedData(2) = 1/2*interval*(inputData(1)+inputData(2)); + for i = 3:N + intergratedData(i) = intergratedData(i-1)+1/2*interval*(inputData(i-1)+inputData(i)); + end +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_WindowWeight.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_WindowWeight.m" new file mode 100644 index 0000000000000000000000000000000000000000..7c822688b402c451fbb21f1e153acd21956ade49 --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_WindowWeight.m" @@ -0,0 +1,32 @@ +function windowWeight = bdsp_calc_WindowWeight(sampleLength,windowType,windowPara) + % windowType - 窗函数类型(正整数) + % 1: 汉宁窗 + % 2: 海明窗 + % 3: 黑曼窗 + % 4: 平顶窗 + % 5: 凯塞窗(需要 beta) + % Others: 不加窗 + % windowPara - Kaiser窗的beta参数 + if ~ismember(windowType, [1, 2, 3, 4, 5]) + windowType = 6; + end + switch windowType + case 1 + windowWeight = hann(sampleLength); + case 2 + windowWeight = hamming(sampleLength); + case 3 + windowWeight = blackman(sampleLength); + case 4 + windowWeight = zeros(1,sampleLength); + a = [0.21557895,0.41663158,0.277263158,0.083578947,0.006947368]; + for i = 0:1:sampleLength-1 + windowWeight(i+1) = a(1) - a(2)*cos(2*pi*i/(sampleLength-1)) + a(3)*cos(4*pi*i/(sampleLength-1)) - a(4)*cos(6*pi*i/(sampleLength-1)) +a(5)*cos(8*pi*i/(sampleLength-1)); + end + windowWeight = windowWeight'; + case 5 + beta = windowPara; + windowWeight = kaiser(sampleLength, beta); + otherwise + windowWeight = ones(1,sampleLength)'; + end diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_dB.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_dB.m" new file mode 100644 index 0000000000000000000000000000000000000000..d1f23f1d84d7052c3fc69f06a79bb0235c5ca57c --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_dB.m" @@ -0,0 +1,6 @@ +function dB = bdsp_calc_dB(FFTPwr,lowerFreq,upperFreq,freqSeq,dBref) + indices = freqSeq >= lowerFreq & freqSeq <= upperFreq; + Pwr_inFreq = FFTPwr(indices); + energy = 0.25*Pwr_inFreq(1)+0.25*Pwr_inFreq(end)+sum(Pwr_inFreq(2:end-1))/2; + dB = 10*log10(energy/dBref^2); +end diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octave.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octave.m" new file mode 100644 index 0000000000000000000000000000000000000000..06f63ffdafacc7ef82bbff9c762cf68af42e433d --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octave.m" @@ -0,0 +1,13 @@ +function dB = bdsp_calc_octave(FFTPwr,lowerFreq,upperFreq,freqSeq,dBref) + N = length(lowerFreq); + dB = zeros(1,N); + for i = 1:N + indices = freqSeq >= lowerFreq(i) & freqSeq <= upperFreq(i); + Pwr_inFreq = FFTPwr(indices); + if isempty(Pwr_inFreq)==1 + dB(i) = 0; + continue + end + energy = 0.25*Pwr_inFreq(1)+0.25*Pwr_inFreq(end)+sum(Pwr_inFreq(2:end-1))/2; + dB(i) = 10*log10(energy/dBref^2); + end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octaveFreq.m" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octaveFreq.m" new file mode 100644 index 0000000000000000000000000000000000000000..960a46455896cd97b4b4a8893247043877ee39dd --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/Dsp/bdsp_calc_octaveFreq.m" @@ -0,0 +1,33 @@ +function [lowerFreq,upperFreq] = bdsp_calc_octaveFreq(octaveType) + + % 计算中心频率为10~10000Hz的倍频程各频带上下限频率 + + % octaveType - 倍频程种类 + % 1 - 1/3 倍频程 (GB/T 3785.1-2023) + % 2 - 1/6 倍频程 (GB/T 3785.1-2023) + % 3 - 1/12 倍频程 (GB/T 3785.1-2023) + % 4 - 1 倍频程 + + bandWidth = [1/6,1/12,1/24,1/2]; + + N = [31,61,121,11]; + lowerFreq = zeros(1,N(octaveType)); + upperFreq = zeros(1,N(octaveType)); + + if octaveType < 4 + for i = 1:N(octaveType) + lowerFreq(i) = 10^(1+3/5*bandWidth(octaveType)*(i-1))/2^bandWidth(octaveType); + upperFreq(i) = 10^(1+3/5*bandWidth(octaveType)*(i-1))*2^bandWidth(octaveType); + end + else + if octaveType == 4 + Freq = [11,22,44,88,177,355,710,1420,2840,5680,11360,22720]; + lowerFreq = Freq(1:end-1); + upperFreq = Freq(2:end); + else + error("Invalid octaveType"); + + end + end + +end \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/bdsp_filter.c" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/bdsp_filter.c" new file mode 100644 index 0000000000000000000000000000000000000000..efc0aaab57d7eb50b45a0b7fe3fc3d18d543bb4a --- /dev/null +++ "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/bdsp_filter.c" @@ -0,0 +1,398 @@ +#include +#include +#include +#include + +#define PI 3.14159265358979323846 + +// 复数结构体定义 +typedef struct +{ + double real; // 复数的实部 + double imag; // 复数的虚部 +} Complex; + +// 创建复数 +Complex c_Complex(double real, double imag) +{ + Complex z; + z.real = real; + z.imag = imag; + return z; +} + +// 复数加法 +Complex c_add(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real + z2.real; + answer.imag = z1.imag + z2.imag; + return answer; +} + +// 复数减法 +Complex c_sub(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real - z2.real; + answer.imag = z1.imag - z2.imag; + return answer; +} + +// 复数乘法 +Complex c_Mul(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real * z2.real - z1.imag * z2.imag; + answer.imag = z1.real * z2.imag + z1.imag * z2.real; + return answer; +} + +// 复数除法 +Complex c_Div(Complex z1, Complex z2) +{ + Complex answer; + double denominator = z2.real * z2.real + z2.imag * z2.imag; + answer.real = (z1.real * z2.real + z1.imag * z2.imag) / denominator; + answer.imag = (z1.imag * z2.real - z1.real * z2.imag) / denominator; + return answer; +} + +// 计算二项式系数 +void calc_bcof(int n, double *bcof) +{ + int m; + // 计算二项式系数 C(n,k) + bcof[0] = 1; + bcof[1] = n; + m = n / 2; + for (int i = 2; i <= m; ++i) + { + bcof[i] = (n - i + 1) * bcof[i - 1] / i; + bcof[n - i] = bcof[i]; // 利用对称性 + } + bcof[n - 1] = n; + bcof[n] = 1; +} + +// 二项式乘法运算 +void binomial_mult(int n, Complex *p, double *result) +{ + Complex *a = (Complex *)calloc(n + 1, sizeof(Complex)); + + // 初始化系数 + a[0] = c_Complex(1, 0); + a[1] = c_sub(c_Complex(0, 0), p[0]); + + // 计算多项式乘积 + for (int i = 1; i < n; i++) + { + for (int j = i + 1; j > 0; j--) + { + a[j] = c_sub(a[j], c_Mul(a[j - 1], p[i])); + } + } + + // 提取实部作为结果 + for (int i = 0; i < n + 1; i++) + { + result[i] = a[i].real; + } + + free(a); +} + +// 三项式乘法运算 +void trinominal_mult(int n, Complex *p, Complex *q, double *result) +{ + Complex *a = (Complex *)calloc(2 * n + 1, sizeof(Complex)); + + a[0] = c_Complex(1, 0); + a[1] = p[0]; + a[2] = q[0]; + for (int i = 1; i < n; i++) + { + for (int j = 2 * i + 2; j > 1; j--) + { + a[j] = c_add(a[j], c_Mul(a[j - 1], p[i])); + a[j] = c_add(a[j], c_Mul(a[j - 2], q[i])); + } + a[1] = c_add(a[1], p[i]); + } + for (int i = 0; i < 2 * n + 1; i++) + { + result[i] = a[i].real; + } + free(a); +} + +// 低通滤波器设计 +void calc_low(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + Complex Omegap = c_Complex(tan(PI * w[0] / 2), 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + // 双线性变换 + p[i] = c_Div(c_add(c_Complex(1, 0), c_Mul(Omegap, poles)), + c_sub(c_Complex(1, 0), c_Mul(Omegap, poles))); + temp = c_Div(Omegap, c_sub(c_Complex(1, 0), c_Mul(Omegap, poles))); + sf = c_Mul(sf, temp); + } + + // 计算最终的滤波器系数 + binomial_mult(order, p, a); + calc_bcof(order, b); + for (int i = 0; i < order + 1; i++) + { + b[i] = b[i] * sf.real; + } + + free(p); +} + +// 高通滤波器设计 +void calc_high(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + Complex Omegap = c_Complex(tan(PI * w[1] / 2), 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + // 高通变换 + p[i] = c_Div(c_add(poles, Omegap), c_sub(poles, Omegap)); + sf = c_Div(sf, c_sub(Omegap, poles)); + } + + // 计算最终的滤波器系数 + binomial_mult(order, p, a); + calc_bcof(order, b); + for (int i = 0; i < order + 1; i++) + { + if (i % 2 == 1) + { + b[i] = -b[i]; + } + b[i] = b[i] * sf.real; + } + + free(p); +} + +// 带通滤波器设计 +void calc_bandpass(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + double Omega1 = tan(PI * w[0] / 2); + double Omega3 = tan(PI * w[1] / 2); + double c = Omega1 * Omega3; + Complex d = c_Complex(Omega3 - Omega1, 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + Complex *q = (Complex *)calloc(order + 1, sizeof(Complex)); + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + p[i] = c_Div(c_Complex(2 * c - 2, 0), c_sub(c_Complex(1 + c, 0), c_Mul(poles, d))); + q[i] = c_Div(c_add(c_Complex(c + 1, 0), c_Mul(poles, d)), c_sub(c_Complex(c + 1, 0), c_Mul(poles, d))); + temp = c_Div(d, c_sub(c_Complex(1 + c, 0), c_Mul(poles, d))); + sf = c_Mul(sf, temp); + } + trinominal_mult(order, p, q, a); + calc_bcof(order, b); + for (int i = 2 * order; i > 1; i = i - 2) + { + if ((i / 2) % 2 == 1) + { + b[i] = -b[i / 2] * sf.real; + } + else + { + b[i] = b[i / 2] * sf.real; + } + b[i - 1] = 0.0; + } + b[0] = b[0] * sf.real; + free(p); + free(q); +} + +// 带阻滤波器设计 +void calc_stop(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + double Omega1 = tan(PI * w[0] / 2); + double Omega3 = tan(PI * w[1] / 2); + double c = Omega1 * Omega3; + Complex d = c_Complex(Omega3 - Omega1, 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(2 * order + 1, sizeof(Complex)); + Complex *q = (Complex *)calloc(2 * order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + Complex tempF; + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + temp = c_sub(d, c_Mul(poles, c_Complex(1 + c, 0))); + tempF = c_sub(c_sub(c_Complex(0, 0), d), c_Mul(poles, c_Complex(1 + c, 0))); + p[i] = c_Div(c_Mul(c_Complex(2 - 2 * c, 0), poles), temp); + q[i] = c_Div(tempF, temp); + sf = c_Mul(sf, temp); + } + + // 计算最终的滤波器系数 + trinominal_mult(order, p, q, a); + tempF = c_Div(c_Complex(2 * c - 2, 0), c_Complex(1 + c, 0)); + for (int i = 0; i < order; i++) + { + p[i] = tempF; + q[i] = c_Complex(1, 0); + sf = c_Div(sf, c_Complex(c + 1, 0)); + } + trinominal_mult(order, p, q, b); + for (int i = 0; i < 2 * order + 1; i++) + { + b[i] = b[i] / sf.real; + } + free(p); + free(q); +} + +void bdsp_filter(int coeffLength, double *b, double *a, double *originSample, double *result, int dataLength) +{ + result[0] = 0; + for (int i = 1; i < dataLength; i++) + { + result[i] = 0; + for (int j = 0; j < coeffLength && (i - j) >= 0; j++) + { + result[i] += b[j] * originSample[i - j]; + } + for (int j = 1; j < coeffLength && (i - j) >= 0; j++) + { + result[i] -= a[j] * result[i - j]; + } + } +} + +// mode = 1,high; mode = 2, low;mode = 3,bandpass;mode = 4,stop +// 传进来的系数长度:带阻带通为2*order+1,高通低通为order+1,为order+1 +void bdsp_butterCoeff(int order, double *a, double *b, double w[2], int mode) +{ + switch (mode) + { + case 1: + calc_high(order, a, b, w); + break; + case 2: + calc_low(order, a, b, w); + break; + case 3: + calc_bandpass(order, a, b, w); + break; + case 4: + calc_stop(order, a, b, w); + break; + } +} + +// 示例 +int main() +{ + int order = 4; // 滤波器阶数 + int mode = 3; // 滤波器类型,1为高通,2为低通,3为带通, 4为带阻 + int coeffLength = 2 * order + 1; // 低通和高通为order+1,带阻和带通为2*order+1 + double *a = (double *)calloc(coeffLength, sizeof(double)); + double *b = (double *)calloc(coeffLength, sizeof(double)); + + // 设置截止频率(归一化频率,范围0-1) + double w[2] = {0.3, 0.4}; + + // 计算滤波器系数 + bdsp_butterCoeff(order, a, b, w, mode); + + // 打开文件以保存滤波器系数 + FILE *coeff_file = fopen("filter_coefficients.txt", "w"); + if (coeff_file == NULL) + { + printf("Error opening coefficient file!\n"); + return 1; + } + + // 写入滤波器系数 + fprintf(coeff_file, "分母系数 a[n]:\n"); + for (int i = 0; i <= 2 * order; i++) + { + fprintf(coeff_file, "a[%d] = %.10f\n", i, a[i]); + } + fprintf(coeff_file, "\n分子系数 b[n]:\n"); + for (int i = 0; i <= 2 * order; i++) + { + fprintf(coeff_file, "b[%d] = %.10f\n", i, b[i]); + } + fclose(coeff_file); + + // 示例:处理一些数据 + int dataLength = 1000; + double *input = (double *)malloc(dataLength * sizeof(double)); + double *output = (double *)malloc(dataLength * sizeof(double)); + + // 生成测试信号(例如:正弦波) + for (int i = 0; i < dataLength; i++) + { + input[i] = sin(2 * PI * 0.1 * (i + 1)) + sin(2 * PI * 0.6 * (i + 1)); + } + + // 进行滤波 + + bdsp_filter(coeffLength, b, a, input, output, dataLength); + + // 打开文件以保存滤波后的信号 + FILE *signal_file = fopen("filtered_signal.txt", "w"); + if (signal_file == NULL) + { + printf("Error opening signal file!\n"); + return 1; + } + + // 写入原始信号和滤波后的信号 + fprintf(signal_file, "Sample\tInput\tOutput\n"); + for (int i = 0; i < dataLength; i++) + { + fprintf(signal_file, "%d\t%.10f\t%.10f\n", i, input[i], output[i]); + } + fclose(signal_file); + + // 清理资源 + // freeFilter(filter); + free(input); + free(output); + free(a); + free(b); + + printf("Filter coefficients have been saved to 'filter_coefficients.txt'\n"); + printf("Filtered signal has been saved to 'filtered_signal.txt'\n"); + + return 0; +} \ No newline at end of file diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/~$\345\207\275\346\225\260\345\220\215.xlsx" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/~$\345\207\275\346\225\260\345\220\215.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..7580356f57163278a09cadb16f3a949036c9621c Binary files /dev/null and "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/~$\345\207\275\346\225\260\345\220\215.xlsx" differ diff --git "a/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/\345\207\275\346\225\260\345\220\215.xlsx" "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/\345\207\275\346\225\260\345\220\215.xlsx" new file mode 100644 index 0000000000000000000000000000000000000000..715302d18ec3e7ff1f6cccb4c1a4e3b849603aa5 Binary files /dev/null and "b/250118 \347\256\227\346\263\225\345\272\223\351\207\215\346\236\204/\345\207\275\346\225\260\345\220\215.xlsx" differ diff --git a/documents/img/image-20250112230050485.png b/documents/img/image-20250112230050485.png new file mode 100644 index 0000000000000000000000000000000000000000..61ae200e6028fe36a41cf17683f020d83e016ba4 Binary files /dev/null and b/documents/img/image-20250112230050485.png differ diff --git a/documents/img/image-20250119120055229.png b/documents/img/image-20250119120055229.png new file mode 100644 index 0000000000000000000000000000000000000000..b964dc9359db9d33655fb45f2d040071a081f2c3 Binary files /dev/null and b/documents/img/image-20250119120055229.png differ diff --git "a/documents/img/\346\227\266\345\237\237\347\211\271\345\276\201.png" "b/documents/img/\346\227\266\345\237\237\347\211\271\345\276\201.png" new file mode 100644 index 0000000000000000000000000000000000000000..08d3bad93e0abdc7bc2e47281ef6a367766ed2c2 Binary files /dev/null and "b/documents/img/\346\227\266\345\237\237\347\211\271\345\276\201.png" differ diff --git "a/documents/img/\346\234\211\347\272\277\344\274\240\346\204\237\345\231\250\347\256\227\346\263\225.png" "b/documents/img/\346\234\211\347\272\277\344\274\240\346\204\237\345\231\250\347\256\227\346\263\225.png" new file mode 100644 index 0000000000000000000000000000000000000000..184d64f3748ddfdb903d5f14d9364148d67b67d4 Binary files /dev/null and "b/documents/img/\346\234\211\347\272\277\344\274\240\346\204\237\345\231\250\347\256\227\346\263\225.png" differ diff --git "a/documents/img/\347\256\227\346\263\225\346\241\206\346\236\266.png" "b/documents/img/\347\256\227\346\263\225\346\241\206\346\236\266.png" new file mode 100644 index 0000000000000000000000000000000000000000..41f4c781385727d659134a5e6106aa8633f71996 Binary files /dev/null and "b/documents/img/\347\256\227\346\263\225\346\241\206\346\236\266.png" differ diff --git "a/documents/img/\351\242\221\345\237\237\347\211\271\345\276\201.png" "b/documents/img/\351\242\221\345\237\237\347\211\271\345\276\201.png" new file mode 100644 index 0000000000000000000000000000000000000000..eb1532ba82be031427dbc7c21244b5075354c5a5 Binary files /dev/null and "b/documents/img/\351\242\221\345\237\237\347\211\271\345\276\201.png" differ diff --git "a/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.html" "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.html" new file mode 100644 index 0000000000000000000000000000000000000000..557adf1db2a347a1caaacad6670ca7078b067d40 --- /dev/null +++ "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.html" @@ -0,0 +1,941 @@ + + + + + +算法设计文档 + +
+

算法库设计文档

序号修订日期修订说明修订人员修订软件版本
12025-01-13初次编制郭政彤、候嫣茹、童宇翔V0.1
     
     

算法库设计概述

原有软件与算法框架存在问题

  1. 配置耦合严重

    原有软件采集配置、存储配置、算法配置统一存储在一个配置文件中,软件中将所有配置读取为一个结构体后在多处整体使用,实际里面有很多对算法无用的参数,同时容易导致算法配置参数读取、更新出现问题。

  2. 算法更新困难,可扩展性差

    项目需求需要对算法进行更新时,需要嵌入式开发人员与算法设计人员对传入参数、算法调用方式进行反复沟通,同时算法库内部函数设计耦合严重,算法更新扩展困难。

  3. 算法库版本管理不当

    未针对不同硬件平台、不同项目应用进行良好的算法库版本管理,频发算法版本使用错误导致花费大量精力排查问题。

更新算法库组成框架

更新后算法库主要由定制库、中间库、基础库组成,各层级算法库所设计内容及功能如下所示

  • 定制库:主要依据项目需求所设计信号流程图完成定制算法的实现,通过调用中间库中函数接口进行算法功能模块的组合。在定制库中进行算法配置的初始化读取,无需应用软件反复确认算法配置是否传输正确。

  • 中间库:主要针对各种信号类型形成通用的算法功能函数,通过调用基础库中基本计算算法实现,作为定制库到基础库的过渡,实现中间参数的分解转译,降低算法的耦合性。

  • 基础库:主要包含时域特征计算、频域特征计算、时域滤波等基本计算接口。

    算法库组成

软件流程

函数、结构体、变量命名规范

函数:前缀名+功能名称,示例:

  • 中间库mdsp_calc_time_eigen_data()

  • 基础库bdsp_calc_max()

结构体:示例:

变量:timeEigenData;

定制库对外接口(应用程序调用)

函数接口

dsp_process()

Brief:通用通道数据算法调用接口

Parameters:

  • datainput-通道采集原始数据输入,单位为mV电压

  • size-数据长度

  • channelconfig-通道属性配置,包含采样信号类型、采样率等属性

  • dspconfig-算法计算过程中涉及参数配置,包含特征频率、分析上下限等

  • dspoutput-算法输出结果,分为谱线数据及特征数据

Returns:

  • 返回错误码,0为计算成功

 


dsp_get_version()

Brief:输出软件版本信息

Parameters:

  • version-版本号字符串

 


dsp_get_config()

Brief:格式化输出算法配置信息

 


dsp_calc_intensity()

Brief:多通道数据合成计算烈度值

 

定制库内部实现

结构体定义

DspConfig

 

DspChannelProperty

通道属性定义

 

DspChannelRestoreCoefficient

信号还原结构体

DspProcessingConfig

算法计算参数配置

 

void *signalProcessConfig

不同信号特殊配置

 

DspOutput

算法输出结果

DspSinspecData

谱线数据

DspTimeEigenData

时域特征

DspFreqEigenData

频域特征

 

运行错误代码

 

中间库函数接口

时域特征依赖关系

频域特征依赖

+ + \ No newline at end of file diff --git "a/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.md" "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..00c5fa883ae7bfba54ae2c3bc35fe1cd03c9be18 --- /dev/null +++ "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.md" @@ -0,0 +1,364 @@ +# 算法库设计文档 + +| 序号 | 修订日期 | 修订说明 | 修订人员 | 修订软件版本 | +| ---- | ---------- | -------- | ---------------------- | ------------ | +| 1 | 2025-01-13 | 初次编制 | 郭政彤、候嫣茹、童宇翔 | V0.1 | +| 2 | 2025-01-19 | 修订 | 郭政彤、童宇翔 | V0.2 | +| | | | | | + +# 算法库设计概述 + +## 原有软件与算法框架存在问题 + +1. **配置耦合严重** + + 原有软件采集配置、存储配置、算法配置统一存储在一个配置文件中,软件中将所有配置读取为一个结构体后在多处整体使用,实际里面有很多对算法无用的参数,同时容易导致算法配置参数读取、更新出现问题。 + +2. **算法更新困难,可扩展性差** + + 项目需求需要对算法进行更新时,需要嵌入式开发人员与算法设计人员对传入参数、算法调用方式进行反复沟通,同时算法库内部函数设计耦合严重,算法更新扩展困难。 + +3. **算法库版本管理不当** + + 未针对不同硬件平台、不同项目无针对项目的算法库版本管理,应用程序开发人员频繁算法版本使用错误导致在现场花费大量精力排查问题。 + +## 新算法库组成框架 + +新算法库主要由定制库、中间库、基础库组成,各层级算法库所设计内容及功能如下所示 + +- 定制库:针对不同项目需求,依据项目所需信号及信号特征值、统计量等设计项目算法计算流程树。对外仅有一个算法函数接口(完全包含整个项目算法计算流程树),定制库算法内部实现通过调用中间库中函数接口进行算法功能模块的组合。在定制库中进行算法配置的初始化读取,无需应用软件反复确认算法配置是否传输正确,算法开发人员可直接与项目需求对接。 + +- 中间库:主要针对各种信号类型形成通用的算法功能函数,通过调用基础库中基本计算算法实现,作为定制库到基础库的过渡,实现中间参数的分解转译,降低算法的耦合性。另外中间库会将一些调用频繁的基础库封装成一个中间层函数,方便不同计算树的多次调用,减少重复开发的时间浪费。 + +- 基础库:由各基础计算函数(每种特征量、统计量计算为一基础计算函数)组成,包含时域特征计算、频域特征计算、时域滤波等基本计算接口,该库中各函数接口仅包含所需配置参数。 + + ![算法库组成](./img/算法框架.png) + +# 软件流程 + +每个定制化项目,根据用户所需特征值进行特征值计算配置,定制化一个接口函数。定制接口函数输入值为某一种信号的时间序列及算法配置项,算法优先根据信号类型将其分配所属计算流程树,并根据特征值计算配置简化不必要的计算步骤及重复计算步骤。整体软件架构还提供算法库版本查询、算法配置参数查询及算法结果查询接口,该一系列查询接口可使整套算法完全独立运行,应用开发人员仅需进行一系列查询即可获取计算结果,不再需要单独配置算法,单独适应算法输出结构体等,简化应用程序开发流程。 + + + + + +# 函数、结构体、变量命名规范 + +函数:前缀名+功能名称,示例: + +- 中间库mdsp_calc_time_eigen_data() +- 基础库bdsp_calc_max() + +结构体:示例: + +```c +typedef struct DspTimeEigenData{ + +}DspTimeEigenData; +``` + +变量:timeEigenData; + +# 定制库对外接口(应用程序调用) + +## 函数接口 + +### dsp_process() + +**Brief:通用通道数据算法调用接口** + +**Parameters:** + +- datainput-通道采集原始数据输入,单位为mV电压 + +- size-数据长度 +- ~~channelconfig-通道属性配置,包含采样信号类型、采样率等属性~~ + +- ~~dspconfig-算法计算过程中涉及参数配置,包含特征频率、分析上下限等~~ +- dspoutput-算法输出结果,分为谱线数据及特征数据 + +**Returns:** + +- 返回错误码,0为计算成功 + +```c +int dsp_process(const float *dataInput,\ + uint32_t size, \ + struct libDspOutput *dspOutput) +``` + + + +--- + +### dsp_get_version() + +**Brief:输出软件版本信息** + +**Parameters:** + +- version-版本号字符串 + +```c +void dsp_get_version(char *version) +``` + + + +--- + +### dsp_get_config() + +**Brief:格式化输出算法配置信息** + +```C +void dsp_get_config(void) +``` + + + +--- + +### dsp_calc_intensity() + +**Brief:多通道数据合成计算烈度值** + +```c +int dsp_calc_intensity(float *axis_x, float *axis_y, float *axis_z) +``` + + + +# 定制库内部实现 + +## 结构体定义 + +### DspConfig + +```c +struct DspConfig{ + struct ChannelProperty channelProperty; + struct ChannelRestoreCoefficient restoreCoeff; + struct DspProcessingConfig dspProcessingConfig; + void *signalProcessConfig; // 信号类型特有配置 + uint32_t dataEnableflags[10]; // 算法使能位表 +} +``` + + + +### DspChannelProperty + +**通道属性定义** + +```c +struct DspChannelProperty { + uint32_t sampleMode; // 采样模式,0-等时间采样,1-等角度采样 + uint32_t signalType; // 信号类型,0-振动信号,1-噪声信号,2-缓变信号,3-转速信号,4-…… +} +``` + + + +### DspChannelRestoreCoefficient + +**信号还原结构体** + +```c +struct ChannelRestoreCoefficient { + float adjustCoefficient; // 校正系数 + float offsetValue; // 偏置值 + float sensitivity; // 灵敏度值 +} +``` + + + +### DspProcessingConfig + +**算法计算参数配置** + +```c +struct DspProcessingConfig{ + uint32_t sensorAxis; // 传感器安装方向,0-x向,1-y向,2-z向 + uint32_t sampleRate; // 采样率 + float analyzeLowerFreq; // 分析下限频率 + float analyzeUpperFreq; // 分析上限频率 + struct DspFilterConfig FilterConfig;// 滤波配置 + uint32_t windowType; // 窗函数类型 + uint32_t octaveType; // 倍频程类型 + uint32_t weightingType; // 计权类型 + uint32_t timeIntergralTimes; // 时域积分次数 + uint32_t FreqIntergralTimes; // 频域积分次数 + uint32_t averageType; // 频谱平均类型,0-无平均,1-线性平均,2-指数平均,3-峰值保持 + uint32_t averageTimes; // 平均次数 + float rpm; // 转频/基频 + uint32_t featureNumber; // 预留特征个数 + float *featureFreqs; // 预留特征频率 + struct DspFindPeakConfig findPeakConfig; // 寻峰算法配置 +} + +struct DspFilterConfig{ + uint32_t filterType; // 滤波类型 + uint32_t filterOrder; // 滤波阶数 + float filterLowerFreq; // 滤波下限截止频率 + float filterUpperFreq; // 滤波上限截止频率 +} + +struct DspFindPeakConfig{ + uint32_t peakNumbers; // 寻峰个数 + float minPeakHeight; // 设定峰值最小高度 + uint32_t minPeakDistance; // 设定两峰值最小间隔 +} + +// 预留多个分析频段配置 +struct DspFrequencyChoice{ + float analyzeLowerFreq; // 分析下限频率 + float analyzeUpperFreq; // 分析上限频率 +} +``` + + + +### void *signalProcessConfig + +**不同信号特殊配置** + +```c +/* 信号特殊配置 */ +struct DspDistanceProcessConfig{ + float axisTpXGap[LIBVibrationDSP_CHANNEL_MAX/2]; //轴承座X方向双侧间隙 + float axisTpYGap[LIBVibrationDSP_CHANNEL_MAX/2]; //轴承座y方向双侧间隙 + float initialXCorrection[LIBVibrationDSP_CHANNEL_MAX/2];//X轴初始位置修正 + float initialYCorrection[LIBVibrationDSP_CHANNEL_MAX/2];//Y轴初始位置修正 + float seatXOffset[LIBVibrationDSP_CHANNEL_MAX/2]; //轴承座横向偏移 + float seatYElevation[LIBVibrationDSP_CHANNEL_MAX/2]; //轴承座纵向标高 +} +``` + + + +### DspOutput + +**算法输出结果** + +- struct [DspSinspecData *](#DspSinspecData)-时频域谱线数据 +- struct [DspTimeEigenData *](#DspTimeEigenData)-时域特征数据 +- struct [DspFreqEigenData *](#DspFreqEigenData)-频域特征数据 + +```c +struct DspOutput +{ + struct DspSinspecData *SinspecData; + struct DspTimeEigenData *timeEigenData; + struct DspFreqEigenData *FreqEigenData; +} +``` + +### DspSinspecData + +**谱线数据** + +```c +struct libDspSinspecData +{ + /* 通用 */ + float *rawtimeData; // 原始数据 + float *dspFFTAmp; // FFT频谱 + float *dspFFTAmpDB; // FFT频谱,单位:dB + float *dspFFTPha; // FFT相位谱 + float *dspFFTPower; // 功率谱 + float *dspCeps; // 倒谱 + /* 振动 */ + float *velocityFFTAmp; // 速度谱 + float *distanceFFTAmp; // 速度谱 +} +``` + +### DspTimeEigenData + +**时域特征** + +```c +struct DspTimeEigenData{ + /* 通用特征 */ + float timeEigen_PPV; + float timeEigen_P; + float timeEigen_Max; + float timeEigen_Min; + float timeEigen_AVE; + float timeEigen_ABS_AVE; + float timeEigen_ABS_AVE_AMP; + float timeEigen_RMS; + float timeEigen_Sr_AMP; + float timeEigen_Variance; + float timeEigen_SD; + float timeEigen_P_Factor; + float timeEigen_Pulse_Factor; + float timeEigen_Margin_Factor; + float timeEigen_Curve_Factor; + float timeEigen_Kurtosis_Factor; + float timeEigen_Kurtosis; + float timeEigen_Skewness_Factor; + float timeEigen_Skewness; + /* 位移特有特征 */ + // DisTimeEigen *disTimeEigen; + /* 加速度特有特征 */ + // accTimeEigen_t *accTimeEigen; + /* 噪声特有特征 */ + // soundTimeEigen_t *soundTimeEigen; + /* 磁场特有特征…… */ + /* 应力应变特有特征 */ +}; +``` + +### DspFreqEigenData + +**频域特征** + +```c +struct DspFreqEigenData{ + float freq_BasePha; + float freq_TotaldB; + float freq_HighdB; + float freq_LowdB; + float *octavedB; + float freq_VelocityRMS; + float freq_AverageVoltage; + float freq_DisplacementRMS; + float freq_FC; + float freq_Msf; + float freq_Rmsf; + float freq_Vf; + float Freq_rpm; + struct FreqAmpPairs *featureFreqAmpPair; // 自定义个倍频值 + struct FreqAmpPairs *peakFreqAmpPair; // 频谱自定义个峰值 +}; +``` + + + +## 运行错误代码 + +```c +const int32_t T_SUCCESS = 0; // 算法运行成功 +const int32_t E_DATAEMPTY = 1; +const int32_t E_PARAMINVALID = 2; // 算法参数无效 +const int32_t E_UNKOWN = -1; +``` + + + +# 中间库函数接口 + +```c +int LibDspTimeFilter() +int LibDspGetOctave(float *spectrum, uint32_t octaveType, float *octave) +int LibDspGetTimeEigenData(float *data_afterfilter, uint32_t size,) +int LibDspGetFreqDB() +int LibDspTimeIntergration() +``` + +![时域特征依赖关系](./img/时域特征.png) + +![频域特征依赖](./img/频域特征.png) diff --git "a/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.pdf" "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.pdf" new file mode 100644 index 0000000000000000000000000000000000000000..117c36ba62ebfec7eeecd5e36e63ca2c64f5bae8 Binary files /dev/null and "b/documents/\347\256\227\346\263\225\350\256\276\350\256\241\346\226\207\346\241\243.pdf" differ diff --git a/dsp/bdsp_ConvertFFTAmp.c b/dsp/bdsp_ConvertFFTAmp.c new file mode 100644 index 0000000000000000000000000000000000000000..a85c7363ef644dd2f7ab06125098470b4a82cd86 --- /dev/null +++ b/dsp/bdsp_ConvertFFTAmp.c @@ -0,0 +1,50 @@ +#include +#include + +/* DSP配置结构体定义 */ +typedef struct { + int windowType; // 窗函数类型 + // 可以添加其他DSP相关配置参数 +} DspConfig; + +/** + * 将FFT频谱转换为幅值谱 + * @param Spectrum 输入的FFT频谱数组指针 + * @param FFTAmp 输出的幅值谱数组指针 + * @param length 数组长度 + * @param config DSP配置结构体指针 + * @return 0:成功, -1:参数错误 + * + * 窗函数类型: + * 1: 汉宁窗 + * 2: 海明窗 + * 3: 黑曼窗 + * 4: 平顶窗 + * 5: 凯塞窗 + * 其他: 不加窗 + */ +int bdsp_ConvertFFTAmp(float *Spectrum, float *FFTAmp, int length, const DspConfig *config) { + // 参数检查 + if (Spectrum == NULL || FFTAmp == NULL || config == NULL || length <= 0) { + return -1; + } + + // 定义转换系数数组 + const float convertCoeff[] = {2.0f, 1.8516f, 2.3810f, 4.18f, 2.49f, 1.0f}; + + // 确定使用的窗函数系数 + int windowIndex; + if (config->windowType >= 1 && config->windowType <= 5) { + windowIndex = config->windowType - 1; + } else { + windowIndex = 6; // 不加窗 + } + + // 计算幅值谱 + float coeff = convertCoeff[windowIndex]; + for (int i = 0; i < length; i++) { + FFTAmp[i] = Spectrum[i] * coeff; + } + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_ConvertFFTAmpDB.c b/dsp/bdsp_ConvertFFTAmpDB.c new file mode 100644 index 0000000000000000000000000000000000000000..c01b0ee256c61865f89ccbadc7f35d6a27f6118e --- /dev/null +++ b/dsp/bdsp_ConvertFFTAmpDB.c @@ -0,0 +1,21 @@ +/** + * 将FFT幅值转换为分贝值 + * + * @param FFTAmp 输入参数,FFT幅值数组指针 + * @param dBref 输入参数,分贝转换的参考值 + * @param FFTAmpDB 输出参数,转换后的分贝值数组指针 + * @param len 输入参数,数组长度 + * + * @return 返回0表示正常执行完成 + */ +int bdsp_ConvertFFTAmpDB(float *FFTAmp, float dBref, float *FFTAmpDB, int len) +{ + int i; + for(i = 0; i < len; i++) { + /* 将FFT幅值转换为分贝值 + * 计算公式: dB = 20 * log10(幅值/参考值) + */ + FFTAmpDB[i] = 20.0f * log10f(FFTAmp[i] / dBref); + } + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_ConvertFFTPwr.c b/dsp/bdsp_ConvertFFTPwr.c new file mode 100644 index 0000000000000000000000000000000000000000..e7e6776211fc9e6c0f218bd60950bdfdf273fbf4 --- /dev/null +++ b/dsp/bdsp_ConvertFFTPwr.c @@ -0,0 +1,53 @@ +#include +/** + * FFT频谱转换为功率谱函数 + * + * @param Spectrum 输入FFT频谱数组 + * @param FFTPwr 输出功率谱数组 + * @param sampleLength 采样点数/FFT点数 + * @param sampleRate 采样率(Hz) + * @param windowType 窗函数类型: + * 1: 汉宁窗 + * 2: 海明窗 + * 3: 黑曼窗 + * 4: 平顶窗 + * 5: 凯塞窗 + * 其他: 不加窗 + * + * @return 0: 成功 + * -1: 无效的输入参数 + */ +int bdsp_ConvertFFTPwr(const float *Spectrum, float *FFTPwr, + int sampleLength, float sampleRate, int windowType) +{ + + // 参数有效性检查 + if (Spectrum == NULL || FFTPwr == NULL || + sampleLength <= 0 || sampleRate <= 0) + { + return -1; + } + + // 定义各种窗函数的转换系数 + const float convertCoeff[] = {1.6338f, 1.5863f, 1.8119f, 2.26f, 1.85f, 1.0f}; + + // 选择对应的转换系数 + float coeff; + if (windowType >= 1 && windowType <= 5) + { + coeff = convertCoeff[windowType - 1]; + } + else + { + coeff = convertCoeff[5]; // 不加窗系数 + } + + // 计算功率谱 + + for (int i = 0; i < sampleLength; i++) + { + FFTPwr[i] = pow(Spectrum[i] * coeff, 2.0); + } + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_DataRestore.c b/dsp/bdsp_DataRestore.c new file mode 100644 index 0000000000000000000000000000000000000000..e964c36be433da37a0305c55d8f0b27f81e252b5 --- /dev/null +++ b/dsp/bdsp_DataRestore.c @@ -0,0 +1,42 @@ +#include + +/** + * @brief 通道数据恢复的系数结构体 + * 用于存储数据恢复计算所需的各项系数 + */ +struct ChannelRestoreCoefficient +{ + float adjustCoefficient; // 调整系数:用于线性校准,对原始数据进行比例调整 + float offsetValue; // 偏移值:修正零点偏移,进行加减运算调整 + float sensitivity; // 灵敏度:传感器的响应系数,将数字量转换为物理量 +}; + +/** + * @brief 数据恢复计算函数 + * 根据输入数据和恢复系数计算实际物理量 + * 计算公式: outputData = adjustCoefficient * inputdata / sensitivity + offsetValue + * + * @param inputdata 输入数据指针,指向原始采集数据 + * @param coefficient 系数结构体指针,包含计算所需的各项系数 + * @param outputData 输出数据指针,用于存储计算后的结果 + * + * @return int 返回执行状态 + * 0: 执行成功 + * -1: 参数错误(空指针) + */ +int bdsp_DataRestore(float *inputdata, struct ChannelRestoreCoefficient *coefficient, float *outputData) +{ + // 参数有效性检查 + if (inputdata == NULL || coefficient == NULL || outputData == NULL) + { + return -1; // 错误处理:任一指针为空时返回错误码 + } + + // 数据恢复计算 + // 1. 原始数据乘以调整系数 + // 2. 除以灵敏度得到物理量 + // 3. 加上偏移值进行零点修正 + *outputData = coefficient->adjustCoefficient * (*inputdata) / coefficient->sensitivity + coefficient->offsetValue; + + return 0; // 计算成功返回0 +} \ No newline at end of file diff --git a/dsp/bdsp_FFTWeighting.c b/dsp/bdsp_FFTWeighting.c new file mode 100644 index 0000000000000000000000000000000000000000..9cdb5e9f0dcd3bee6dfe0a7cb7fac323911152fe --- /dev/null +++ b/dsp/bdsp_FFTWeighting.c @@ -0,0 +1,77 @@ +#include +#include + +/** + * FFT频域计权 + * @param FFTPwr 输入/输出的功率谱数组指针 + * @param length 数组长度(采样点数) + * @param weightingType 计权类型(1:A计权, 2:B计权, 3:C计权) + * @param sampleRate 采样率 + * @return 0:成功, -1:参数错误, -2:不支持的计权类型 + */ +int bdsp_FFTWeighting(float *FFTPwr, int length, uint32_t weightingType, float sampleRate) { + // 参数检查 + if (FFTPwr == NULL || length <= 0 || sampleRate <= 0.0f) { + return -1; + } + + if (weightingType < 1 || weightingType > 3) { + return -2; + } + + // 计算实际处理的长度(一半频谱) + int halfLength = (length + 1) / 2; + + // 定义特征频率 + const float f[] = {20.6f, 107.7f, 737.9f, 12194.0f}; + const float f4_2 = f[3] * f[3]; // f(4)^2,预计算常用值 + const float log10_2 = log10(2.0f); // 预计算log10(2) + + // 计算每个频点的频率和权重 + float deltaF = sampleRate / (float)length; // 频率分辨率 + + for (int i = 0; i < halfLength; i++) { + float freq = i * deltaF; + if (freq < 1.0f) freq = 1.0f; // 避免0频率导致的计算问题 + + float freq2 = freq * freq; + float w = 0.0f; + + // 根据不同计权类型计算权重 + switch (weightingType) { + case 1: // A计权 + w = 2.0f + 20.0f * log10_2 * log10( + (f4_2 * freq2 * freq2) / + ((freq2 + f[0] * f[0]) * + sqrt((freq2 + f[1] * f[1])) * + sqrt((freq2 + f[2] * f[2])) * + (freq2 + f4_2))); + break; + + case 2: // B计权 + w = 0.17f + 20.0f * log10_2 * log10( + (f4_2 * freq2 * freq2) / + ((freq2 + f[0] * f[0]) * + sqrt((freq2 + 158.5f * 158.5f)) * + (freq2 + f4_2))); + break; + + case 3: // C计权 + w = 0.062f + 20.0f * log10_2 * log10( + (f4_2 * freq2 * freq2) / + ((freq2 + f[0] * f[0]) * + (freq2 + f4_2))); + break; + } + + // 应用权重 + FFTPwr[i] *= powf(10.0f, w / 10.0f); + } + + // 对称复制到后半部分(如果length是偶数) + for (int i = halfLength; i < length; i++) { + FFTPwr[i] = FFTPwr[length - i - 1]; + } + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_FindPeaks.c b/dsp/bdsp_FindPeaks.c new file mode 100644 index 0000000000000000000000000000000000000000..005d8a76c2fc7794de0555981dde024f4cdd9948 --- /dev/null +++ b/dsp/bdsp_FindPeaks.c @@ -0,0 +1,82 @@ +#include +/** + * FFT幅值谱寻峰函数 + * + * @param FFTAmp 输入FFT幅值谱数组 + * @param sampleLength 采样点数/FFT点数 + * @param sampleRate 采样率(Hz) + * @param minPeakHeight 最小峰值高度阈值 + * @param minPeakDistance 相邻峰值最小间隔点数 + * @param peakFreqs 输出峰值频率数组 + * @param peakAmps 输出峰值幅度数组 + * @param numPeaks 输出检测到的峰值个数 + * @param maxPeaks peakFreqs和peakAmps数组的最大长度 + * + * @return 0: 成功 + * -1: 无效的输入参数 + * -2: 检测到的峰值数超过maxPeaks + */ +int bdsp_FindPeaks(const float *FFTAmp, int sampleLength, float sampleRate, + float minPeakHeight, int minPeakDistance, + float *peakFreqs, float *peakAmps, + int *numPeaks, int maxPeaks) { + + int i; + int isPeak; + int peakCount = 0; + float freq; + + // 参数有效性检查 + if(FFTAmp == NULL || peakFreqs == NULL || + peakAmps == NULL || numPeaks == NULL || + sampleLength <= 0 || sampleRate <= 0 || + minPeakDistance < 0 || maxPeaks <= 0) { + return -1; + } + + // 只处理到奈奎斯特频率(采样率/2) + int maxIndex = sampleLength/2; + + // 确保最小间隔不超过数据长度 + if(minPeakDistance >= maxIndex) { + minPeakDistance = maxIndex - 1; + } + + // 遍历FFT幅值谱寻找峰值 + for(i = minPeakDistance; i < maxIndex-minPeakDistance; i++) { + isPeak = 1; + + // 检查是否超过最小峰值高度 + if(FFTAmp[i] < minPeakHeight) { + continue; + } + + // 在最小间隔范围内检查是否为局部最大值 + for(int j = i-minPeakDistance; j <= i+minPeakDistance; j++) { + if(j == i) continue; + if(FFTAmp[j] >= FFTAmp[i]) { + isPeak = 0; + break; + } + } + + // 如果是峰值点,记录频率和幅度 + if(isPeak) { + // 检查是否超出输出数组容量 + if(peakCount >= maxPeaks) { + return -2; + } + + // 计算频率值 + freq = (float)i * sampleRate / sampleLength; + + // 存储峰值频率和幅度 + peakFreqs[peakCount] = freq; + peakAmps[peakCount] = FFTAmp[i]; + peakCount++; + } + } + + *numPeaks = peakCount; + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_TimeFilter.c b/dsp/bdsp_TimeFilter.c new file mode 100644 index 0000000000000000000000000000000000000000..1c2cf507764af3c8d8eaf1d8ad4d7b95be7cd186 --- /dev/null +++ b/dsp/bdsp_TimeFilter.c @@ -0,0 +1,123 @@ + +#include +#include + +#define M_PI 3.14159265358979323846 + +/* 巴特沃斯带通滤波器系数计算函数 */ +void butterBandpassCoeff(int order, double wn1, double wn2, double* b) { + // 计算中心频率和带宽 + double w0 = sqrt(wn1 * wn2); // 中心频率 + double bw = wn2 - wn1; // 带宽 + + // 计算系数 + double alpha = sin(w0) * sinh(log(2) / 2 * bw * w0 / sin(w0)); + + // 对于不同阶数的滤波器,计算系数 + switch(order) { + case 1: + b[0] = alpha / (1 + alpha); + b[1] = 0; + b[2] = -alpha / (1 + alpha); + break; + + case 2: + b[0] = alpha / (1 + alpha); + b[1] = 0; + b[2] = -2 * alpha / (1 + alpha); + b[3] = alpha / (1 + alpha); + break; + + case 3: + b[0] = alpha * (1 + alpha) / ((1 + alpha) * (1 + alpha)); + b[1] = 2 * alpha / ((1 + alpha) * (1 + alpha)); + b[2] = alpha * (1 - alpha) / ((1 + alpha) * (1 + alpha)); + b[3] = -2 * alpha * (1 - alpha) / ((1 + alpha) * (1 + alpha)); + b[4] = -alpha / ((1 + alpha) * (1 + alpha)); + break; + + case 4: + b[0] = alpha / pow(1 + alpha, 2); + b[1] = 4 * alpha / pow(1 + alpha, 2); + b[2] = 6 * alpha / pow(1 + alpha, 2); + b[3] = 4 * alpha / pow(1 + alpha, 2); + b[4] = alpha / pow(1 + alpha, 2); + break; + + default: + // 对于更高阶数,使用简化的系数计算 + for(int i = 0; i <= order; i++) { + double theta = M_PI * i / order; + b[i] = 2 * sin(theta) * alpha / (1 + alpha); + } + } + + // 归一化系数 + double sum = 0; + for(int i = 0; i <= order; i++) { + sum += fabs(b[i]); + } + for(int i = 0; i <= order; i++) { + b[i] /= sum; + } +} + +/* + * 带通滤波函数 + * 输入参数: + * double *inputdata - 输入数据数组 + * int dataLength - 输入数据长度 + * double sampleRate - 采样率(Hz) + * int filterOrder - 滤波器阶数 + * double filterLowerFreq - 滤波器下截止频率(Hz) + * double filterUpperFreq - 滤波器上截止频率(Hz) + * 输出参数: + * int - 执行状态(0表示成功,-1表示失败) + * double *filteredData - 滤波后的数据(通过指针返回) + */ +int bdsp_TimeFilter(double *inputdata, int dataLength, double sampleRate, + int filterOrder, double filterLowerFreq, double filterUpperFreq, + double *filteredData) { + + int i, j; + double wn1, wn2; + double *b = NULL; + int coeffLength; + + /* 检查输入参数 */ + if(inputdata == NULL || filteredData == NULL || dataLength <= 0 || + sampleRate <= 0 || filterOrder < 1 || + filterLowerFreq >= filterUpperFreq || + filterUpperFreq >= sampleRate/2) { + return -1; + } + + /* 计算归一化截止频率 */ + wn1 = 2.0 * filterLowerFreq / sampleRate; + wn2 = 2.0 * filterUpperFreq / sampleRate; + + /* 计算滤波器系数长度 */ + coeffLength = filterOrder + 1; + + /* 分配滤波器系数内存 */ + b = (double*)malloc(coeffLength * sizeof(double)); + if(b == NULL) { + return -1; + } + + /* 计算巴特沃斯带通滤波器系数 */ + butterBandpassCoeff(filterOrder, wn1, wn2, b); + + /* 执行滤波 */ + for(i = 0; i < dataLength; i++) { + filteredData[i] = 0; + for(j = 0; j < coeffLength && j <= i; j++) { + filteredData[i] += b[j] * inputdata[i-j]; + } + } + + /* 释放内存 */ + free(b); + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_Windowed.c b/dsp/bdsp_Windowed.c new file mode 100644 index 0000000000000000000000000000000000000000..3e7b12505146ba15610e43bbbde2be6230c9b717 --- /dev/null +++ b/dsp/bdsp_Windowed.c @@ -0,0 +1,175 @@ +#include +#include + +#define M_PI 3.14159265358979323846 + +// 窗函数相关声明 +void window_hamming(double* arr, int taps); //海明窗 +void window_hanning(double* arr, int taps); //汉宁窗 +void window_blackman(double* arr, int taps); //布莱克曼窗 +void window_Flattop(double* arr, int taps); //平顶窗 +void kaiser(double* arr, double beta, int n); //凯泽窗 +int n_jiecheng(int n); +double I0(int n, double x); + +/* +* 窗函数参数结构体 +* winAmpCompesationPara: 幅值补偿系数 +* winEnergyCompesationPara: 能量补偿系数 +* 说明: +* 1. 幅值补偿系数用于补偿窗函数对信号幅值的衰减 +* 2. 能量补偿系数用于补偿窗函数对信号能量的衰减 +*/ +struct windowParameter { + double winAmpCompesationPara; // 幅值补偿系数 + double winEnergyCompesationPara; // 能量补偿系数 +}; + +/* +* 函数名: bdsp_Windowed +* 功能: 对输入数据加窗处理 +* 参数: +* tempBuffer: 输入数据缓存 +* type: 窗类型选择 +* 1 - 汉宁窗(Hanning) +* 2 - 海明窗(Hamming) +* 3 - 布莱克曼窗(Blackman) +* 4 - 平顶窗(Flattop) +* 5 - 凯泽窗(Kaiser) +* 其他值 - 不加窗 +* windowPara: 窗函数参数结构体 +* dataLength: 数据长度 +* 返回值: +* 0 - 成功 +* -1 - 失败 +*/ +int bdsp_Windowed(double *tempBuffer, int type, struct windowParameter *windowPara, int dataLength) +{ + if(tempBuffer == NULL || windowPara == NULL || dataLength <= 0) + { + return -1; + } + + enum windowType{hanning=1, hamming, blackman, flattop, Kaiser}; + + //根据type选择窗函数类型 + switch(type) + { + case hanning: + window_hanning(tempBuffer,dataLength); + windowPara->winAmpCompesationPara = 2; + windowPara->winEnergyCompesationPara = 1.6338; + break; + + case hamming: + window_hamming(tempBuffer,dataLength); + windowPara->winAmpCompesationPara = 1.8516; + windowPara->winEnergyCompesationPara = 1.5863; + break; + + case blackman: + window_blackman(tempBuffer,dataLength); + windowPara->winAmpCompesationPara = 2.3810; + windowPara->winEnergyCompesationPara = 1.8119; + break; + + case flattop: + window_Flattop(tempBuffer,dataLength); + windowPara->winAmpCompesationPara = 4.18; + windowPara->winEnergyCompesationPara = 2.26; + break; + + case Kaiser: + kaiser(tempBuffer, 2.5, dataLength); + windowPara->winAmpCompesationPara = 2.49; + windowPara->winEnergyCompesationPara = 1.85; + break; + + default: + for(int tempi = 0; tempi < dataLength; tempi++) + { + tempBuffer[tempi] = 1.0; + } + windowPara->winAmpCompesationPara = 1; + windowPara->winEnergyCompesationPara = 1; + } + return 0; +} + +//汉宁窗 +void window_hanning(double *arr, int taps) +{ + int i; + for (i = 1; i <= taps; i++) + { + arr[i-1] = 0.5*(1-cos((2*(double)M_PI*i)/(taps+1))); + } +} + +//海明窗 +void window_hamming(double *arr, int taps) +{ + int i; + double alpha = 0.54; + double beta = 0.46; + for (i = 0; i < taps; i++) { + arr[i] = alpha - beta*cos(2.0*M_PI*i/(taps-1)); + } +} + +//布莱克曼窗 +void window_blackman(double *arr, int taps) +{ + double alpha0 = 0.42; + double alpha1 = 0.5; + double alpha2 = 0.08; + int i = 0; + for (i = 0; i < taps; i++) { + arr[i] = alpha0 - alpha1*cos(2.0*M_PI*i/(taps-1)) + + alpha2*cos(4.0*M_PI*i/(taps-1)); + } +} + +//平顶窗 +void window_Flattop(double *arr, int taps) +{ + double a0 = 0.21557895; + double a1 = 0.41663158; + double a2 = 0.277263158; + double a3 = 0.083578947; + double a4 = 0.006947368; + int n = 0; + for (n = 0; n < taps; n++) { + arr[n] = a0 - a1*cos(2*M_PI*n/(taps-1)) + a2*cos(4*M_PI*n/(taps-1)) + - a3*cos(6*M_PI*n/(taps-1)) + a4*cos(8*M_PI*n/(taps-1)); + } +} + +//凯泽窗 +void kaiser(double *arr, double beta, int n) { + int j; + for (j = 0; j < n; j++) { + arr[j] = I0(20, beta*sqrt(1-pow(2*j/(n-1)-1, 2))) / I0(20, beta); + } +} + +//求n阶乘 +int n_jiecheng(int n) { + int sum = 1; + int i = 1; + for (i = 1; i <= n; i++) + { + sum *= i; + } + return sum; +} + +//零阶第一类修正贝塞尔函数,一般n取20 +double I0(int n, double x) { + double I0_x = 1.0; + int i = 1; + for (i = 1; i <= n; i++) { + I0_x += pow((pow(x / 2, i) / n_jiecheng(i)), 2); + } + return I0_x; +} diff --git a/dsp/bdsp_calc_EigenFreqAmp.c b/dsp/bdsp_calc_EigenFreqAmp.c new file mode 100644 index 0000000000000000000000000000000000000000..fae462c089d83d4d2130ceacdbdf69d241772f2d --- /dev/null +++ b/dsp/bdsp_calc_EigenFreqAmp.c @@ -0,0 +1,81 @@ +#include + +struct FreqAmpPairs { + float* freq; // 频率数组 + float* amp; // 对应的幅值数组 + int length; // 数组长度 +}; + +/** + * @brief 计算特征频率对应的幅值 + * @param FFTAmp FFT幅值谱数组 + * @param eigenFreq 特征频率数组 + * @param N 特征频率数组长度 + * @param sampleLength 采样点数/FFT点数 + * @param sampleRate 采样率 + * @param bandWidth 带宽,在特征频率上下bandWidth/2范围内寻找最大幅值 + * @param FreqAmpPair 特征频率-幅值对结构体 + * @return 0:成功, -1:内存分配失败 + */ +int bdsp_calc_EigenFreqAmp(float* FFTAmp, float* eigenFreq, int N, + int sampleLength, float sampleRate, float bandWidth, + struct FreqAmpPairs* FreqAmpPair) { + + // 分配频率数组内存,用于存储FFT频率点 + float* freq = (float*)malloc((sampleLength/2 + 1) * sizeof(float)); + if(freq == NULL) return -1; + + // 计算FFT频率点数组: 0, df, 2df, ..., fs/2 + // 其中df = sampleRate/sampleLength + int freqLength = 0; + for(float f = 0; f <= sampleRate/2; f += sampleRate/sampleLength) { + freq[freqLength++] = f; + if(freqLength > sampleLength/2) break; + } + + // 为输出结构体分配内存 + FreqAmpPair->freq = (float*)malloc(N * sizeof(float)); + FreqAmpPair->amp = (float*)malloc(N * sizeof(float)); + if(FreqAmpPair->freq == NULL || FreqAmpPair->amp == NULL) { + free(freq); + return -1; + } + FreqAmpPair->length = N; + + // 拷贝特征频率数组到输出结构体 + memcpy(FreqAmpPair->freq, eigenFreq, N * sizeof(float)); + + // 对每个特征频率寻找对应的最大幅值 + for(int i = 0; i < N; i++) { + // 如果特征频率超出奈奎斯特频率,置幅值为0 + if(eigenFreq[i] > freq[freqLength-1]) { + FreqAmpPair->amp[i] = 0; + continue; + } + + // 计算查找范围的上下限 + float lowerBound = eigenFreq[i] - bandWidth / 2; + float upperBound = eigenFreq[i] + bandWidth / 2; + + // 在频带范围内查找最大幅值 + float maxAmp = 0; + int found = 0; + + for(int j = 0; j < freqLength; j++) { + if(freq[j] >= lowerBound && freq[j] <= upperBound) { + if(!found || FFTAmp[j] > maxAmp) { + maxAmp = FFTAmp[j]; + found = 1; + } + } + } + + // 如果在带宽范围内找到了频率点,则记录最大幅值 + // 否则记录为0 + FreqAmpPair->amp[i] = found ? maxAmp : 0; + } + + // 释放临时内存 + free(freq); + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_calc_FreqBandValue.c b/dsp/bdsp_calc_FreqBandValue.c new file mode 100644 index 0000000000000000000000000000000000000000..13b86c79c5b874b409b9387ff98537d02db01efb --- /dev/null +++ b/dsp/bdsp_calc_FreqBandValue.c @@ -0,0 +1,42 @@ +#include + +/** + * 计算指定频率范围内的频谱总值 + * @param spectrumData 输入的频谱数据数组指针(如速度谱) + * @param length 数组长度(采样点数) + * @param sampleRate 采样率 + * @param freqLow 频段下限频率 + * @param freqHigh 频段上限频率 + * @param bandValue 输出的频段总值指针 + * @return 0:成功, -1:参数错误 + */ +int bdsp_calc_FreqBandValue(const float *spectrumData, int length, float sampleRate, + float freqLow, float freqHigh, float *bandValue) { + // 参数检查 + if (spectrumData == NULL || bandValue == NULL || + length <= 0 || sampleRate <= 0.0f || + freqLow < 0.0f || freqHigh <= freqLow || + freqHigh > sampleRate/2.0f) { + return -1; + } + + // 计算频率分辨率 + float deltaF = sampleRate / (float)length; + + // 计算频率范围对应的数组索引 + int lowIndex = (int)(freqLow / deltaF + 0.5f); // 四舍五入 + int highIndex = (int)(freqHigh / deltaF + 0.5f); // 四舍五入 + + // 确保索引在有效范围内 + if (lowIndex < 0) lowIndex = 0; + if (highIndex >= length/2) highIndex = length/2 - 1; + + // 计算指定频段内的总值(能量累加后转dB) + float sum = 0.0f; + for (int i = lowIndex; i <= highIndex; i++) { + sum += spectrumData[i]; + } + + *bandValue = 10.0f * log10f(sum); + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_calc_FreqEigenValue.c b/dsp/bdsp_calc_FreqEigenValue.c new file mode 100644 index 0000000000000000000000000000000000000000..b43540ee6756c52b9708495cada9b4592db7ffeb --- /dev/null +++ b/dsp/bdsp_calc_FreqEigenValue.c @@ -0,0 +1,131 @@ +// Structure definition for frequency domain eigenvalues +struct bdsp_FreqEigenValue { + float Ampavg; // 幅值均值 + float fc; // 重心频率 + float Msf; // 均方频率 + float Ampvar; // 幅值方差 + float Ampstd; // 幅值标准差 + float Ampskewness; // 幅值偏度 + float Ampkurtosis; // 幅值峭度 + float rmsf; // 均方根频率 + float vf; // 频率方差 + float rvf; // 频率标准差 + float sigma; // 频率分布系数 + float fskewness; // 频率偏度 + float fkurtosis; // 频率峭度 + float sqrtf; // 平方根比率 +}; + +int bdsp_calc_FreqEigenValue(float *FFTAmp, float *FFTPwr, int sampleLength, float sampleRate, struct bdsp_FreqEigenValue *TimeEigen) { + if (!FFTAmp || !FFTPwr || !TimeEigen || sampleLength <= 0) { + return -1; // Error checking + } + + // Calculate frequency array + int N = sampleLength / 2; + float *freq = (float *)malloc(N * sizeof(float)); + if (!freq) { + return -2; // Memory allocation failed + } + + for (int i = 0; i < N; i++) { + freq[i] = i * (sampleRate / sampleLength); + } + + // Calculate sum of FFTPwr for normalization + float sum_FFTPwr = 0.0f; + for (int i = 0; i < N; i++) { + sum_FFTPwr += FFTPwr[i]; + } + + // 01 幅值均值 + TimeEigen->Ampavg = 0.0f; + for (int i = 0; i < N; i++) { + TimeEigen->Ampavg += FFTAmp[i]; + } + TimeEigen->Ampavg /= N; + + // 02 重心频率 + TimeEigen->fc = 0.0f; + for (int i = 0; i < N; i++) { + TimeEigen->fc += freq[i] * FFTPwr[i]; + } + TimeEigen->fc /= sum_FFTPwr; + + // 03 均方频率 + TimeEigen->Msf = 0.0f; + for (int i = 0; i < N; i++) { + TimeEigen->Msf += freq[i] * freq[i] * FFTPwr[i]; + } + TimeEigen->Msf /= sum_FFTPwr; + + // 04 幅值方差 + TimeEigen->Ampvar = 0.0f; + for (int i = 0; i < N; i++) { + float diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampvar += diff * diff; + } + TimeEigen->Ampvar /= N; + + // 05 幅值标准差 + TimeEigen->Ampstd = sqrt(TimeEigen->Ampvar); + + // 06 幅值偏度 + TimeEigen->Ampskewness = 0.0f; + for (int i = 0; i < N; i++) { + float diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampskewness += diff * diff * diff; + } + TimeEigen->Ampskewness /= (N * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd); + + // 07 幅值峭度 + TimeEigen->Ampkurtosis = 0.0f; + for (int i = 0; i < N; i++) { + float diff = FFTAmp[i] - TimeEigen->Ampavg; + TimeEigen->Ampkurtosis += diff * diff * diff * diff; + } + TimeEigen->Ampkurtosis /= (N * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd * TimeEigen->Ampstd); + + // 08 均方根频率 + TimeEigen->rmsf = sqrt(TimeEigen->Msf); + + // 09 频率方差 + TimeEigen->vf = 0.0f; + for (int i = 0; i < N; i++) { + float diff = freq[i] - TimeEigen->fc; + TimeEigen->vf += diff * diff * FFTPwr[i]; + } + TimeEigen->vf /= sum_FFTPwr; + + // 10 频率标准差 + TimeEigen->rvf = sqrt(TimeEigen->vf); + + // 11-13 频率分布系数、频率偏度、频率峭度 + TimeEigen->sigma = 0.0f; + for (int i = 0; i < N; i++) { + float diff = freq[i] - TimeEigen->fc; + TimeEigen->sigma += diff * diff * FFTPwr[i]; + } + TimeEigen->sigma /= N; + + TimeEigen->fskewness = 0.0f; + TimeEigen->fkurtosis = 0.0f; + for (int i = 0; i < N; i++) { + float diff = freq[i] - TimeEigen->fc; + TimeEigen->fskewness += diff * diff * diff * FFTPwr[i]; + TimeEigen->fkurtosis += diff * diff * diff * diff * FFTPwr[i]; + } + TimeEigen->fskewness /= (N * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma); + TimeEigen->fkurtosis /= (N * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma * TimeEigen->sigma); + + // 14 平方根比率 + TimeEigen->sqrtf = 0.0f; + for (int i = 0; i < N; i++) { + float diff = freq[i] - TimeEigen->fc; + TimeEigen->sqrtf += sqrt(fabs(diff)) * FFTPwr[i]; + } + TimeEigen->sqrtf /= (sqrt(TimeEigen->sigma) * N); + + free(freq); + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_calc_FreqIntegration.c b/dsp/bdsp_calc_FreqIntegration.c new file mode 100644 index 0000000000000000000000000000000000000000..e339f895b5c50c02aeb7dae015c8fa77cc2a5b4a --- /dev/null +++ b/dsp/bdsp_calc_FreqIntegration.c @@ -0,0 +1,38 @@ +#include + +#define M_PI 3.14159265358979323846 + +/** + * FFT频域积分 - 将加速度谱转换为速度谱 + * @param FFTPwr 输入的功率谱数组指针 + * @param integratedData 输出的速度谱数组指针 + * @param length 数组长度(采样点数) + * @param sampleRate 采样率 + * @return 0:成功, -1:参数错误 + */ +int bdsp_calc_FreqIntegration(float *FFTPwr, float *integratedData, int length, float sampleRate) { + // 参数检查 + if (FFTPwr == NULL || integratedData == NULL || + length <= 0 || sampleRate <= 0.0f) { + return -1; + } + + // 计算频率分辨率 + float deltaF = sampleRate / (float)length; + + // 对每个频点进行积分计算 + for (int i = 0; i < length/2; i++) { + float freq = i * deltaF; + if (freq < 1.0f) freq = 1.0f; // 避免除零 + + // 一次积分(速度谱): |H(f)| = 1/(2πf) + integratedData[i] = FFTPwr[i] / (2.0f * M_PI * freq); + } + + // 对称复制到后半部分(如果length是偶数) + for (int i = length/2; i < length; i++) { + integratedData[i] = integratedData[length - i - 1]; + } + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_calc_Spectrum.c b/dsp/bdsp_calc_Spectrum.c new file mode 100644 index 0000000000000000000000000000000000000000..4ef25c56e1b14703d72a90a67732ef32c812a261 --- /dev/null +++ b/dsp/bdsp_calc_Spectrum.c @@ -0,0 +1,197 @@ +#include +#include +#include +#include + +#define M_PI 3.14159265358979323846 + +/* +* FFT相关结构体定义 +*/ +typedef struct { + double real; + double imag; +} Complex; + +/* +* 函数名: bdsp_calc_Spectrum +* 功能: 对已加窗的输入数据进行FFT变换并输出频谱 +* 参数: +* input: 输入数据数组(已加窗) +* N: 数据长度(必须是2的整数次幂) +* spectrum: 输出频谱数组(长度为N/2) +* 返回值: +* 0 - 成功 +* -1 - 失败 +*/ +int bdsp_calc_Spectrum(const double *input, int N, float *spectrum) +{ + // 参数检查 + if(input == NULL || spectrum == NULL || N <= 0) + return -1; + + // 检查N是否为2的整数次幂 + int temp = N; + while(temp > 1) { + if(temp % 2 != 0) + return -1; + temp /= 2; + } + + // 分配内存 + Complex *fftData = (Complex *)malloc(N * sizeof(Complex)); + if(fftData == NULL) { + return -1; + } + + // 将数据转换为复数形式 + for(int i = 0; i < N; i++) { + fftData[i].real = input[i]; + fftData[i].imag = 0.0; + } + + // 执行FFT + fft(fftData, N); + + // 计算频谱(幅值谱) + for(int i = 0; i < N/2; i++) { + double magnitude = sqrt(fftData[i].real * fftData[i].real + + fftData[i].imag * fftData[i].imag); + // 将双精度结果转换为单精度输出 + spectrum[i] = (float)(magnitude * 2.0 / N); // 2/N是FFT的幅值校正因子 + } + + // 释放内存 + free(fftData); + return 0; +} + +/* +* 位反转函数 +*/ +void bit_reverse(Complex *data, int N) { + int j = 0; + for(int i = 0; i < N - 1; i++) { + if(i < j) { + Complex temp = data[i]; + data[i] = data[j]; + data[j] = temp; + } + int k = N >> 1; + while(k <= j) { + j -= k; + k >>= 1; + } + j += k; + } +} + +/* +* FFT核心算法实现 +*/ +void fft(Complex *data, int N) { + bit_reverse(data, N); + + // 蝶形运算 + for(int step = 1; step < N; step <<= 1) { + double theta = M_PI / step; + Complex wp = {cos(theta), -sin(theta)}; + + for(int group = 0; group < N; group += (step << 1)) { + Complex w = {1.0, 0.0}; + + for(int k = 0; k < step; k++) { + Complex t = { + w.real * data[group + k + step].real - w.imag * data[group + k + step].imag, + w.real * data[group + k + step].imag + w.imag * data[group + k + step].real + }; + + data[group + k + step].real = data[group + k].real - t.real; + data[group + k + step].imag = data[group + k].imag - t.imag; + data[group + k].real += t.real; + data[group + k].imag += t.imag; + + // 更新旋转因子 + double temp = w.real; + w.real = w.real * wp.real - w.imag * wp.imag; + w.imag = temp * wp.imag + w.imag * wp.real; + } + } + } +} + +// 使用示例 + +/* +* 窗函数参数结构体 +* winAmpCompesationPara: 幅值补偿系数 +* winEnergyCompesationPara: 能量补偿系数 +* 说明: +* 1. 幅值补偿系数用于补偿窗函数对信号幅值的衰减 +* 2. 能量补偿系数用于补偿窗函数对信号能量的衰减 +*/ +struct windowParameter { + double winAmpCompesationPara; // 幅值补偿系数 + double winEnergyCompesationPara; // 能量补偿系数 +}; + +// 声明外部窗函数 +int bdsp_Windowed(double *tempBuffer, int type, struct windowParameter *windowPara, int dataLength); + +int main() { + const int N = 1024; // 必须是2的整数次幂 + double *input = (double *)malloc(N * sizeof(double)); + double *windowedData = (double *)malloc(N * sizeof(double)); + float *spectrum = (float *)malloc((N / 2) * sizeof(float)); + + if (input == NULL || windowedData == NULL || spectrum == NULL) { + printf("内存分配失败\n"); + free(input); + free(windowedData); + free(spectrum); + return -1; + } + + // 生成测试信号 + double f1 = 10.0; // 10Hz + double f2 = 50.0; // 50Hz + double fs = 1000.0; // 采样频率1000Hz + for(int i = 0; i < N; i++) { + double t = (double)i / fs; + input[i] = sin(2 * M_PI * f1 * t) + 0.5 * sin(2 * M_PI * f2 * t); + } + + // 复制数据用于加窗 + memcpy(windowedData, input, N * sizeof(double)); + + // 对数据进行加窗处理 + struct windowParameter winPara; + if(bdsp_Windowed(windowedData, 1, &winPara, N) != 0) { // 使用汉宁窗(type=1) + printf("加窗处理失败\n"); + free(input); + free(windowedData); + free(spectrum); + return -1; + } + + // 执行FFT + if(bdsp_calc_Spectrum(windowedData, N, spectrum) == 0) { + // 输出频谱结果 + printf("频谱结果(前10个点):\n"); + for(int i = 0; i < 10; i++) { + double freq = (double)i * fs / N; + // 应用窗函数的幅值补偿 + printf("频率:%.1f Hz, 幅值:%.6f\n", + freq, spectrum[i] * winPara.winAmpCompesationPara); + } + } else { + printf("FFT计算失败\n"); + } + + // 释放内存 + free(input); + free(windowedData); + free(spectrum); + + return 0; +} \ No newline at end of file diff --git a/dsp/bdsp_calc_TimeEigenValue.c b/dsp/bdsp_calc_TimeEigenValue.c new file mode 100644 index 0000000000000000000000000000000000000000..d6c66abe8eefdab54db3c857455c15431a8ed377 --- /dev/null +++ b/dsp/bdsp_calc_TimeEigenValue.c @@ -0,0 +1,186 @@ +#include +#include + +// 结构体来存储时域统计量 +struct timeEigen +{ + float Max; // 最大值 + float Min; // 最小值 + float Ave; // 平均值 + float AbsAve; // 均值绝对值 + float AbsAveAmp; // 绝对平均幅值 + float XFG; // 方根幅值 + float Rms; // 均方根 + float Std; // 标准差 + float Var; // 方差 + float Peak2Valley; // 峰峰值 + float Peakfactor; // 峰值因子 + float Pulsefactor; // 脉冲因子 + float Marginfactor; // 裕度因子 + float Wavefactor; // 波形因子 + float Skewness; // 偏度 + float Kurtosis; // 峭度 + float Skewnessfactor; // 偏度因子 + float Kurtosisfactor; // 峭度因子 +}; + +// 计算均方根 +float rms(float *x, int length) +{ + float sum = 0.0f; + for (int i = 0; i < length; i++) + { + sum += x[i] * x[i]; + } + return sqrt(sum / length); +} + +// 计算标准差 +float std_dev(float *x, int length) +{ + float mean = 0.0f; + for (int i = 0; i < length; i++) + { + mean += x[i]; + } + mean /= length; + + float sum = 0.0f; + for (int i = 0; i < length; i++) + { + sum += (x[i] - mean) * (x[i] - mean); + } + + return sqrt(sum / (length - 1)); // 使用无偏估计 +} + +// 计算偏度 +float skewness(float *x, int length) +{ + float mean = 0.0f; + for (int i = 0; i < length; i++) + { + mean += x[i]; + } + mean /= length; + + float m3 = 0.0f; + float m2 = 0.0f; + for (int i = 0; i < length; i++) + { + m3 += pow(x[i] - mean, 3); + m2 += pow(x[i] - mean, 2); + } + + m2 /= length; + m3 /= length; + + return m3 / pow(m2, 1.5f); // 偏度公式 +} + +// 计算峭度 +float kurtosis(float *x, int length) +{ + float mean = 0.0f; + for (int i = 0; i < length; i++) + { + mean += x[i]; + } + mean /= length; + + float m4 = 0.0f; + float m2 = 0.0f; + for (int i = 0; i < length; i++) + { + m4 += pow(x[i] - mean, 4); + m2 += pow(x[i] - mean, 2); + } + + m2 /= length; + m4 /= length; + + return m4 / (m2 * m2) - 3.0f; // 峭度公式 +} + +// 计算时域统计量 +struct timeEigen bdsp_calc_TimeEigenValue(float *inputdata, int length) +{ + struct timeEigen timeEigen; + + // 最大值 + timeEigen.Max = inputdata[0]; + timeEigen.Min = inputdata[0]; + float sum = 0.0f; + for (int i = 0; i < length; i++) + { + if (inputdata[i] > timeEigen.Max) + { + timeEigen.Max = inputdata[i]; + } + if (inputdata[i] < timeEigen.Min) + { + timeEigen.Min = inputdata[i]; + } + sum += inputdata[i]; + } + + // 平均值 + timeEigen.Ave = sum / length; + + // 均值绝对值 + timeEigen.AbsAve = fabs(timeEigen.Ave); + + // 绝对平均幅值 + sum = 0.0f; + for (int i = 0; i < length; i++) + { + sum += fabs(inputdata[i]); + } + timeEigen.AbsAveAmp = sum / length; + + // 方根幅值 + float root_sum = 0.0f; + for (int i = 0; i < length; i++) + { + root_sum += pow(fabs(inputdata[i]), 2); + } + timeEigen.XFG = sqrt(root_sum / length); + + // 均方根 + timeEigen.Rms = rms(inputdata, length); + + // 标准差 + timeEigen.Std = std_dev(inputdata, length); + + // 方差 + timeEigen.Var = timeEigen.Std * timeEigen.Std; + + // 峰峰值 + timeEigen.Peak2Valley = timeEigen.Max - timeEigen.Min; + + // 峰值因子 + timeEigen.Peakfactor = timeEigen.Max / timeEigen.Rms; + + // 脉冲因子 + timeEigen.Pulsefactor = timeEigen.Max / timeEigen.AbsAveAmp; + + // 裕度因子 + timeEigen.Marginfactor = timeEigen.Max / timeEigen.XFG; + + // 波形因子 + timeEigen.Wavefactor = timeEigen.Rms / timeEigen.AbsAveAmp; + + // 偏度因子 + timeEigen.Skewnessfactor = skewness(inputdata, length); + + // 峭度因子 + timeEigen.Kurtosisfactor = kurtosis(inputdata, length); + + // 偏度 + timeEigen.Skewness = timeEigen.Skewnessfactor * pow(timeEigen.Std, 3); + + // 峭度 + timeEigen.Kurtosis = timeEigen.Kurtosisfactor * pow(timeEigen.Std, 4); + + return timeEigen; +} diff --git a/dsp/bdsp_calc_TimeIntegration.c b/dsp/bdsp_calc_TimeIntegration.c new file mode 100644 index 0000000000000000000000000000000000000000..04f676ec90608da157971e1f76d485a16d845c15 --- /dev/null +++ b/dsp/bdsp_calc_TimeIntegration.c @@ -0,0 +1,30 @@ +#include + +/** + * 时域单次积分函数 + * @param inputData 输入数据数组指针 + * @param outputData 输出积分结果数组指针 + * @param dataLength 数据长度 + * @param sampleRate 采样率(Hz) + * @return 0:成功, -1:失败 + * 说明:使用梯形积分法计算时域积分 + */ +int bdsp_calc_TimeIntegration(const float* inputData, float* outputData, int dataLength, float sampleRate) { + // 参数检查 + if (inputData == NULL || outputData == NULL || dataLength <= 1 || sampleRate <= 0) { + return -1; + } + + // 计算采样时间间隔 + float interval = 1.0f / sampleRate; + + // 设置初始值为0 + outputData[0] = 0.0f; + + // 使用梯形法则计算积分值 + for (int i = 1; i < dataLength; i++) { + outputData[i] = outputData[i-1] + 0.5f * interval * (inputData[i-1] + inputData[i]); + } + + return 0; +} diff --git a/dsp/fft/dsp_common.h b/dsp/fft/dsp_common.h new file mode 100644 index 0000000000000000000000000000000000000000..84924263d0e78b8f0105e9dcefbb920e5965010d --- /dev/null +++ b/dsp/fft/dsp_common.h @@ -0,0 +1,17 @@ +#ifndef __DSP_COMMON_H__ +#define __DSP_COMMON_H__ +#include +#include +#include + +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; + +#define T_SUCCESS 0 +#define E_PARAMINVALID 1 +#define E_MEMORYFAULT 2 +#define E_EMPTYPOINT 3 + +#endif diff --git a/dsp/fft/dsp_fft.c b/dsp/fft/dsp_fft.c new file mode 100644 index 0000000000000000000000000000000000000000..bd283c2d140dcda480ff107910012083f113f570 --- /dev/null +++ b/dsp/fft/dsp_fft.c @@ -0,0 +1,91 @@ +#include "fft.h" +#include "win_function.h" +#include "dsp_common.h" +#include "dsp_fft.h" + +#define WIN_FUNC_NUM 8 // 支持的窗函数总数 +const float winRecovery[WIN_FUNC_NUM][2] = { + {1.000000f, 1.000000f}, // uniform √ + {2.000000f, 1.632993f}, // hann √ + {1.851865f, 1.586309f}, // hamming √ + {1.000000f, 1.000000f}, // force x + {1.000000f, 1.000000f}, // force exp x + {2.380972f, 1.811911f}, // blackman √ + {1.000000f, 1.000000f}, // kaiser x + {4.638709f, 2.388970f}, // flattop √ +}; + +static float *winFactor = NULL; +static float *fftReals = NULL; +static float *fftImags = NULL; +static float ampRecovery, powerRecovery = 0; + +/* -------------------------------------------------------------------------- */ +/* 接口函数 */ +/* -------------------------------------------------------------------------- */ + +int dsp_fft_init(uint32_t dataSize) +{ + uint32_t fftSize = dataSize / 2; + uint32_t wf = 1; // hann窗 + + winFactor = (float *)malloc(dataSize * sizeof(float)); + if (winFactor == NULL) + { + return E_MEMORYFAULT; + } + fftReals = (float *)malloc(dataSize * sizeof(float)); + if (fftReals == NULL) + { + return E_MEMORYFAULT; + } + fftImags = (float *)malloc(fftSize * sizeof(float)); + if (fftImags == NULL) + { + return E_MEMORYFAULT; + } + + get_window_factor(winFactor, dataSize, wf); + ampRecovery = winRecovery[wf][0]; + powerRecovery = winRecovery[wf][1]; + + return T_SUCCESS; +} + +int dsp_calc_fft(float *inputData, uint32_t dataSize, float *spectrum) +{ + int i; + int errCode; + uint32_t fftSize; + + if (winFactor == NULL || fftReals == NULL || fftImags == NULL) + { + return E_MEMORYFAULT; + } + + for (i = 0; i < dataSize; i++) + { + fftReals[i] = inputData[i] * winFactor[i]; + } + fft_execute_dft(fftReals, fftImags, dataSize); + + for (i = 0; i < fftSize; i++) + { + fftReals[i] = (fftReals[i] * fftReals[i] + fftImags[i] * fftImags[i]); + arm_sqrt_f32(fftReals[i], &fftReals[i]); + + fftReals[i] = fftReals[i] / fftSize / M_SQRT2; // 补偿前RMS + fftReals[i] = fftReals[i] * ampRecovery; // 加速度幅值RMS + } + + spectrum = fftReals; + + return T_SUCCESS; +} + +int dsp_fft_delete(void) +{ + free(fftImags); + free(fftReals); + free(winFactor); +} \ No newline at end of file diff --git a/dsp/fft/dsp_fft.h b/dsp/fft/dsp_fft.h new file mode 100644 index 0000000000000000000000000000000000000000..32d5e77c39000a9ff2e07a28d03dc02a021828aa --- /dev/null +++ b/dsp/fft/dsp_fft.h @@ -0,0 +1,8 @@ +#include "dsp_common.h" + +/* -------------------------------------------------------------------------- */ +/* 接口函数定义 */ +/* -------------------------------------------------------------------------- */ +int dsp_fft_init(uint32_t dataSize); +int dsp_calc_fft(float *inputData, uint32_t dataSize, float *spectrum); +int dsp_fft_delete(void); \ No newline at end of file diff --git a/dsp/fft/fft.c b/dsp/fft/fft.c new file mode 100644 index 0000000000000000000000000000000000000000..888d8e96180a5ce7026d5001a1fe743b99862ebc --- /dev/null +++ b/dsp/fft/fft.c @@ -0,0 +1,118 @@ +/********************************************************************* + * @File name: fft.c + * @Author: merry merry + * @Version: 1.0.0 + * @Date: 2023/10/30 + * @LastDate: 2023/10/30 + * @Description: + *********************************************************************/ +#include "fft.h" +#include "fft_tab.h" + +const int fft_table[FFT_N] = { + 16, 32, 64, 128, 256, 512, + 1024, 2048, 4096, 8192, + 16384, 32768, 65536, 131072}; + +/********************************************************************* +** 接口函数实现 +*********************************************************************/ +#ifndef static_fft_table +int calc_rotation_factor(uint32_t fft_number) +{ + int i = 0; + for (i = 0; i < FFT_N; i++) + if (fft_number == fft_table[i]) + break; + if (i >= FFT_N) + return -1; + + fft_number >>= 1; + for (i = 0; i < fft_number; i++) + { + sintab[i] = sinf(M_PI * i / fft_number); + costab[i] = cosf(M_PI * i / fft_number); + } + return 0; +} +#endif + +int fft_execute_dft(float *reals, float *imags, uint32_t fft_number) +{ + memset(imags, 0, fft_number * sizeof(float)); + float32_t TempReal1, TempImag1, TempReal2, TempImag2; + uint32_t k, i, j, z; + uint32_t Butterfly_NoPerColumn; /* 每级蝶形的蝶形组数 */ + uint32_t Butterfly_NoOfGroup; /* 蝶形组的第几组 */ + uint32_t Butterfly_NoPerGroup; /* 蝶形组的第几个蝶形 */ + uint32_t ButterflyIndex1, ButterflyIndex2, P, J; + uint32_t L; + uint32_t M; + + for (i = 0; i < FFT_N; i++) + { + if (fft_number == fft_table[i]) + { + M = i + 4; + break; + } + } + if (i >= FFT_N) + return -1; + z = fft_number / 2; /* 变址运算,即把自然顺序变成倒位序,采用雷德算法 */ + + for (i = 0, j = 0; i < fft_number - 1; i++) + { + /* 如果ij说明前面已经变换过了,不许再变化,注意这里一般是实数 有虚数部分 设置成结合体 */ + if (i < j) + { + TempReal1 = reals[j]; + reals[j] = reals[i]; + reals[i] = TempReal1; + } + k = z; /*求j的下一个倒位序 */ + + while (k <= j) /* 如果k<=j,表示j的最高位为1 */ + { + j = j - k; /* 把最高位变成0 */ + k = k / 2; /* k/2,比较次高位,依次类推,逐个比较,直到某个位为0,通过下面那句j=j+k使其变为1 */ + } + j = j + k; /* 求下一个反序号,如果是0,则把0改为1 */ + } + + /* 第L级蝶形(M)第Butterfly_NoOfGroup组(Butterfly_NoPerColumn)第J个蝶形(Butterfly_NoPerGroup)****** */ + /* 蝶形的组数以2的倍数递减Butterfly_NoPerColumn,每组中蝶形的个数以2的倍数递增Butterfly_NoPerGroup */ + /* 在计算蝶形时,每L列的蝶形组数,一共有M列,每组蝶形中蝶形的个数,蝶形的阶数(0,1,2.....M-1) */ + Butterfly_NoPerColumn = fft_number; + Butterfly_NoPerGroup = 1; + + for (L = 0; L < M; L++) + { + Butterfly_NoPerColumn >>= 1; /* 蝶形组数 假如N=8,则(4,2,1) */ + + /* 第L级蝶形 第Butterfly_NoOfGroup组 (0,1,....Butterfly_NoOfGroup-1)*/ + for (Butterfly_NoOfGroup = 0; Butterfly_NoOfGroup < Butterfly_NoPerColumn; Butterfly_NoOfGroup++) + { + for (J = 0; J < Butterfly_NoPerGroup; J++) /* 第 Butterfly_NoOfGroup 组中的第J个 */ + { /* 第 ButterflyIndex1 和第 ButterflyIndex2 个元素作蝶形运算,WNC */ + ButterflyIndex1 = ((Butterfly_NoOfGroup * Butterfly_NoPerGroup) << 1) + J; /* (0,2,4,6)(0,1,4,5)(0,1,2,3) */ + ButterflyIndex2 = ButterflyIndex1 + Butterfly_NoPerGroup; /* 两个要做蝶形运算的数相距Butterfly_NoPerGroup (ge=1,2,4) */ + P = J * Butterfly_NoPerColumn; /* 这里相当于P=J*2^(M-L),做了一个换算下标都是N (0,0,0,0)(0,2,0,2)(0,1,2,3) */ + + /* 计算和转换因子乘积 */ + TempReal2 = reals[ButterflyIndex2] * costab[P] + imags[ButterflyIndex2] * sintab[P]; + TempImag2 = imags[ButterflyIndex2] * costab[P] - reals[ButterflyIndex2] * sintab[P]; + TempReal1 = reals[ButterflyIndex1]; + TempImag1 = imags[ButterflyIndex1]; + + /* 蝶形运算 */ + reals[ButterflyIndex1] = TempReal1 + TempReal2; + imags[ButterflyIndex1] = TempImag1 + TempImag2; + reals[ButterflyIndex2] = TempReal1 - TempReal2; + imags[ButterflyIndex2] = TempImag1 - TempImag2; + } + } + Butterfly_NoPerGroup <<= 1; /* 一组中蝶形的个数(1,2,4) */ + } + return 0; +} diff --git a/dsp/fft/fft.h b/dsp/fft/fft.h new file mode 100644 index 0000000000000000000000000000000000000000..13d6ef19f3484ce235d03d47f3ba4e79758818ef --- /dev/null +++ b/dsp/fft/fft.h @@ -0,0 +1,45 @@ +/* + * @Descripttion: + * @version: + * @Author: ChristLP + * @Date: 2023-11-01 14:14:52 + * @LastEditors: christlp guomin001@126.com + * @LastEditTime: 2023-11-07 19:24:17 + */ + +#ifndef __FFT_H__ +#define __FFT_H__ + +#include "math.h" +#include "arm_math.h" +#include "dsp_common.h" + +#define FFT_N 14 + +#ifndef M_PI +#define M_PI (3.141592653589793238462643) +#endif + +/** + * 预生成rotation_factor,应写入外部flash,因系统进入standby会丢失ram数据 + */ + +/** + * @brief 计算旋转因子 + * @param fft_number 采样率索引值 131072,65536,32768,... + * @return 0:正常, -1:长度异常 + * @note 计算fft前,必须正常初始化 + */ +// int calc_rotation_factor(uint32_t fft_number); + +/** + * @brief fft执行函数 + * @param reals 输入变换前序列,输出变换后实部序列 + * @param imags 输出变换后虚部序列 + * @param fft_number 采样率索引值 131072,65536,32768,... + * @return 0:正常, -1:长度异常 + * @note 实部序列原地存放在输入序列数组上! + */ +int fft_execute_dft(float *reals, float *imags, uint32_t fft_number); + +#endif diff --git a/dsp/fft/fft_tab.h b/dsp/fft/fft_tab.h new file mode 100644 index 0000000000000000000000000000000000000000..36c1b6c5ac21808dd782df30d4a272ef20f40dbb --- /dev/null +++ b/dsp/fft/fft_tab.h @@ -0,0 +1,153 @@ +/* + * @Author: christlp + * @Date: 2023-11-07 16:43:30 + * @LastEditors: christlp guomin001@126.com + * @LastEditTime: 2023-11-07 18:14:24 + * @FilePath: \wireless-4ch-monitor\User\fft\fft_tab.h + * @Description: + */ +#ifndef __FFT_TAB_H__ +#define __FFT_TAB_H__ + +#define static_fft_table + +#ifdef static_fft_table +static const float sintab[2048] = { +0.00000000000f,0.00153398019f,0.00306795676f,0.00460192612f,0.00613588465f,0.00766982874f,0.00920375478f,0.01073765917f,0.01227153829f,0.01380538853f,0.01533920628f,0.01687298795f,0.01840672991f,0.01994042855f,0.02147408028f,0.02300768147f,0.02454122852f,0.02607471783f,0.02760814578f,0.02914150876f,0.03067480318f,0.03220802541f,0.03374117185f,0.03527423890f,0.03680722294f,0.03834012037f,0.03987292759f,0.04140564098f,0.04293825693f,0.04447077185f,0.04600318213f,0.04753548416f, +0.04906767433f,0.05059974904f,0.05213170468f,0.05366353765f,0.05519524435f,0.05672682117f,0.05825826450f,0.05978957075f,0.06132073630f,0.06285175756f,0.06438263093f,0.06591335280f,0.06744391956f,0.06897432763f,0.07050457339f,0.07203465325f,0.07356456360f,0.07509430085f,0.07662386139f,0.07815324163f,0.07968243797f,0.08121144681f,0.08274026455f,0.08426888759f,0.08579731234f,0.08732553521f,0.08885355258f,0.09038136088f,0.09190895650f,0.09343633585f,0.09496349533f,0.09649043136f, +0.09801714033f,0.09954361866f,0.10106986275f,0.10259586902f,0.10412163387f,0.10564715371f,0.10717242496f,0.10869744401f,0.11022220729f,0.11174671121f,0.11327095218f,0.11479492661f,0.11631863091f,0.11784206151f,0.11936521481f,0.12088808724f,0.12241067520f,0.12393297512f,0.12545498341f,0.12697669650f,0.12849811079f,0.13001922272f,0.13154002870f,0.13306052516f,0.13458070851f,0.13610057518f,0.13762012159f,0.13913934416f,0.14065823933f,0.14217680352f,0.14369503315f,0.14521292465f, +0.14673047446f,0.14824767899f,0.14976453468f,0.15128103796f,0.15279718526f,0.15431297301f,0.15582839765f,0.15734345562f,0.15885814333f,0.16037245724f,0.16188639378f,0.16339994938f,0.16491312049f,0.16642590354f,0.16793829497f,0.16945029123f,0.17096188876f,0.17247308400f,0.17398387339f,0.17549425338f,0.17700422041f,0.17851377094f,0.18002290141f,0.18153160826f,0.18303988796f,0.18454773694f,0.18605515166f,0.18756212858f,0.18906866415f,0.19057475482f,0.19208039705f,0.19358558730f, +0.19509032202f,0.19659459767f,0.19809841072f,0.19960175762f,0.20110463484f,0.20260703884f,0.20410896609f,0.20561041305f,0.20711137619f,0.20861185198f,0.21011183688f,0.21161132737f,0.21311031992f,0.21460881099f,0.21610679708f,0.21760427464f,0.21910124016f,0.22059769011f,0.22209362097f,0.22358902923f,0.22508391136f,0.22657826385f,0.22807208317f,0.22956536582f,0.23105810828f,0.23255030704f,0.23404195858f,0.23553305940f,0.23702360599f,0.23851359484f,0.24000302245f,0.24149188530f, +0.24298017990f,0.24446790275f,0.24595505034f,0.24744161917f,0.24892760575f,0.25041300657f,0.25189781815f,0.25338203700f,0.25486565960f,0.25634868249f,0.25783110216f,0.25931291513f,0.26079411792f,0.26227470702f,0.26375467897f,0.26523403029f,0.26671275747f,0.26819085706f,0.26966832557f,0.27114515953f,0.27262135545f,0.27409690987f,0.27557181931f,0.27704608031f,0.27851968939f,0.27999264308f,0.28146493793f,0.28293657046f,0.28440753721f,0.28587783473f,0.28734745954f,0.28881640821f, +0.29028467725f,0.29175226323f,0.29321916269f,0.29468537218f,0.29615088824f,0.29761570744f,0.29907982631f,0.30054324142f,0.30200594932f,0.30346794657f,0.30492922974f,0.30638979537f,0.30784964004f,0.30930876031f,0.31076715275f,0.31222481392f,0.31368174040f,0.31513792875f,0.31659337556f,0.31804807739f,0.31950203082f,0.32095523243f,0.32240767880f,0.32385936652f,0.32531029216f,0.32676045232f,0.32820984358f,0.32965846253f,0.33110630576f,0.33255336987f,0.33399965144f,0.33544514708f, +0.33688985339f,0.33833376697f,0.33977688441f,0.34121920232f,0.34266071731f,0.34410142599f,0.34554132496f,0.34698041085f,0.34841868025f,0.34985612979f,0.35129275609f,0.35272855576f,0.35416352542f,0.35559766170f,0.35703096123f,0.35846342063f,0.35989503653f,0.36132580557f,0.36275572437f,0.36418478957f,0.36561299780f,0.36704034572f,0.36846682995f,0.36989244715f,0.37131719395f,0.37274106701f,0.37416406297f,0.37558617849f,0.37700741022f,0.37842775481f,0.37984720892f,0.38126576922f, +0.38268343237f,0.38410019502f,0.38551605384f,0.38693100551f,0.38834504670f,0.38975817407f,0.39117038430f,0.39258167407f,0.39399204006f,0.39540147895f,0.39680998742f,0.39821756215f,0.39962419985f,0.40102989718f,0.40243465086f,0.40383845757f,0.40524131400f,0.40664321687f,0.40804416286f,0.40944414869f,0.41084317106f,0.41224122667f,0.41363831224f,0.41503442448f,0.41642956010f,0.41782371582f,0.41921688836f,0.42060907445f,0.42200027080f,0.42339047414f,0.42477968121f,0.42616788873f, +0.42755509343f,0.42894129206f,0.43032648134f,0.43171065803f,0.43309381885f,0.43447596057f,0.43585707992f,0.43723717366f,0.43861623854f,0.43999427131f,0.44137126873f,0.44274722756f,0.44412214457f,0.44549601651f,0.44686884016f,0.44824061229f,0.44961132965f,0.45098098905f,0.45234958723f,0.45371712100f,0.45508358713f,0.45644898240f,0.45781330360f,0.45917654752f,0.46053871096f,0.46189979070f,0.46325978355f,0.46461868631f,0.46597649577f,0.46733320874f,0.46868882204f,0.47004333246f, +0.47139673683f,0.47274903195f,0.47410021465f,0.47545028175f,0.47679923006f,0.47814705642f,0.47949375766f,0.48083933060f,0.48218377208f,0.48352707893f,0.48486924800f,0.48621027612f,0.48755016015f,0.48888889692f,0.49022648329f,0.49156291611f,0.49289819223f,0.49423230852f,0.49556526183f,0.49689704902f,0.49822766697f,0.49955711255f,0.50088538261f,0.50221247405f,0.50353838373f,0.50486310853f,0.50618664535f,0.50750899105f,0.50883014254f,0.51015009671f,0.51146885044f,0.51278640063f, +0.51410274419f,0.51541787802f,0.51673179902f,0.51804450410f,0.51935599017f,0.52066625414f,0.52197529294f,0.52328310348f,0.52458968268f,0.52589502747f,0.52719913478f,0.52850200154f,0.52980362469f,0.53110400115f,0.53240312788f,0.53370100181f,0.53499761989f,0.53629297907f,0.53758707630f,0.53887990853f,0.54017147273f,0.54146176585f,0.54275078486f,0.54403852673f,0.54532498842f,0.54661016691f,0.54789405917f,0.54917666219f,0.55045797294f,0.55173798840f,0.55301670558f,0.55429412145f, +0.55557023302f,0.55684503728f,0.55811853122f,0.55939071186f,0.56066157620f,0.56193112124f,0.56319934401f,0.56446624152f,0.56573181078f,0.56699604883f,0.56825895267f,0.56952051935f,0.57078074589f,0.57203962932f,0.57329716670f,0.57455335505f,0.57580819142f,0.57706167286f,0.57831379641f,0.57956455914f,0.58081395810f,0.58206199034f,0.58330865294f,0.58455394295f,0.58579785746f,0.58704039352f,0.58828154822f,0.58952131864f,0.59075970186f,0.59199669496f,0.59323229504f,0.59446649918f, +0.59569930449f,0.59693070806f,0.59816070700f,0.59938929840f,0.60061647938f,0.60184224706f,0.60306659854f,0.60428953095f,0.60551104140f,0.60673112703f,0.60794978497f,0.60916701234f,0.61038280628f,0.61159716393f,0.61281008243f,0.61402155893f,0.61523159058f,0.61644017453f,0.61764730794f,0.61885298796f,0.62005721176f,0.62125997651f,0.62246127937f,0.62366111753f,0.62485948814f,0.62605638840f,0.62725181550f,0.62844576660f,0.62963823891f,0.63082922963f,0.63201873594f,0.63320675505f, +0.63439328416f,0.63557832049f,0.63676186124f,0.63794390362f,0.63912444486f,0.64030348218f,0.64148101281f,0.64265703397f,0.64383154289f,0.64500453682f,0.64617601298f,0.64734596864f,0.64851440102f,0.64968130739f,0.65084668500f,0.65201053110f,0.65317284295f,0.65433361783f,0.65549285300f,0.65665054573f,0.65780669330f,0.65896129298f,0.66011434207f,0.66126583784f,0.66241577759f,0.66356415861f,0.66471097820f,0.66585623367f,0.66699992230f,0.66814204143f,0.66928258835f,0.67042156038f, +0.67155895485f,0.67269476907f,0.67382900038f,0.67496164610f,0.67609270358f,0.67722217014f,0.67835004313f,0.67947631990f,0.68060099780f,0.68172407417f,0.68284554639f,0.68396541180f,0.68508366777f,0.68620031168f,0.68731534089f,0.68842875278f,0.68954054474f,0.69065071413f,0.69175925836f,0.69286617482f,0.69397146089f,0.69507511398f,0.69617713149f,0.69727751083f,0.69837624941f,0.69947334464f,0.70056879394f,0.70166259474f,0.70275474446f,0.70384524052f,0.70493408038f,0.70602126145f, +0.70710678119f,0.70819063703f,0.70927282644f,0.71035334686f,0.71143219575f,0.71250937056f,0.71358486878f,0.71465868786f,0.71573082528f,0.71680127852f,0.71787004506f,0.71893712237f,0.72000250796f,0.72106619931f,0.72212819393f,0.72318848931f,0.72424708295f,0.72530397237f,0.72635915508f,0.72741262860f,0.72846439045f,0.72951443815f,0.73056276923f,0.73160938122f,0.73265427167f,0.73369743811f,0.73473887810f,0.73577858917f,0.73681656888f,0.73785281479f,0.73888732446f,0.73992009546f, +0.74095112535f,0.74198041172f,0.74300795214f,0.74403374418f,0.74505778544f,0.74608007351f,0.74710060598f,0.74811938045f,0.74913639452f,0.75015164581f,0.75116513191f,0.75217685045f,0.75318679904f,0.75419497532f,0.75520137690f,0.75620600141f,0.75720884651f,0.75820990981f,0.75920918898f,0.76020668165f,0.76120238548f,0.76219629813f,0.76318841726f,0.76417874054f,0.76516726562f,0.76615399020f,0.76713891194f,0.76812202852f,0.76910333765f,0.77008283699f,0.77106052426f,0.77203639715f, +0.77301045336f,0.77398269061f,0.77495310659f,0.77592169904f,0.77688846567f,0.77785340421f,0.77881651238f,0.77977778792f,0.78073722857f,0.78169483207f,0.78265059617f,0.78360451861f,0.78455659716f,0.78550682956f,0.78645521360f,0.78740174703f,0.78834642763f,0.78928925317f,0.79023022144f,0.79116933022f,0.79210657730f,0.79304196048f,0.79397547755f,0.79490712633f,0.79583690461f,0.79676481021f,0.79769084094f,0.79861499463f,0.79953726911f,0.80045766219f,0.80137617172f,0.80229279554f, +0.80320753148f,0.80412037740f,0.80503133114f,0.80594039057f,0.80684755354f,0.80775281793f,0.80865618159f,0.80955764240f,0.81045719825f,0.81135484702f,0.81225058659f,0.81314441485f,0.81403632971f,0.81492632906f,0.81581441081f,0.81670057287f,0.81758481315f,0.81846712958f,0.81934752008f,0.82022598257f,0.82110251499f,0.82197711528f,0.82284978138f,0.82372051123f,0.82458930279f,0.82545615400f,0.82632106285f,0.82718402727f,0.82804504526f,0.82890411477f,0.82976123379f,0.83061640031f, +0.83146961230f,0.83232086777f,0.83317016470f,0.83401750111f,0.83486287499f,0.83570628435f,0.83654772722f,0.83738720162f,0.83822470555f,0.83906023707f,0.83989379420f,0.84072537497f,0.84155497744f,0.84238259964f,0.84320823964f,0.84403189549f,0.84485356525f,0.84567324699f,0.84649093877f,0.84730663869f,0.84812034480f,0.84893205521f,0.84974176800f,0.85054948127f,0.85135519311f,0.85215890162f,0.85296060493f,0.85376030114f,0.85455798837f,0.85535366474f,0.85614732838f,0.85693897742f, +0.85772861000f,0.85851622426f,0.85930181836f,0.86008539043f,0.86086693864f,0.86164646114f,0.86242395611f,0.86319942171f,0.86397285612f,0.86474425752f,0.86551362409f,0.86628095402f,0.86704624552f,0.86780949676f,0.86857070597f,0.86932987135f,0.87008699111f,0.87084206347f,0.87159508666f,0.87234605889f,0.87309497842f,0.87384184347f,0.87458665228f,0.87532940310f,0.87607009420f,0.87680872381f,0.87754529021f,0.87827979166f,0.87901222643f,0.87974259280f,0.88047088905f,0.88119711347f, +0.88192126435f,0.88264333998f,0.88336333867f,0.88408125871f,0.88479709843f,0.88551085614f,0.88622253015f,0.88693211879f,0.88763962040f,0.88834503331f,0.88904835585f,0.88974958638f,0.89044872324f,0.89114576479f,0.89184070939f,0.89253355540f,0.89322430120f,0.89391294515f,0.89459948563f,0.89528392104f,0.89596624976f,0.89664647018f,0.89732458071f,0.89800057974f,0.89867446569f,0.89934623698f,0.90001589202f,0.90068342923f,0.90134884705f,0.90201214390f,0.90267331824f,0.90333236849f, +0.90398929312f,0.90464409058f,0.90529675932f,0.90594729781f,0.90659570451f,0.90724197792f,0.90788611649f,0.90852811872f,0.90916798309f,0.90980570810f,0.91044129226f,0.91107473406f,0.91170603201f,0.91233518462f,0.91296219043f,0.91358704795f,0.91420975570f,0.91483031224f,0.91544871609f,0.91606496580f,0.91667905992f,0.91729099701f,0.91790077562f,0.91850839433f,0.91911385169f,0.91971714629f,0.92031827671f,0.92091724153f,0.92151403934f,0.92210866874f,0.92270112833f,0.92329141672f, +0.92387953251f,0.92446547433f,0.92504924078f,0.92563083051f,0.92621024214f,0.92678747430f,0.92736252565f,0.92793539482f,0.92850608047f,0.92907458126f,0.92964089584f,0.93020502289f,0.93076696108f,0.93132670908f,0.93188426558f,0.93243962927f,0.93299279883f,0.93354377298f,0.93409255040f,0.93463912982f,0.93518350994f,0.93572568948f,0.93626566717f,0.93680344174f,0.93733901191f,0.93787237644f,0.93840353406f,0.93893248353f,0.93945922360f,0.93998375303f,0.94050607059f,0.94102617505f, +0.94154406518f,0.94205973977f,0.94257319760f,0.94308443747f,0.94359345816f,0.94410025849f,0.94460483726f,0.94510719329f,0.94560732538f,0.94610523237f,0.94660091308f,0.94709436635f,0.94758559102f,0.94807458592f,0.94856134992f,0.94904588185f,0.94952818059f,0.95000824500f,0.95048607395f,0.95096166631f,0.95143502097f,0.95190613681f,0.95237501272f,0.95284164760f,0.95330604035f,0.95376818989f,0.95422809511f,0.95468575494f,0.95514116831f,0.95559433413f,0.95604525135f,0.95649391890f, +0.95694033573f,0.95738450079f,0.95782641303f,0.95826607141f,0.95870347490f,0.95913862246f,0.95957151308f,0.96000214574f,0.96043051942f,0.96085663311f,0.96128048581f,0.96170207653f,0.96212140427f,0.96253846804f,0.96295326687f,0.96336579978f,0.96377606580f,0.96418406395f,0.96458979329f,0.96499325285f,0.96539444170f,0.96579335887f,0.96619000345f,0.96658437448f,0.96697647104f,0.96736629222f,0.96775383709f,0.96813910475f,0.96852209427f,0.96890280478f,0.96928123536f,0.96965738512f, +0.97003125319f,0.97040283869f,0.97077214073f,0.97113915845f,0.97150389099f,0.97186633748f,0.97222649708f,0.97258436893f,0.97293995221f,0.97329324605f,0.97364424965f,0.97399296217f,0.97433938279f,0.97468351069f,0.97502534507f,0.97536488512f,0.97570213004f,0.97603707904f,0.97636973133f,0.97670008613f,0.97702814266f,0.97735390015f,0.97767735782f,0.97799851493f,0.97831737072f,0.97863392443f,0.97894817532f,0.97926012265f,0.97956976569f,0.97987710370f,0.98018213597f,0.98048486177f, +0.98078528040f,0.98108339115f,0.98137919331f,0.98167268620f,0.98196386911f,0.98225274137f,0.98253930229f,0.98282355120f,0.98310548743f,0.98338511032f,0.98366241921f,0.98393741345f,0.98421009239f,0.98448045538f,0.98474850180f,0.98501423101f,0.98527764239f,0.98553873531f,0.98579750917f,0.98605396335f,0.98630809724f,0.98655991026f,0.98680940181f,0.98705657131f,0.98730141816f,0.98754394179f,0.98778414164f,0.98802201714f,0.98825756773f,0.98849079285f,0.98872169196f,0.98895026451f, +0.98917650996f,0.98940042779f,0.98962201746f,0.98984127846f,0.99005821026f,0.99027281236f,0.99048508426f,0.99069502544f,0.99090263543f,0.99110791372f,0.99131085985f,0.99151147332f,0.99170975367f,0.99190570043f,0.99209931314f,0.99229059135f,0.99247953460f,0.99266614245f,0.99285041446f,0.99303235020f,0.99321194923f,0.99338921115f,0.99356413552f,0.99373672194f,0.99390697000f,0.99407487930f,0.99424044945f,0.99440368006f,0.99456457073f,0.99472312110f,0.99487933079f,0.99503319944f, +0.99518472667f,0.99533391214f,0.99548075549f,0.99562525638f,0.99576741447f,0.99590722942f,0.99604470090f,0.99617982860f,0.99631261218f,0.99644305135f,0.99657114579f,0.99669689520f,0.99682029929f,0.99694135776f,0.99706007034f,0.99717643674f,0.99729045668f,0.99740212990f,0.99751145614f,0.99761843514f,0.99772306664f,0.99782535041f,0.99792528620f,0.99802287377f,0.99811811290f,0.99821100336f,0.99830154493f,0.99838973741f,0.99847558057f,0.99855907423f,0.99864021818f,0.99871901223f, +0.99879545621f,0.99886954991f,0.99894129319f,0.99901068585f,0.99907772775f,0.99914241872f,0.99920475862f,0.99926474729f,0.99932238459f,0.99937767039f,0.99943060456f,0.99948118697f,0.99952941750f,0.99957529605f,0.99961882250f,0.99965999674f,0.99969881870f,0.99973528826f,0.99976940535f,0.99980116989f,0.99983058180f,0.99985764101f,0.99988234745f,0.99990470108f,0.99992470184f,0.99994234968f,0.99995764455f,0.99997058643f,0.99998117528f,0.99998941108f,0.99999529381f,0.99999882345f, +1.00000000000f,0.99999882345f,0.99999529381f,0.99998941108f,0.99998117528f,0.99997058643f,0.99995764455f,0.99994234968f,0.99992470184f,0.99990470108f,0.99988234745f,0.99985764101f,0.99983058180f,0.99980116989f,0.99976940535f,0.99973528826f,0.99969881870f,0.99965999674f,0.99961882250f,0.99957529605f,0.99952941750f,0.99948118697f,0.99943060456f,0.99937767039f,0.99932238459f,0.99926474729f,0.99920475862f,0.99914241872f,0.99907772775f,0.99901068585f,0.99894129319f,0.99886954991f, +0.99879545621f,0.99871901223f,0.99864021818f,0.99855907423f,0.99847558057f,0.99838973741f,0.99830154493f,0.99821100336f,0.99811811290f,0.99802287377f,0.99792528620f,0.99782535041f,0.99772306664f,0.99761843514f,0.99751145614f,0.99740212990f,0.99729045668f,0.99717643674f,0.99706007034f,0.99694135776f,0.99682029929f,0.99669689520f,0.99657114579f,0.99644305135f,0.99631261218f,0.99617982860f,0.99604470090f,0.99590722942f,0.99576741447f,0.99562525638f,0.99548075549f,0.99533391214f, +0.99518472667f,0.99503319944f,0.99487933079f,0.99472312110f,0.99456457073f,0.99440368006f,0.99424044945f,0.99407487930f,0.99390697000f,0.99373672194f,0.99356413552f,0.99338921115f,0.99321194923f,0.99303235020f,0.99285041446f,0.99266614245f,0.99247953460f,0.99229059135f,0.99209931314f,0.99190570043f,0.99170975367f,0.99151147332f,0.99131085985f,0.99110791372f,0.99090263543f,0.99069502544f,0.99048508426f,0.99027281236f,0.99005821026f,0.98984127846f,0.98962201746f,0.98940042779f, +0.98917650996f,0.98895026451f,0.98872169196f,0.98849079285f,0.98825756773f,0.98802201714f,0.98778414164f,0.98754394179f,0.98730141816f,0.98705657131f,0.98680940181f,0.98655991026f,0.98630809724f,0.98605396335f,0.98579750917f,0.98553873531f,0.98527764239f,0.98501423101f,0.98474850180f,0.98448045538f,0.98421009239f,0.98393741345f,0.98366241921f,0.98338511032f,0.98310548743f,0.98282355120f,0.98253930229f,0.98225274137f,0.98196386911f,0.98167268620f,0.98137919331f,0.98108339115f, +0.98078528040f,0.98048486177f,0.98018213597f,0.97987710370f,0.97956976569f,0.97926012265f,0.97894817532f,0.97863392443f,0.97831737072f,0.97799851493f,0.97767735782f,0.97735390015f,0.97702814266f,0.97670008613f,0.97636973133f,0.97603707904f,0.97570213004f,0.97536488512f,0.97502534507f,0.97468351069f,0.97433938279f,0.97399296217f,0.97364424965f,0.97329324605f,0.97293995221f,0.97258436893f,0.97222649708f,0.97186633748f,0.97150389099f,0.97113915845f,0.97077214073f,0.97040283869f, +0.97003125319f,0.96965738512f,0.96928123536f,0.96890280478f,0.96852209427f,0.96813910475f,0.96775383709f,0.96736629222f,0.96697647104f,0.96658437448f,0.96619000345f,0.96579335887f,0.96539444170f,0.96499325285f,0.96458979329f,0.96418406395f,0.96377606580f,0.96336579978f,0.96295326687f,0.96253846804f,0.96212140427f,0.96170207653f,0.96128048581f,0.96085663311f,0.96043051942f,0.96000214574f,0.95957151308f,0.95913862246f,0.95870347490f,0.95826607141f,0.95782641303f,0.95738450079f, +0.95694033573f,0.95649391890f,0.95604525135f,0.95559433413f,0.95514116831f,0.95468575494f,0.95422809511f,0.95376818989f,0.95330604035f,0.95284164760f,0.95237501272f,0.95190613681f,0.95143502097f,0.95096166631f,0.95048607395f,0.95000824500f,0.94952818059f,0.94904588185f,0.94856134992f,0.94807458592f,0.94758559102f,0.94709436635f,0.94660091308f,0.94610523237f,0.94560732538f,0.94510719329f,0.94460483726f,0.94410025849f,0.94359345816f,0.94308443747f,0.94257319760f,0.94205973977f, +0.94154406518f,0.94102617505f,0.94050607059f,0.93998375303f,0.93945922360f,0.93893248353f,0.93840353406f,0.93787237644f,0.93733901191f,0.93680344174f,0.93626566717f,0.93572568948f,0.93518350994f,0.93463912982f,0.93409255040f,0.93354377298f,0.93299279883f,0.93243962927f,0.93188426558f,0.93132670908f,0.93076696108f,0.93020502289f,0.92964089584f,0.92907458126f,0.92850608047f,0.92793539482f,0.92736252565f,0.92678747430f,0.92621024214f,0.92563083051f,0.92504924078f,0.92446547433f, +0.92387953251f,0.92329141672f,0.92270112833f,0.92210866874f,0.92151403934f,0.92091724153f,0.92031827671f,0.91971714629f,0.91911385169f,0.91850839433f,0.91790077562f,0.91729099701f,0.91667905992f,0.91606496580f,0.91544871609f,0.91483031224f,0.91420975570f,0.91358704795f,0.91296219043f,0.91233518462f,0.91170603201f,0.91107473406f,0.91044129226f,0.90980570810f,0.90916798309f,0.90852811872f,0.90788611649f,0.90724197792f,0.90659570451f,0.90594729781f,0.90529675932f,0.90464409058f, +0.90398929312f,0.90333236849f,0.90267331824f,0.90201214390f,0.90134884705f,0.90068342923f,0.90001589202f,0.89934623698f,0.89867446569f,0.89800057974f,0.89732458071f,0.89664647018f,0.89596624976f,0.89528392104f,0.89459948563f,0.89391294515f,0.89322430120f,0.89253355540f,0.89184070939f,0.89114576479f,0.89044872324f,0.88974958638f,0.88904835585f,0.88834503331f,0.88763962040f,0.88693211879f,0.88622253015f,0.88551085614f,0.88479709843f,0.88408125871f,0.88336333867f,0.88264333998f, +0.88192126435f,0.88119711347f,0.88047088905f,0.87974259280f,0.87901222643f,0.87827979166f,0.87754529021f,0.87680872381f,0.87607009420f,0.87532940310f,0.87458665228f,0.87384184347f,0.87309497842f,0.87234605889f,0.87159508666f,0.87084206347f,0.87008699111f,0.86932987135f,0.86857070597f,0.86780949676f,0.86704624552f,0.86628095402f,0.86551362409f,0.86474425752f,0.86397285612f,0.86319942171f,0.86242395611f,0.86164646114f,0.86086693864f,0.86008539043f,0.85930181836f,0.85851622426f, +0.85772861000f,0.85693897742f,0.85614732838f,0.85535366474f,0.85455798837f,0.85376030114f,0.85296060493f,0.85215890162f,0.85135519311f,0.85054948127f,0.84974176800f,0.84893205521f,0.84812034480f,0.84730663869f,0.84649093877f,0.84567324699f,0.84485356525f,0.84403189549f,0.84320823964f,0.84238259964f,0.84155497744f,0.84072537497f,0.83989379420f,0.83906023707f,0.83822470555f,0.83738720162f,0.83654772722f,0.83570628435f,0.83486287499f,0.83401750111f,0.83317016470f,0.83232086777f, +0.83146961230f,0.83061640031f,0.82976123379f,0.82890411477f,0.82804504526f,0.82718402727f,0.82632106285f,0.82545615400f,0.82458930279f,0.82372051123f,0.82284978138f,0.82197711528f,0.82110251499f,0.82022598257f,0.81934752008f,0.81846712958f,0.81758481315f,0.81670057287f,0.81581441081f,0.81492632906f,0.81403632971f,0.81314441485f,0.81225058659f,0.81135484702f,0.81045719825f,0.80955764240f,0.80865618159f,0.80775281793f,0.80684755354f,0.80594039057f,0.80503133114f,0.80412037740f, +0.80320753148f,0.80229279554f,0.80137617172f,0.80045766219f,0.79953726911f,0.79861499463f,0.79769084094f,0.79676481021f,0.79583690461f,0.79490712633f,0.79397547755f,0.79304196048f,0.79210657730f,0.79116933022f,0.79023022144f,0.78928925317f,0.78834642763f,0.78740174703f,0.78645521360f,0.78550682956f,0.78455659716f,0.78360451861f,0.78265059617f,0.78169483207f,0.78073722857f,0.77977778792f,0.77881651238f,0.77785340421f,0.77688846567f,0.77592169904f,0.77495310659f,0.77398269061f, +0.77301045336f,0.77203639715f,0.77106052426f,0.77008283699f,0.76910333765f,0.76812202852f,0.76713891194f,0.76615399020f,0.76516726562f,0.76417874054f,0.76318841726f,0.76219629813f,0.76120238548f,0.76020668165f,0.75920918898f,0.75820990981f,0.75720884651f,0.75620600141f,0.75520137690f,0.75419497532f,0.75318679904f,0.75217685045f,0.75116513191f,0.75015164581f,0.74913639452f,0.74811938045f,0.74710060598f,0.74608007351f,0.74505778544f,0.74403374418f,0.74300795214f,0.74198041172f, +0.74095112535f,0.73992009546f,0.73888732446f,0.73785281479f,0.73681656888f,0.73577858917f,0.73473887810f,0.73369743811f,0.73265427167f,0.73160938122f,0.73056276923f,0.72951443815f,0.72846439045f,0.72741262860f,0.72635915508f,0.72530397237f,0.72424708295f,0.72318848931f,0.72212819393f,0.72106619931f,0.72000250796f,0.71893712237f,0.71787004506f,0.71680127852f,0.71573082528f,0.71465868786f,0.71358486878f,0.71250937056f,0.71143219575f,0.71035334686f,0.70927282644f,0.70819063703f, +0.70710678119f,0.70602126145f,0.70493408038f,0.70384524052f,0.70275474446f,0.70166259474f,0.70056879394f,0.69947334464f,0.69837624941f,0.69727751083f,0.69617713149f,0.69507511398f,0.69397146089f,0.69286617482f,0.69175925836f,0.69065071413f,0.68954054474f,0.68842875278f,0.68731534089f,0.68620031168f,0.68508366777f,0.68396541180f,0.68284554639f,0.68172407417f,0.68060099780f,0.67947631990f,0.67835004313f,0.67722217014f,0.67609270358f,0.67496164610f,0.67382900038f,0.67269476907f, +0.67155895485f,0.67042156038f,0.66928258835f,0.66814204143f,0.66699992230f,0.66585623367f,0.66471097820f,0.66356415861f,0.66241577759f,0.66126583784f,0.66011434207f,0.65896129298f,0.65780669330f,0.65665054573f,0.65549285300f,0.65433361783f,0.65317284295f,0.65201053110f,0.65084668500f,0.64968130739f,0.64851440102f,0.64734596864f,0.64617601298f,0.64500453682f,0.64383154289f,0.64265703397f,0.64148101281f,0.64030348218f,0.63912444486f,0.63794390362f,0.63676186124f,0.63557832049f, +0.63439328416f,0.63320675505f,0.63201873594f,0.63082922963f,0.62963823891f,0.62844576660f,0.62725181550f,0.62605638840f,0.62485948814f,0.62366111753f,0.62246127937f,0.62125997651f,0.62005721176f,0.61885298796f,0.61764730794f,0.61644017453f,0.61523159058f,0.61402155893f,0.61281008243f,0.61159716393f,0.61038280628f,0.60916701234f,0.60794978497f,0.60673112703f,0.60551104140f,0.60428953095f,0.60306659854f,0.60184224706f,0.60061647938f,0.59938929840f,0.59816070700f,0.59693070806f, +0.59569930449f,0.59446649918f,0.59323229504f,0.59199669496f,0.59075970186f,0.58952131864f,0.58828154822f,0.58704039352f,0.58579785746f,0.58455394295f,0.58330865294f,0.58206199034f,0.58081395810f,0.57956455914f,0.57831379641f,0.57706167286f,0.57580819142f,0.57455335505f,0.57329716670f,0.57203962932f,0.57078074589f,0.56952051935f,0.56825895267f,0.56699604883f,0.56573181078f,0.56446624152f,0.56319934401f,0.56193112124f,0.56066157620f,0.55939071186f,0.55811853122f,0.55684503728f, +0.55557023302f,0.55429412145f,0.55301670558f,0.55173798840f,0.55045797294f,0.54917666219f,0.54789405917f,0.54661016691f,0.54532498842f,0.54403852673f,0.54275078486f,0.54146176585f,0.54017147273f,0.53887990853f,0.53758707630f,0.53629297907f,0.53499761989f,0.53370100181f,0.53240312788f,0.53110400115f,0.52980362469f,0.52850200154f,0.52719913478f,0.52589502747f,0.52458968268f,0.52328310348f,0.52197529294f,0.52066625414f,0.51935599017f,0.51804450410f,0.51673179902f,0.51541787802f, +0.51410274419f,0.51278640063f,0.51146885044f,0.51015009671f,0.50883014254f,0.50750899105f,0.50618664535f,0.50486310853f,0.50353838373f,0.50221247405f,0.50088538261f,0.49955711255f,0.49822766697f,0.49689704902f,0.49556526183f,0.49423230852f,0.49289819223f,0.49156291611f,0.49022648329f,0.48888889692f,0.48755016015f,0.48621027612f,0.48486924800f,0.48352707893f,0.48218377208f,0.48083933060f,0.47949375766f,0.47814705642f,0.47679923006f,0.47545028175f,0.47410021465f,0.47274903195f, +0.47139673683f,0.47004333246f,0.46868882204f,0.46733320874f,0.46597649577f,0.46461868631f,0.46325978355f,0.46189979070f,0.46053871096f,0.45917654752f,0.45781330360f,0.45644898240f,0.45508358713f,0.45371712100f,0.45234958723f,0.45098098905f,0.44961132965f,0.44824061229f,0.44686884016f,0.44549601651f,0.44412214457f,0.44274722756f,0.44137126873f,0.43999427131f,0.43861623854f,0.43723717366f,0.43585707992f,0.43447596057f,0.43309381885f,0.43171065803f,0.43032648134f,0.42894129206f, +0.42755509343f,0.42616788873f,0.42477968121f,0.42339047414f,0.42200027080f,0.42060907445f,0.41921688836f,0.41782371582f,0.41642956010f,0.41503442448f,0.41363831224f,0.41224122667f,0.41084317106f,0.40944414869f,0.40804416286f,0.40664321687f,0.40524131400f,0.40383845757f,0.40243465086f,0.40102989718f,0.39962419985f,0.39821756215f,0.39680998742f,0.39540147895f,0.39399204006f,0.39258167407f,0.39117038430f,0.38975817407f,0.38834504670f,0.38693100551f,0.38551605384f,0.38410019502f, +0.38268343237f,0.38126576922f,0.37984720892f,0.37842775481f,0.37700741022f,0.37558617849f,0.37416406297f,0.37274106701f,0.37131719395f,0.36989244715f,0.36846682995f,0.36704034572f,0.36561299780f,0.36418478957f,0.36275572437f,0.36132580557f,0.35989503653f,0.35846342063f,0.35703096123f,0.35559766170f,0.35416352542f,0.35272855576f,0.35129275609f,0.34985612979f,0.34841868025f,0.34698041085f,0.34554132496f,0.34410142599f,0.34266071731f,0.34121920232f,0.33977688441f,0.33833376697f, +0.33688985339f,0.33544514708f,0.33399965144f,0.33255336987f,0.33110630576f,0.32965846253f,0.32820984358f,0.32676045232f,0.32531029216f,0.32385936652f,0.32240767880f,0.32095523243f,0.31950203082f,0.31804807739f,0.31659337556f,0.31513792875f,0.31368174040f,0.31222481392f,0.31076715275f,0.30930876031f,0.30784964004f,0.30638979537f,0.30492922974f,0.30346794657f,0.30200594932f,0.30054324142f,0.29907982631f,0.29761570744f,0.29615088824f,0.29468537218f,0.29321916269f,0.29175226323f, +0.29028467725f,0.28881640821f,0.28734745954f,0.28587783473f,0.28440753721f,0.28293657046f,0.28146493793f,0.27999264308f,0.27851968939f,0.27704608031f,0.27557181931f,0.27409690987f,0.27262135545f,0.27114515953f,0.26966832557f,0.26819085706f,0.26671275747f,0.26523403029f,0.26375467897f,0.26227470702f,0.26079411792f,0.25931291513f,0.25783110216f,0.25634868249f,0.25486565960f,0.25338203700f,0.25189781815f,0.25041300657f,0.24892760575f,0.24744161917f,0.24595505034f,0.24446790275f, +0.24298017990f,0.24149188530f,0.24000302245f,0.23851359484f,0.23702360599f,0.23553305940f,0.23404195858f,0.23255030704f,0.23105810828f,0.22956536582f,0.22807208317f,0.22657826385f,0.22508391136f,0.22358902923f,0.22209362097f,0.22059769011f,0.21910124016f,0.21760427464f,0.21610679708f,0.21460881099f,0.21311031992f,0.21161132737f,0.21011183688f,0.20861185198f,0.20711137619f,0.20561041305f,0.20410896609f,0.20260703884f,0.20110463484f,0.19960175762f,0.19809841072f,0.19659459767f, +0.19509032202f,0.19358558730f,0.19208039705f,0.19057475482f,0.18906866415f,0.18756212858f,0.18605515166f,0.18454773694f,0.18303988796f,0.18153160826f,0.18002290141f,0.17851377094f,0.17700422041f,0.17549425338f,0.17398387339f,0.17247308400f,0.17096188876f,0.16945029123f,0.16793829497f,0.16642590354f,0.16491312049f,0.16339994938f,0.16188639378f,0.16037245724f,0.15885814333f,0.15734345562f,0.15582839765f,0.15431297301f,0.15279718526f,0.15128103796f,0.14976453468f,0.14824767899f, +0.14673047446f,0.14521292465f,0.14369503315f,0.14217680352f,0.14065823933f,0.13913934416f,0.13762012159f,0.13610057518f,0.13458070851f,0.13306052516f,0.13154002870f,0.13001922272f,0.12849811079f,0.12697669650f,0.12545498341f,0.12393297512f,0.12241067520f,0.12088808724f,0.11936521481f,0.11784206151f,0.11631863091f,0.11479492661f,0.11327095218f,0.11174671121f,0.11022220729f,0.10869744401f,0.10717242496f,0.10564715371f,0.10412163387f,0.10259586902f,0.10106986275f,0.09954361866f, +0.09801714033f,0.09649043136f,0.09496349533f,0.09343633585f,0.09190895650f,0.09038136088f,0.08885355258f,0.08732553521f,0.08579731234f,0.08426888759f,0.08274026455f,0.08121144681f,0.07968243797f,0.07815324163f,0.07662386139f,0.07509430085f,0.07356456360f,0.07203465325f,0.07050457339f,0.06897432763f,0.06744391956f,0.06591335280f,0.06438263093f,0.06285175756f,0.06132073630f,0.05978957075f,0.05825826450f,0.05672682117f,0.05519524435f,0.05366353765f,0.05213170468f,0.05059974904f, +0.04906767433f,0.04753548416f,0.04600318213f,0.04447077185f,0.04293825693f,0.04140564098f,0.03987292759f,0.03834012037f,0.03680722294f,0.03527423890f,0.03374117185f,0.03220802541f,0.03067480318f,0.02914150876f,0.02760814578f,0.02607471783f,0.02454122852f,0.02300768147f,0.02147408028f,0.01994042855f,0.01840672991f,0.01687298795f,0.01533920628f,0.01380538853f,0.01227153829f,0.01073765917f,0.00920375478f,0.00766982874f,0.00613588465f,0.00460192612f,0.00306795676f,0.00153398019f +}; + +static const float costab[2048] = { +1.00000000000f,0.99999882345f,0.99999529381f,0.99998941108f,0.99998117528f,0.99997058643f,0.99995764455f,0.99994234968f,0.99992470184f,0.99990470108f,0.99988234745f,0.99985764101f,0.99983058180f,0.99980116989f,0.99976940535f,0.99973528826f,0.99969881870f,0.99965999674f,0.99961882250f,0.99957529605f,0.99952941750f,0.99948118697f,0.99943060456f,0.99937767039f,0.99932238459f,0.99926474729f,0.99920475862f,0.99914241872f,0.99907772775f,0.99901068585f,0.99894129319f,0.99886954991f, +0.99879545621f,0.99871901223f,0.99864021818f,0.99855907423f,0.99847558057f,0.99838973741f,0.99830154493f,0.99821100336f,0.99811811290f,0.99802287377f,0.99792528620f,0.99782535041f,0.99772306664f,0.99761843514f,0.99751145614f,0.99740212990f,0.99729045668f,0.99717643674f,0.99706007034f,0.99694135776f,0.99682029929f,0.99669689520f,0.99657114579f,0.99644305135f,0.99631261218f,0.99617982860f,0.99604470090f,0.99590722942f,0.99576741447f,0.99562525638f,0.99548075549f,0.99533391214f, +0.99518472667f,0.99503319944f,0.99487933079f,0.99472312110f,0.99456457073f,0.99440368006f,0.99424044945f,0.99407487930f,0.99390697000f,0.99373672194f,0.99356413552f,0.99338921115f,0.99321194923f,0.99303235020f,0.99285041446f,0.99266614245f,0.99247953460f,0.99229059135f,0.99209931314f,0.99190570043f,0.99170975367f,0.99151147332f,0.99131085985f,0.99110791372f,0.99090263543f,0.99069502544f,0.99048508426f,0.99027281236f,0.99005821026f,0.98984127846f,0.98962201746f,0.98940042779f, +0.98917650996f,0.98895026451f,0.98872169196f,0.98849079285f,0.98825756773f,0.98802201714f,0.98778414164f,0.98754394179f,0.98730141816f,0.98705657131f,0.98680940181f,0.98655991026f,0.98630809724f,0.98605396335f,0.98579750917f,0.98553873531f,0.98527764239f,0.98501423101f,0.98474850180f,0.98448045538f,0.98421009239f,0.98393741345f,0.98366241921f,0.98338511032f,0.98310548743f,0.98282355120f,0.98253930229f,0.98225274137f,0.98196386911f,0.98167268620f,0.98137919331f,0.98108339115f, +0.98078528040f,0.98048486177f,0.98018213597f,0.97987710370f,0.97956976569f,0.97926012265f,0.97894817532f,0.97863392443f,0.97831737072f,0.97799851493f,0.97767735782f,0.97735390015f,0.97702814266f,0.97670008613f,0.97636973133f,0.97603707904f,0.97570213004f,0.97536488512f,0.97502534507f,0.97468351069f,0.97433938279f,0.97399296217f,0.97364424965f,0.97329324605f,0.97293995221f,0.97258436893f,0.97222649708f,0.97186633748f,0.97150389099f,0.97113915845f,0.97077214073f,0.97040283869f, +0.97003125319f,0.96965738512f,0.96928123536f,0.96890280478f,0.96852209427f,0.96813910475f,0.96775383709f,0.96736629222f,0.96697647104f,0.96658437448f,0.96619000345f,0.96579335887f,0.96539444170f,0.96499325285f,0.96458979329f,0.96418406395f,0.96377606580f,0.96336579978f,0.96295326687f,0.96253846804f,0.96212140427f,0.96170207653f,0.96128048581f,0.96085663311f,0.96043051942f,0.96000214574f,0.95957151308f,0.95913862246f,0.95870347490f,0.95826607141f,0.95782641303f,0.95738450079f, +0.95694033573f,0.95649391890f,0.95604525135f,0.95559433413f,0.95514116831f,0.95468575494f,0.95422809511f,0.95376818989f,0.95330604035f,0.95284164760f,0.95237501272f,0.95190613681f,0.95143502097f,0.95096166631f,0.95048607395f,0.95000824500f,0.94952818059f,0.94904588185f,0.94856134992f,0.94807458592f,0.94758559102f,0.94709436635f,0.94660091308f,0.94610523237f,0.94560732538f,0.94510719329f,0.94460483726f,0.94410025849f,0.94359345816f,0.94308443747f,0.94257319760f,0.94205973977f, +0.94154406518f,0.94102617505f,0.94050607059f,0.93998375303f,0.93945922360f,0.93893248353f,0.93840353406f,0.93787237644f,0.93733901191f,0.93680344174f,0.93626566717f,0.93572568948f,0.93518350994f,0.93463912982f,0.93409255040f,0.93354377298f,0.93299279883f,0.93243962927f,0.93188426558f,0.93132670908f,0.93076696108f,0.93020502289f,0.92964089584f,0.92907458126f,0.92850608047f,0.92793539482f,0.92736252565f,0.92678747430f,0.92621024214f,0.92563083051f,0.92504924078f,0.92446547433f, +0.92387953251f,0.92329141672f,0.92270112833f,0.92210866874f,0.92151403934f,0.92091724153f,0.92031827671f,0.91971714629f,0.91911385169f,0.91850839433f,0.91790077562f,0.91729099701f,0.91667905992f,0.91606496580f,0.91544871609f,0.91483031224f,0.91420975570f,0.91358704795f,0.91296219043f,0.91233518462f,0.91170603201f,0.91107473406f,0.91044129226f,0.90980570810f,0.90916798309f,0.90852811872f,0.90788611649f,0.90724197792f,0.90659570451f,0.90594729781f,0.90529675932f,0.90464409058f, +0.90398929312f,0.90333236849f,0.90267331824f,0.90201214390f,0.90134884705f,0.90068342923f,0.90001589202f,0.89934623698f,0.89867446569f,0.89800057974f,0.89732458071f,0.89664647018f,0.89596624976f,0.89528392104f,0.89459948563f,0.89391294515f,0.89322430120f,0.89253355540f,0.89184070939f,0.89114576479f,0.89044872324f,0.88974958638f,0.88904835585f,0.88834503331f,0.88763962040f,0.88693211879f,0.88622253015f,0.88551085614f,0.88479709843f,0.88408125871f,0.88336333867f,0.88264333998f, +0.88192126435f,0.88119711347f,0.88047088905f,0.87974259280f,0.87901222643f,0.87827979166f,0.87754529021f,0.87680872381f,0.87607009420f,0.87532940310f,0.87458665228f,0.87384184347f,0.87309497842f,0.87234605889f,0.87159508666f,0.87084206347f,0.87008699111f,0.86932987135f,0.86857070597f,0.86780949676f,0.86704624552f,0.86628095402f,0.86551362409f,0.86474425752f,0.86397285612f,0.86319942171f,0.86242395611f,0.86164646114f,0.86086693864f,0.86008539043f,0.85930181836f,0.85851622426f, +0.85772861000f,0.85693897742f,0.85614732838f,0.85535366474f,0.85455798837f,0.85376030114f,0.85296060493f,0.85215890162f,0.85135519311f,0.85054948127f,0.84974176800f,0.84893205521f,0.84812034480f,0.84730663869f,0.84649093877f,0.84567324699f,0.84485356525f,0.84403189549f,0.84320823964f,0.84238259964f,0.84155497744f,0.84072537497f,0.83989379420f,0.83906023707f,0.83822470555f,0.83738720162f,0.83654772722f,0.83570628435f,0.83486287499f,0.83401750111f,0.83317016470f,0.83232086777f, +0.83146961230f,0.83061640031f,0.82976123379f,0.82890411477f,0.82804504526f,0.82718402727f,0.82632106285f,0.82545615400f,0.82458930279f,0.82372051123f,0.82284978138f,0.82197711528f,0.82110251499f,0.82022598257f,0.81934752008f,0.81846712958f,0.81758481315f,0.81670057287f,0.81581441081f,0.81492632906f,0.81403632971f,0.81314441485f,0.81225058659f,0.81135484702f,0.81045719825f,0.80955764240f,0.80865618159f,0.80775281793f,0.80684755354f,0.80594039057f,0.80503133114f,0.80412037740f, +0.80320753148f,0.80229279554f,0.80137617172f,0.80045766219f,0.79953726911f,0.79861499463f,0.79769084094f,0.79676481021f,0.79583690461f,0.79490712633f,0.79397547755f,0.79304196048f,0.79210657730f,0.79116933022f,0.79023022144f,0.78928925317f,0.78834642763f,0.78740174703f,0.78645521360f,0.78550682956f,0.78455659716f,0.78360451861f,0.78265059617f,0.78169483207f,0.78073722857f,0.77977778792f,0.77881651238f,0.77785340421f,0.77688846567f,0.77592169904f,0.77495310659f,0.77398269061f, +0.77301045336f,0.77203639715f,0.77106052426f,0.77008283699f,0.76910333765f,0.76812202852f,0.76713891194f,0.76615399020f,0.76516726562f,0.76417874054f,0.76318841726f,0.76219629813f,0.76120238548f,0.76020668165f,0.75920918898f,0.75820990981f,0.75720884651f,0.75620600141f,0.75520137690f,0.75419497532f,0.75318679904f,0.75217685045f,0.75116513191f,0.75015164581f,0.74913639452f,0.74811938045f,0.74710060598f,0.74608007351f,0.74505778544f,0.74403374418f,0.74300795214f,0.74198041172f, +0.74095112535f,0.73992009546f,0.73888732446f,0.73785281479f,0.73681656888f,0.73577858917f,0.73473887810f,0.73369743811f,0.73265427167f,0.73160938122f,0.73056276923f,0.72951443815f,0.72846439045f,0.72741262860f,0.72635915508f,0.72530397237f,0.72424708295f,0.72318848931f,0.72212819393f,0.72106619931f,0.72000250796f,0.71893712237f,0.71787004506f,0.71680127852f,0.71573082528f,0.71465868786f,0.71358486878f,0.71250937056f,0.71143219575f,0.71035334686f,0.70927282644f,0.70819063703f, +0.70710678119f,0.70602126145f,0.70493408038f,0.70384524052f,0.70275474446f,0.70166259474f,0.70056879394f,0.69947334464f,0.69837624941f,0.69727751083f,0.69617713149f,0.69507511398f,0.69397146089f,0.69286617482f,0.69175925836f,0.69065071413f,0.68954054474f,0.68842875278f,0.68731534089f,0.68620031168f,0.68508366777f,0.68396541180f,0.68284554639f,0.68172407417f,0.68060099780f,0.67947631990f,0.67835004313f,0.67722217014f,0.67609270358f,0.67496164610f,0.67382900038f,0.67269476907f, +0.67155895485f,0.67042156038f,0.66928258835f,0.66814204143f,0.66699992230f,0.66585623367f,0.66471097820f,0.66356415861f,0.66241577759f,0.66126583784f,0.66011434207f,0.65896129298f,0.65780669330f,0.65665054573f,0.65549285300f,0.65433361783f,0.65317284295f,0.65201053110f,0.65084668500f,0.64968130739f,0.64851440102f,0.64734596864f,0.64617601298f,0.64500453682f,0.64383154289f,0.64265703397f,0.64148101281f,0.64030348218f,0.63912444486f,0.63794390362f,0.63676186124f,0.63557832049f, +0.63439328416f,0.63320675505f,0.63201873594f,0.63082922963f,0.62963823891f,0.62844576660f,0.62725181550f,0.62605638840f,0.62485948814f,0.62366111753f,0.62246127937f,0.62125997651f,0.62005721176f,0.61885298796f,0.61764730794f,0.61644017453f,0.61523159058f,0.61402155893f,0.61281008243f,0.61159716393f,0.61038280628f,0.60916701234f,0.60794978497f,0.60673112703f,0.60551104140f,0.60428953095f,0.60306659854f,0.60184224706f,0.60061647938f,0.59938929840f,0.59816070700f,0.59693070806f, +0.59569930449f,0.59446649918f,0.59323229504f,0.59199669496f,0.59075970186f,0.58952131864f,0.58828154822f,0.58704039352f,0.58579785746f,0.58455394295f,0.58330865294f,0.58206199034f,0.58081395810f,0.57956455914f,0.57831379641f,0.57706167286f,0.57580819142f,0.57455335505f,0.57329716670f,0.57203962932f,0.57078074589f,0.56952051935f,0.56825895267f,0.56699604883f,0.56573181078f,0.56446624152f,0.56319934401f,0.56193112124f,0.56066157620f,0.55939071186f,0.55811853122f,0.55684503728f, +0.55557023302f,0.55429412145f,0.55301670558f,0.55173798840f,0.55045797294f,0.54917666219f,0.54789405917f,0.54661016691f,0.54532498842f,0.54403852673f,0.54275078486f,0.54146176585f,0.54017147273f,0.53887990853f,0.53758707630f,0.53629297907f,0.53499761989f,0.53370100181f,0.53240312788f,0.53110400115f,0.52980362469f,0.52850200154f,0.52719913478f,0.52589502747f,0.52458968268f,0.52328310348f,0.52197529294f,0.52066625414f,0.51935599017f,0.51804450410f,0.51673179902f,0.51541787802f, +0.51410274419f,0.51278640063f,0.51146885044f,0.51015009671f,0.50883014254f,0.50750899105f,0.50618664535f,0.50486310853f,0.50353838373f,0.50221247405f,0.50088538261f,0.49955711255f,0.49822766697f,0.49689704902f,0.49556526183f,0.49423230852f,0.49289819223f,0.49156291611f,0.49022648329f,0.48888889692f,0.48755016015f,0.48621027612f,0.48486924800f,0.48352707893f,0.48218377208f,0.48083933060f,0.47949375766f,0.47814705642f,0.47679923006f,0.47545028175f,0.47410021465f,0.47274903195f, +0.47139673683f,0.47004333246f,0.46868882204f,0.46733320874f,0.46597649577f,0.46461868631f,0.46325978355f,0.46189979070f,0.46053871096f,0.45917654752f,0.45781330360f,0.45644898240f,0.45508358713f,0.45371712100f,0.45234958723f,0.45098098905f,0.44961132965f,0.44824061229f,0.44686884016f,0.44549601651f,0.44412214457f,0.44274722756f,0.44137126873f,0.43999427131f,0.43861623854f,0.43723717366f,0.43585707992f,0.43447596057f,0.43309381885f,0.43171065803f,0.43032648134f,0.42894129206f, +0.42755509343f,0.42616788873f,0.42477968121f,0.42339047414f,0.42200027080f,0.42060907445f,0.41921688836f,0.41782371582f,0.41642956010f,0.41503442448f,0.41363831224f,0.41224122667f,0.41084317106f,0.40944414869f,0.40804416286f,0.40664321687f,0.40524131400f,0.40383845757f,0.40243465086f,0.40102989718f,0.39962419985f,0.39821756215f,0.39680998742f,0.39540147895f,0.39399204006f,0.39258167407f,0.39117038430f,0.38975817407f,0.38834504670f,0.38693100551f,0.38551605384f,0.38410019502f, +0.38268343237f,0.38126576922f,0.37984720892f,0.37842775481f,0.37700741022f,0.37558617849f,0.37416406297f,0.37274106701f,0.37131719395f,0.36989244715f,0.36846682995f,0.36704034572f,0.36561299780f,0.36418478957f,0.36275572437f,0.36132580557f,0.35989503653f,0.35846342063f,0.35703096123f,0.35559766170f,0.35416352542f,0.35272855576f,0.35129275609f,0.34985612979f,0.34841868025f,0.34698041085f,0.34554132496f,0.34410142599f,0.34266071731f,0.34121920232f,0.33977688441f,0.33833376697f, +0.33688985339f,0.33544514708f,0.33399965144f,0.33255336987f,0.33110630576f,0.32965846253f,0.32820984358f,0.32676045232f,0.32531029216f,0.32385936652f,0.32240767880f,0.32095523243f,0.31950203082f,0.31804807739f,0.31659337556f,0.31513792875f,0.31368174040f,0.31222481392f,0.31076715275f,0.30930876031f,0.30784964004f,0.30638979537f,0.30492922974f,0.30346794657f,0.30200594932f,0.30054324142f,0.29907982631f,0.29761570744f,0.29615088824f,0.29468537218f,0.29321916269f,0.29175226323f, +0.29028467725f,0.28881640821f,0.28734745954f,0.28587783473f,0.28440753721f,0.28293657046f,0.28146493793f,0.27999264308f,0.27851968939f,0.27704608031f,0.27557181931f,0.27409690987f,0.27262135545f,0.27114515953f,0.26966832557f,0.26819085706f,0.26671275747f,0.26523403029f,0.26375467897f,0.26227470702f,0.26079411792f,0.25931291513f,0.25783110216f,0.25634868249f,0.25486565960f,0.25338203700f,0.25189781815f,0.25041300657f,0.24892760575f,0.24744161917f,0.24595505034f,0.24446790275f, +0.24298017990f,0.24149188530f,0.24000302245f,0.23851359484f,0.23702360599f,0.23553305940f,0.23404195858f,0.23255030704f,0.23105810828f,0.22956536582f,0.22807208317f,0.22657826385f,0.22508391136f,0.22358902923f,0.22209362097f,0.22059769011f,0.21910124016f,0.21760427464f,0.21610679708f,0.21460881099f,0.21311031992f,0.21161132737f,0.21011183688f,0.20861185198f,0.20711137619f,0.20561041305f,0.20410896609f,0.20260703884f,0.20110463484f,0.19960175762f,0.19809841072f,0.19659459767f, +0.19509032202f,0.19358558730f,0.19208039705f,0.19057475482f,0.18906866415f,0.18756212858f,0.18605515166f,0.18454773694f,0.18303988796f,0.18153160826f,0.18002290141f,0.17851377094f,0.17700422041f,0.17549425338f,0.17398387339f,0.17247308400f,0.17096188876f,0.16945029123f,0.16793829497f,0.16642590354f,0.16491312049f,0.16339994938f,0.16188639378f,0.16037245724f,0.15885814333f,0.15734345562f,0.15582839765f,0.15431297301f,0.15279718526f,0.15128103796f,0.14976453468f,0.14824767899f, +0.14673047446f,0.14521292465f,0.14369503315f,0.14217680352f,0.14065823933f,0.13913934416f,0.13762012159f,0.13610057518f,0.13458070851f,0.13306052516f,0.13154002870f,0.13001922272f,0.12849811079f,0.12697669650f,0.12545498341f,0.12393297512f,0.12241067520f,0.12088808724f,0.11936521481f,0.11784206151f,0.11631863091f,0.11479492661f,0.11327095218f,0.11174671121f,0.11022220729f,0.10869744401f,0.10717242496f,0.10564715371f,0.10412163387f,0.10259586902f,0.10106986275f,0.09954361866f, +0.09801714033f,0.09649043136f,0.09496349533f,0.09343633585f,0.09190895650f,0.09038136088f,0.08885355258f,0.08732553521f,0.08579731234f,0.08426888759f,0.08274026455f,0.08121144681f,0.07968243797f,0.07815324163f,0.07662386139f,0.07509430085f,0.07356456360f,0.07203465325f,0.07050457339f,0.06897432763f,0.06744391956f,0.06591335280f,0.06438263093f,0.06285175756f,0.06132073630f,0.05978957075f,0.05825826450f,0.05672682117f,0.05519524435f,0.05366353765f,0.05213170468f,0.05059974904f, +0.04906767433f,0.04753548416f,0.04600318213f,0.04447077185f,0.04293825693f,0.04140564098f,0.03987292759f,0.03834012037f,0.03680722294f,0.03527423890f,0.03374117185f,0.03220802541f,0.03067480318f,0.02914150876f,0.02760814578f,0.02607471783f,0.02454122852f,0.02300768147f,0.02147408028f,0.01994042855f,0.01840672991f,0.01687298795f,0.01533920628f,0.01380538853f,0.01227153829f,0.01073765917f,0.00920375478f,0.00766982874f,0.00613588465f,0.00460192612f,0.00306795676f,0.00153398019f, +0.00000000000f,-0.00153398019f,-0.00306795676f,-0.00460192612f,-0.00613588465f,-0.00766982874f,-0.00920375478f,-0.01073765917f,-0.01227153829f,-0.01380538853f,-0.01533920628f,-0.01687298795f,-0.01840672991f,-0.01994042855f,-0.02147408028f,-0.02300768147f,-0.02454122852f,-0.02607471783f,-0.02760814578f,-0.02914150876f,-0.03067480318f,-0.03220802541f,-0.03374117185f,-0.03527423890f,-0.03680722294f,-0.03834012037f,-0.03987292759f,-0.04140564098f,-0.04293825693f,-0.04447077185f,-0.04600318213f,-0.04753548416f, +-0.04906767433f,-0.05059974904f,-0.05213170468f,-0.05366353765f,-0.05519524435f,-0.05672682117f,-0.05825826450f,-0.05978957075f,-0.06132073630f,-0.06285175756f,-0.06438263093f,-0.06591335280f,-0.06744391956f,-0.06897432763f,-0.07050457339f,-0.07203465325f,-0.07356456360f,-0.07509430085f,-0.07662386139f,-0.07815324163f,-0.07968243797f,-0.08121144681f,-0.08274026455f,-0.08426888759f,-0.08579731234f,-0.08732553521f,-0.08885355258f,-0.09038136088f,-0.09190895650f,-0.09343633585f,-0.09496349533f,-0.09649043136f, +-0.09801714033f,-0.09954361866f,-0.10106986275f,-0.10259586902f,-0.10412163387f,-0.10564715371f,-0.10717242496f,-0.10869744401f,-0.11022220729f,-0.11174671121f,-0.11327095218f,-0.11479492661f,-0.11631863091f,-0.11784206151f,-0.11936521481f,-0.12088808724f,-0.12241067520f,-0.12393297512f,-0.12545498341f,-0.12697669650f,-0.12849811079f,-0.13001922272f,-0.13154002870f,-0.13306052516f,-0.13458070851f,-0.13610057518f,-0.13762012159f,-0.13913934416f,-0.14065823933f,-0.14217680352f,-0.14369503315f,-0.14521292465f, +-0.14673047446f,-0.14824767899f,-0.14976453468f,-0.15128103796f,-0.15279718526f,-0.15431297301f,-0.15582839765f,-0.15734345562f,-0.15885814333f,-0.16037245724f,-0.16188639378f,-0.16339994938f,-0.16491312049f,-0.16642590354f,-0.16793829497f,-0.16945029123f,-0.17096188876f,-0.17247308400f,-0.17398387339f,-0.17549425338f,-0.17700422041f,-0.17851377094f,-0.18002290141f,-0.18153160826f,-0.18303988796f,-0.18454773694f,-0.18605515166f,-0.18756212858f,-0.18906866415f,-0.19057475482f,-0.19208039705f,-0.19358558730f, +-0.19509032202f,-0.19659459767f,-0.19809841072f,-0.19960175762f,-0.20110463484f,-0.20260703884f,-0.20410896609f,-0.20561041305f,-0.20711137619f,-0.20861185198f,-0.21011183688f,-0.21161132737f,-0.21311031992f,-0.21460881099f,-0.21610679708f,-0.21760427464f,-0.21910124016f,-0.22059769011f,-0.22209362097f,-0.22358902923f,-0.22508391136f,-0.22657826385f,-0.22807208317f,-0.22956536582f,-0.23105810828f,-0.23255030704f,-0.23404195858f,-0.23553305940f,-0.23702360599f,-0.23851359484f,-0.24000302245f,-0.24149188530f, +-0.24298017990f,-0.24446790275f,-0.24595505034f,-0.24744161917f,-0.24892760575f,-0.25041300657f,-0.25189781815f,-0.25338203700f,-0.25486565960f,-0.25634868249f,-0.25783110216f,-0.25931291513f,-0.26079411792f,-0.26227470702f,-0.26375467897f,-0.26523403029f,-0.26671275747f,-0.26819085706f,-0.26966832557f,-0.27114515953f,-0.27262135545f,-0.27409690987f,-0.27557181931f,-0.27704608031f,-0.27851968939f,-0.27999264308f,-0.28146493793f,-0.28293657046f,-0.28440753721f,-0.28587783473f,-0.28734745954f,-0.28881640821f, +-0.29028467725f,-0.29175226323f,-0.29321916269f,-0.29468537218f,-0.29615088824f,-0.29761570744f,-0.29907982631f,-0.30054324142f,-0.30200594932f,-0.30346794657f,-0.30492922974f,-0.30638979537f,-0.30784964004f,-0.30930876031f,-0.31076715275f,-0.31222481392f,-0.31368174040f,-0.31513792875f,-0.31659337556f,-0.31804807739f,-0.31950203082f,-0.32095523243f,-0.32240767880f,-0.32385936652f,-0.32531029216f,-0.32676045232f,-0.32820984358f,-0.32965846253f,-0.33110630576f,-0.33255336987f,-0.33399965144f,-0.33544514708f, +-0.33688985339f,-0.33833376697f,-0.33977688441f,-0.34121920232f,-0.34266071731f,-0.34410142599f,-0.34554132496f,-0.34698041085f,-0.34841868025f,-0.34985612979f,-0.35129275609f,-0.35272855576f,-0.35416352542f,-0.35559766170f,-0.35703096123f,-0.35846342063f,-0.35989503653f,-0.36132580557f,-0.36275572437f,-0.36418478957f,-0.36561299780f,-0.36704034572f,-0.36846682995f,-0.36989244715f,-0.37131719395f,-0.37274106701f,-0.37416406297f,-0.37558617849f,-0.37700741022f,-0.37842775481f,-0.37984720892f,-0.38126576922f, +-0.38268343237f,-0.38410019502f,-0.38551605384f,-0.38693100551f,-0.38834504670f,-0.38975817407f,-0.39117038430f,-0.39258167407f,-0.39399204006f,-0.39540147895f,-0.39680998742f,-0.39821756215f,-0.39962419985f,-0.40102989718f,-0.40243465086f,-0.40383845757f,-0.40524131400f,-0.40664321687f,-0.40804416286f,-0.40944414869f,-0.41084317106f,-0.41224122667f,-0.41363831224f,-0.41503442448f,-0.41642956010f,-0.41782371582f,-0.41921688836f,-0.42060907445f,-0.42200027080f,-0.42339047414f,-0.42477968121f,-0.42616788873f, +-0.42755509343f,-0.42894129206f,-0.43032648134f,-0.43171065803f,-0.43309381885f,-0.43447596057f,-0.43585707992f,-0.43723717366f,-0.43861623854f,-0.43999427131f,-0.44137126873f,-0.44274722756f,-0.44412214457f,-0.44549601651f,-0.44686884016f,-0.44824061229f,-0.44961132965f,-0.45098098905f,-0.45234958723f,-0.45371712100f,-0.45508358713f,-0.45644898240f,-0.45781330360f,-0.45917654752f,-0.46053871096f,-0.46189979070f,-0.46325978355f,-0.46461868631f,-0.46597649577f,-0.46733320874f,-0.46868882204f,-0.47004333246f, +-0.47139673683f,-0.47274903195f,-0.47410021465f,-0.47545028175f,-0.47679923006f,-0.47814705642f,-0.47949375766f,-0.48083933060f,-0.48218377208f,-0.48352707893f,-0.48486924800f,-0.48621027612f,-0.48755016015f,-0.48888889692f,-0.49022648329f,-0.49156291611f,-0.49289819223f,-0.49423230852f,-0.49556526183f,-0.49689704902f,-0.49822766697f,-0.49955711255f,-0.50088538261f,-0.50221247405f,-0.50353838373f,-0.50486310853f,-0.50618664535f,-0.50750899105f,-0.50883014254f,-0.51015009671f,-0.51146885044f,-0.51278640063f, +-0.51410274419f,-0.51541787802f,-0.51673179902f,-0.51804450410f,-0.51935599017f,-0.52066625414f,-0.52197529294f,-0.52328310348f,-0.52458968268f,-0.52589502747f,-0.52719913478f,-0.52850200154f,-0.52980362469f,-0.53110400115f,-0.53240312788f,-0.53370100181f,-0.53499761989f,-0.53629297907f,-0.53758707630f,-0.53887990853f,-0.54017147273f,-0.54146176585f,-0.54275078486f,-0.54403852673f,-0.54532498842f,-0.54661016691f,-0.54789405917f,-0.54917666219f,-0.55045797294f,-0.55173798840f,-0.55301670558f,-0.55429412145f, +-0.55557023302f,-0.55684503728f,-0.55811853122f,-0.55939071186f,-0.56066157620f,-0.56193112124f,-0.56319934401f,-0.56446624152f,-0.56573181078f,-0.56699604883f,-0.56825895267f,-0.56952051935f,-0.57078074589f,-0.57203962932f,-0.57329716670f,-0.57455335505f,-0.57580819142f,-0.57706167286f,-0.57831379641f,-0.57956455914f,-0.58081395810f,-0.58206199034f,-0.58330865294f,-0.58455394295f,-0.58579785746f,-0.58704039352f,-0.58828154822f,-0.58952131864f,-0.59075970186f,-0.59199669496f,-0.59323229504f,-0.59446649918f, +-0.59569930449f,-0.59693070806f,-0.59816070700f,-0.59938929840f,-0.60061647938f,-0.60184224706f,-0.60306659854f,-0.60428953095f,-0.60551104140f,-0.60673112703f,-0.60794978497f,-0.60916701234f,-0.61038280628f,-0.61159716393f,-0.61281008243f,-0.61402155893f,-0.61523159058f,-0.61644017453f,-0.61764730794f,-0.61885298796f,-0.62005721176f,-0.62125997651f,-0.62246127937f,-0.62366111753f,-0.62485948814f,-0.62605638840f,-0.62725181550f,-0.62844576660f,-0.62963823891f,-0.63082922963f,-0.63201873594f,-0.63320675505f, +-0.63439328416f,-0.63557832049f,-0.63676186124f,-0.63794390362f,-0.63912444486f,-0.64030348218f,-0.64148101281f,-0.64265703397f,-0.64383154289f,-0.64500453682f,-0.64617601298f,-0.64734596864f,-0.64851440102f,-0.64968130739f,-0.65084668500f,-0.65201053110f,-0.65317284295f,-0.65433361783f,-0.65549285300f,-0.65665054573f,-0.65780669330f,-0.65896129298f,-0.66011434207f,-0.66126583784f,-0.66241577759f,-0.66356415861f,-0.66471097820f,-0.66585623367f,-0.66699992230f,-0.66814204143f,-0.66928258835f,-0.67042156038f, +-0.67155895485f,-0.67269476907f,-0.67382900038f,-0.67496164610f,-0.67609270358f,-0.67722217014f,-0.67835004313f,-0.67947631990f,-0.68060099780f,-0.68172407417f,-0.68284554639f,-0.68396541180f,-0.68508366777f,-0.68620031168f,-0.68731534089f,-0.68842875278f,-0.68954054474f,-0.69065071413f,-0.69175925836f,-0.69286617482f,-0.69397146089f,-0.69507511398f,-0.69617713149f,-0.69727751083f,-0.69837624941f,-0.69947334464f,-0.70056879394f,-0.70166259474f,-0.70275474446f,-0.70384524052f,-0.70493408038f,-0.70602126145f, +-0.70710678119f,-0.70819063703f,-0.70927282644f,-0.71035334686f,-0.71143219575f,-0.71250937056f,-0.71358486878f,-0.71465868786f,-0.71573082528f,-0.71680127852f,-0.71787004506f,-0.71893712237f,-0.72000250796f,-0.72106619931f,-0.72212819393f,-0.72318848931f,-0.72424708295f,-0.72530397237f,-0.72635915508f,-0.72741262860f,-0.72846439045f,-0.72951443815f,-0.73056276923f,-0.73160938122f,-0.73265427167f,-0.73369743811f,-0.73473887810f,-0.73577858917f,-0.73681656888f,-0.73785281479f,-0.73888732446f,-0.73992009546f, +-0.74095112535f,-0.74198041172f,-0.74300795214f,-0.74403374418f,-0.74505778544f,-0.74608007351f,-0.74710060598f,-0.74811938045f,-0.74913639452f,-0.75015164581f,-0.75116513191f,-0.75217685045f,-0.75318679904f,-0.75419497532f,-0.75520137690f,-0.75620600141f,-0.75720884651f,-0.75820990981f,-0.75920918898f,-0.76020668165f,-0.76120238548f,-0.76219629813f,-0.76318841726f,-0.76417874054f,-0.76516726562f,-0.76615399020f,-0.76713891194f,-0.76812202852f,-0.76910333765f,-0.77008283699f,-0.77106052426f,-0.77203639715f, +-0.77301045336f,-0.77398269061f,-0.77495310659f,-0.77592169904f,-0.77688846567f,-0.77785340421f,-0.77881651238f,-0.77977778792f,-0.78073722857f,-0.78169483207f,-0.78265059617f,-0.78360451861f,-0.78455659716f,-0.78550682956f,-0.78645521360f,-0.78740174703f,-0.78834642763f,-0.78928925317f,-0.79023022144f,-0.79116933022f,-0.79210657730f,-0.79304196048f,-0.79397547755f,-0.79490712633f,-0.79583690461f,-0.79676481021f,-0.79769084094f,-0.79861499463f,-0.79953726911f,-0.80045766219f,-0.80137617172f,-0.80229279554f, +-0.80320753148f,-0.80412037740f,-0.80503133114f,-0.80594039057f,-0.80684755354f,-0.80775281793f,-0.80865618159f,-0.80955764240f,-0.81045719825f,-0.81135484702f,-0.81225058659f,-0.81314441485f,-0.81403632971f,-0.81492632906f,-0.81581441081f,-0.81670057287f,-0.81758481315f,-0.81846712958f,-0.81934752008f,-0.82022598257f,-0.82110251499f,-0.82197711528f,-0.82284978138f,-0.82372051123f,-0.82458930279f,-0.82545615400f,-0.82632106285f,-0.82718402727f,-0.82804504526f,-0.82890411477f,-0.82976123379f,-0.83061640031f, +-0.83146961230f,-0.83232086777f,-0.83317016470f,-0.83401750111f,-0.83486287499f,-0.83570628435f,-0.83654772722f,-0.83738720162f,-0.83822470555f,-0.83906023707f,-0.83989379420f,-0.84072537497f,-0.84155497744f,-0.84238259964f,-0.84320823964f,-0.84403189549f,-0.84485356525f,-0.84567324699f,-0.84649093877f,-0.84730663869f,-0.84812034480f,-0.84893205521f,-0.84974176800f,-0.85054948127f,-0.85135519311f,-0.85215890162f,-0.85296060493f,-0.85376030114f,-0.85455798837f,-0.85535366474f,-0.85614732838f,-0.85693897742f, +-0.85772861000f,-0.85851622426f,-0.85930181836f,-0.86008539043f,-0.86086693864f,-0.86164646114f,-0.86242395611f,-0.86319942171f,-0.86397285612f,-0.86474425752f,-0.86551362409f,-0.86628095402f,-0.86704624552f,-0.86780949676f,-0.86857070597f,-0.86932987135f,-0.87008699111f,-0.87084206347f,-0.87159508666f,-0.87234605889f,-0.87309497842f,-0.87384184347f,-0.87458665228f,-0.87532940310f,-0.87607009420f,-0.87680872381f,-0.87754529021f,-0.87827979166f,-0.87901222643f,-0.87974259280f,-0.88047088905f,-0.88119711347f, +-0.88192126435f,-0.88264333998f,-0.88336333867f,-0.88408125871f,-0.88479709843f,-0.88551085614f,-0.88622253015f,-0.88693211879f,-0.88763962040f,-0.88834503331f,-0.88904835585f,-0.88974958638f,-0.89044872324f,-0.89114576479f,-0.89184070939f,-0.89253355540f,-0.89322430120f,-0.89391294515f,-0.89459948563f,-0.89528392104f,-0.89596624976f,-0.89664647018f,-0.89732458071f,-0.89800057974f,-0.89867446569f,-0.89934623698f,-0.90001589202f,-0.90068342923f,-0.90134884705f,-0.90201214390f,-0.90267331824f,-0.90333236849f, +-0.90398929312f,-0.90464409058f,-0.90529675932f,-0.90594729781f,-0.90659570451f,-0.90724197792f,-0.90788611649f,-0.90852811872f,-0.90916798309f,-0.90980570810f,-0.91044129226f,-0.91107473406f,-0.91170603201f,-0.91233518462f,-0.91296219043f,-0.91358704795f,-0.91420975570f,-0.91483031224f,-0.91544871609f,-0.91606496580f,-0.91667905992f,-0.91729099701f,-0.91790077562f,-0.91850839433f,-0.91911385169f,-0.91971714629f,-0.92031827671f,-0.92091724153f,-0.92151403934f,-0.92210866874f,-0.92270112833f,-0.92329141672f, +-0.92387953251f,-0.92446547433f,-0.92504924078f,-0.92563083051f,-0.92621024214f,-0.92678747430f,-0.92736252565f,-0.92793539482f,-0.92850608047f,-0.92907458126f,-0.92964089584f,-0.93020502289f,-0.93076696108f,-0.93132670908f,-0.93188426558f,-0.93243962927f,-0.93299279883f,-0.93354377298f,-0.93409255040f,-0.93463912982f,-0.93518350994f,-0.93572568948f,-0.93626566717f,-0.93680344174f,-0.93733901191f,-0.93787237644f,-0.93840353406f,-0.93893248353f,-0.93945922360f,-0.93998375303f,-0.94050607059f,-0.94102617505f, +-0.94154406518f,-0.94205973977f,-0.94257319760f,-0.94308443747f,-0.94359345816f,-0.94410025849f,-0.94460483726f,-0.94510719329f,-0.94560732538f,-0.94610523237f,-0.94660091308f,-0.94709436635f,-0.94758559102f,-0.94807458592f,-0.94856134992f,-0.94904588185f,-0.94952818059f,-0.95000824500f,-0.95048607395f,-0.95096166631f,-0.95143502097f,-0.95190613681f,-0.95237501272f,-0.95284164760f,-0.95330604035f,-0.95376818989f,-0.95422809511f,-0.95468575494f,-0.95514116831f,-0.95559433413f,-0.95604525135f,-0.95649391890f, +-0.95694033573f,-0.95738450079f,-0.95782641303f,-0.95826607141f,-0.95870347490f,-0.95913862246f,-0.95957151308f,-0.96000214574f,-0.96043051942f,-0.96085663311f,-0.96128048581f,-0.96170207653f,-0.96212140427f,-0.96253846804f,-0.96295326687f,-0.96336579978f,-0.96377606580f,-0.96418406395f,-0.96458979329f,-0.96499325285f,-0.96539444170f,-0.96579335887f,-0.96619000345f,-0.96658437448f,-0.96697647104f,-0.96736629222f,-0.96775383709f,-0.96813910475f,-0.96852209427f,-0.96890280478f,-0.96928123536f,-0.96965738512f, +-0.97003125319f,-0.97040283869f,-0.97077214073f,-0.97113915845f,-0.97150389099f,-0.97186633748f,-0.97222649708f,-0.97258436893f,-0.97293995221f,-0.97329324605f,-0.97364424965f,-0.97399296217f,-0.97433938279f,-0.97468351069f,-0.97502534507f,-0.97536488512f,-0.97570213004f,-0.97603707904f,-0.97636973133f,-0.97670008613f,-0.97702814266f,-0.97735390015f,-0.97767735782f,-0.97799851493f,-0.97831737072f,-0.97863392443f,-0.97894817532f,-0.97926012265f,-0.97956976569f,-0.97987710370f,-0.98018213597f,-0.98048486177f, +-0.98078528040f,-0.98108339115f,-0.98137919331f,-0.98167268620f,-0.98196386911f,-0.98225274137f,-0.98253930229f,-0.98282355120f,-0.98310548743f,-0.98338511032f,-0.98366241921f,-0.98393741345f,-0.98421009239f,-0.98448045538f,-0.98474850180f,-0.98501423101f,-0.98527764239f,-0.98553873531f,-0.98579750917f,-0.98605396335f,-0.98630809724f,-0.98655991026f,-0.98680940181f,-0.98705657131f,-0.98730141816f,-0.98754394179f,-0.98778414164f,-0.98802201714f,-0.98825756773f,-0.98849079285f,-0.98872169196f,-0.98895026451f, +-0.98917650996f,-0.98940042779f,-0.98962201746f,-0.98984127846f,-0.99005821026f,-0.99027281236f,-0.99048508426f,-0.99069502544f,-0.99090263543f,-0.99110791372f,-0.99131085985f,-0.99151147332f,-0.99170975367f,-0.99190570043f,-0.99209931314f,-0.99229059135f,-0.99247953460f,-0.99266614245f,-0.99285041446f,-0.99303235020f,-0.99321194923f,-0.99338921115f,-0.99356413552f,-0.99373672194f,-0.99390697000f,-0.99407487930f,-0.99424044945f,-0.99440368006f,-0.99456457073f,-0.99472312110f,-0.99487933079f,-0.99503319944f, +-0.99518472667f,-0.99533391214f,-0.99548075549f,-0.99562525638f,-0.99576741447f,-0.99590722942f,-0.99604470090f,-0.99617982860f,-0.99631261218f,-0.99644305135f,-0.99657114579f,-0.99669689520f,-0.99682029929f,-0.99694135776f,-0.99706007034f,-0.99717643674f,-0.99729045668f,-0.99740212990f,-0.99751145614f,-0.99761843514f,-0.99772306664f,-0.99782535041f,-0.99792528620f,-0.99802287377f,-0.99811811290f,-0.99821100336f,-0.99830154493f,-0.99838973741f,-0.99847558057f,-0.99855907423f,-0.99864021818f,-0.99871901223f, +-0.99879545621f,-0.99886954991f,-0.99894129319f,-0.99901068585f,-0.99907772775f,-0.99914241872f,-0.99920475862f,-0.99926474729f,-0.99932238459f,-0.99937767039f,-0.99943060456f,-0.99948118697f,-0.99952941750f,-0.99957529605f,-0.99961882250f,-0.99965999674f,-0.99969881870f,-0.99973528826f,-0.99976940535f,-0.99980116989f,-0.99983058180f,-0.99985764101f,-0.99988234745f,-0.99990470108f,-0.99992470184f,-0.99994234968f,-0.99995764455f,-0.99997058643f,-0.99998117528f,-0.99998941108f,-0.99999529381f,-0.99999882345f +}; +#else +float sintab[65536] = {0}; +float costab[65536] = {0}; +#endif + +#endif diff --git a/dsp/fft/win_function.c b/dsp/fft/win_function.c new file mode 100644 index 0000000000000000000000000000000000000000..35be4465e386d577fc112ff4f56962ee9b276716 --- /dev/null +++ b/dsp/fft/win_function.c @@ -0,0 +1,84 @@ +/********************************************************************* +* @File name: win_function.c +* @Author: merry merry +* @Version: 1.0.0 +* @Date: 2023/11/02 +* @LastDate: 2023/11/02 +* @Description: +*********************************************************************/ +#include "win_function.h" +#include "math.h" + +static void cosine_window(float *w, int n, const double *coeff, int ncoeff, int flag) +{ + int i, j; + double wi; + const int wlength = flag ? (n - 1) : n; + + for (i = 0; i < n; i++) { + wi = coeff[0]; + for (j = 1; j < ncoeff; ++j) { + wi += coeff[j] * cos(i * j * 2.0 * M_PI / wlength); + } + w[i] = wi; + } +} + +static void uniform_window(float *w, int n) +{ + int i; + for (i = 0; i < n; i++) + w[i] = 1.0f; +} + +static void hann_window(float *w, int n, int flag) +{ + const double coeff[2] = {0.5, -0.5}; + + cosine_window(w, n, coeff, 2, flag); +} + +static void hamming_window(float *w, int n, int flag) +{ + const double coeff[2] = {0.54, -0.46}; + + cosine_window(w, n, coeff, 2, flag); +} + +static void blackman_window(float *w, int n, int flag) +{ + const double coeff[3] = {0.42, -0.5, 0.08}; + + cosine_window(w, n, coeff, 3, flag); +} + +static void flattop_window(float *w, int n, int flag) +{ + const double coeff[5] = {0.21557895, -0.41663158, 0.277263158, -0.083578947, 0.006947368}; + + cosine_window(w, n, coeff, 5, flag); +} + +void get_window_factor(float *w, int n, int wf) +{ + switch (wf) { + case 0: + uniform_window(w, n); + break; + case 1: + hann_window(w, n, 1); + break; + case 2: + hamming_window(w, n, 1); + break; + case 5: + blackman_window(w, n, 1); + break; + case 7: + flattop_window(w, n, 1); + break; + default: + uniform_window(w, n); + break; + } +} diff --git a/dsp/fft/win_function.h b/dsp/fft/win_function.h new file mode 100644 index 0000000000000000000000000000000000000000..585787d6e3f71e8013634e6160b0192097d589ce --- /dev/null +++ b/dsp/fft/win_function.h @@ -0,0 +1,10 @@ +#ifndef __WIN_FUNCTION_H__ +#define __WIN_FUNCTION_H__ + +#ifndef M_PI +#define M_PI (3.141592653589793238462643) +#endif + +void get_window_factor(float *w, int n, int wf); + +#endif diff --git a/header/libDSP.h b/header/libDSP.h deleted file mode 100644 index fba504b8b15ccb8aac2e9486c99734e28b839fa0..0000000000000000000000000000000000000000 --- a/header/libDSP.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef LIBDSP_H_ -#define LIBDSP_H_ - -#include "libDSP_struct.h" - -void CombineDSP(static float *inputdata,struct VibrationChannelConfig channelConfig,struct VibrationSignalConfig signalConfig,struct CalResult *outputData); - -#endif /* LIBDSP_H_ */ \ No newline at end of file diff --git a/header/libDSP_struct.h b/header/libDSP_struct.h deleted file mode 100644 index cc1d1b53eb539eee9bb6e88ef2ff68e5cc7cc16c..0000000000000000000000000000000000000000 --- a/header/libDSP_struct.h +++ /dev/null @@ -1,174 +0,0 @@ -#ifndef LIBDSP_STRUCT_H_ -#define LIBDSP_STRUCT_H_ - -#include -#include - -struct VibrationSignalConfig -{ - float SC_AdjustFactor; //矫正设置中的矫正系数 - float SC_ZeroOffset; //矫正设置中的零点偏移 - float SC_SensorOffset; //传感器设置中的偏移量 - float SC_AnalyzeFreqHigh; //分析频段上限 - float SC_AnalyzeFreqLow; //分析频段下限 - float SC_OctaveConfig; //倍频程选项 - char SC_DataChoice[16];//参数名称 用16字节对应位(从最低位开始,目前已有特征值参数依次为第 0 位到第 60 位) -/*时域特征值 -Vibration_PPV 第 0 位 -Vibration_AVE 第 1 位 -Vibration_ABS_AVE 第 2 位 -Vibration_RMS 第 3 位 -Vibration_SD 第 4 位 -Vibration_Sr_AMP 第 5 位 -Vibration_Variance 第 6 位 -Vibration_ABS_AVE_AMP 第 7 位 -Vibration_P 第 8 位 -Vibration_Max 第 9 位 -Vibration_Min 第 10 位 -Vibration_P_Factor 第 11 位 -Vibration_Pulse_Factor 第 12 位 -Vibration_Margin_Factor 第 13 位 -Vibration_Curve_Factor 第 14 位 -Vibration_Kurtosis_Factor 第 15 位 -Vibration_Kurtosis 第 16 位 -Vibration_Skewness_Factor 第 17 位 -Vibration_Skewness 第 18 位*/ - -/*频域特征值 -Freq_BasePha 第 19 位 -Freq_TotaldB 第 20 位 -Freq_HighdB 第 21 位 -Freq_LowdB 第 22 位 -octavedB 第 23 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -Freq_VelocityRMS 第 24 位 -Freq_AverageVoltage 第 25 位 -Freq_DisplacementRMS 第 26 位 -intensity 第 27 位 -Freq_FC 第 28 位 -Freq_Msf 第 29 位 -Freq_Rmsf 第 30 位 -Freq_Vf 第 31 位 -Freq_rpm 第 32 位 -feature 第 33 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -peakValue 第 35 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -Vibration_PPV 第 36 位(频谱特征值) -Vibration_AVE 第 37 位(频谱特征值) -Vibration_ABS_AVE 第 38 位(频谱特征值) -Vibration_RMS 第 39 位(频谱特征值) -Vibration_SD 第 40 位(频谱特征值) -Vibration_Sr_AMP 第 41 位(频谱特征值) -Vibration_Variance 第 42 位(频谱特征值) -Vibration_ABS_AVE_AMP 第 43 位(频谱特征值) -Vibration_P 第 44 位(频谱特征值) -Vibration_Max 第 45 位(频谱特征值) -Vibration_Min 第 46 位(频谱特征值) -Vibration_P_Factor 第 47 位(频谱特征值) -Vibration_Pulse_Factor 第 48 位(频谱特征值) -Vibration_Margin_Factor 第 49 位(频谱特征值) -Vibration_Curve_Factor 第 50 位(频谱特征值) -Vibration_Kurtosis_Factor 第 51 位(频谱特征值) -Vibration_Kurtosis 第 52 位(频谱特征值) -Vibration_Skewness_Factor 第 53 位(频谱特征值) -Vibration_Skewness 第 54 位(频谱特征值) -*/ - -/*时频谱 -rawAccData 第 55 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -accelerationFFTAmpDB 第 56 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -accelerationFFTAmp 第 57 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -dspFFTPha 第 58 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -accelerationFFTPower 第 59 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂) -velocityFFTAmp 第 60 位(由于是指针类型,这里仅表示其启用位,实际处理更复杂)*/ -}; - -struct VibrationChannelConfig -{ - uint32_t CC_ChannelNum; //通道号 - uint32_t CC_ChannelType; //通道类型 - uint32_t CC_SampleMode; //采样方式 0:64倍频X16周期 1:32倍频X32周期 2:16倍频X64周期 3:不跟随转速 - int CC_WindowTap; //窗函数选择,1:hanning窗;2:hamming窗;3:blackman窗;4:flapttop窗;5:不加窗;6:Kaiser窗 - float CC_Magnification; // 通道放大倍数 - float CC_Sensitivity; //灵敏度 - float CC_Rpm; //通道对应设备转速(实测转速或虚拟转速) - float CC_Samplerate; //采样频率 - float CC_Samplepoint; //采样点数 - float CC_FilterOrder; //滤波阶数 - float CC_Filterfc; //滤波截至频率 -}; - - -struct VibrationTimeEigenvalue{ - float Vibration_PPV;//peak-peak value 峰峰值 (位移单位um,加速度单位m/s2) - float Vibration_AVE;//average value 平均值 (位移单位um,加速度单位m/s2) - float Vibration_ABS_AVE;//absolute average 均值绝对值 (位移单位um,加速度单位m/s2) - float Vibration_RMS;//root mean square 均方根 (位移单位um,加速度单位m/s2) - float Vibration_SD;//standard deviation 标准差 (位移单位um,加速度单位m/s2) - float Vibration_Sr_AMP;//square root amplitude 方根幅值 (位移单位um,加速度单位m/s2) - float Vibration_Variance;//variance 方差 (位移单位um,加速度单位m/s2) - float Vibration_ABS_AVE_AMP;//absolute average amplitude 绝对平均幅值 (位移单位um,加速度单位m/s2) - float Vibration_P;//peak value 峰值 (位移单位um,加速度单位m/s2) - float Vibration_Max;//maximum 最大值(位移单位um,加速度单位m/s2) - float Vibration_Min;//minimum 最小值(位移单位um,加速度单位m/s2) - float Vibration_P_Factor;// peak value factor 峰值因子 - float Vibration_Pulse_Factor;//pulse factor 脉冲因子 - float Vibration_Margin_Factor;//margin factor 裕度因子 - float Vibration_Curve_Factor;//curve factor 波形因子 - float Vibration_Kurtosis_Factor;// kurtosis factor 峭度因子 - float Vibration_Kurtosis;// kurtosis 峭度 - float Vibration_Skewness_Factor;//skewness factor 偏度因子 - float Vibration_Skewness;//skewness 偏度 -}VibrationTimeEigenvalue_t; - -struct VibrationFrequencyEigenvalue{ - float Amplitude; - float Phase; - float Frequency; -}; - -struct LibVibrationdspDisplacementFeature{ - float Amplitude; - float Phase; -}; - -struct LibVibrationFreqValue{//频域数据处理结果 - float Freq_BasePha;//基频相位 单位° 20220331 - float Freq_TotaldB;//振动加速度总值 - float Freq_HighdB;//高频段总值 - float Freq_LowdB;//低频段总值 - float *octavedB;//倍频程 - float Freq_VelocityRMS;//单向速度RMS值,用于计算烈度 单位mm/s - float Freq_AverageVoltage;//平均电压 单位V - float Freq_DisplacementRMS;//加速度积分成位移有效值,单位um - float intensity;//烈度 - float Freq_FC;//重心频率 - float Freq_Msf; //均方频率 - float Freq_Rmsf; //均方根频率 - float Freq_Vf; //频率方差 - float Freq_rpm;//跟随转速值 - struct VibrationFrequencyEigenvalue *feature; //自定义个倍频值 - struct VibrationFrequencyEigenvalue *peakValue; //频谱自定义个峰值 - struct VibrationTimeEigenvalue featureValue;//频谱特征值(频谱幅值过时域算法) -}; - -struct LibVibrationdspMachineIntensityResult{//机组总烈度值 - float intensity; -}; - -struct LibVibrationdspSinSpecData{//速度/加速度数据处理结果 - /* 通用 */ - float *rawAccData; // 原始数据 - float *accelerationFFTAmpDB; // FFT频谱,单位:dB - float *accelerationFFTAmp; // FFT频谱 - float *dspFFTPha; // FFT相位谱 - float *accelerationFFTPower; // 功率谱 - float *velocityFFTAmp; // 速度谱 -}; - -struct CalResult{ - struct LibVibrationdspSinSpecData *sinSpecData; - struct LibVibrationFreqValue *freqData; - struct VibrationTimeEigenvalue *timeEigenData; - struct LibVibrationdspMachineIntensityResult *machineIntensity; -} - -#endif /* LIBDSP_STRUCT_H_ */ diff --git a/lib_bdsp/bdsp.h b/lib_bdsp/bdsp.h new file mode 100644 index 0000000000000000000000000000000000000000..37b3715e6432c475b8f0154871728ac3ba03c9ae --- /dev/null +++ b/lib_bdsp/bdsp.h @@ -0,0 +1,149 @@ +#ifndef __BDSP_H__ +#define __BDSP_H__ + +#include "dsp_common.h" + +/* -------------------------------------------------------------------------- */ +/* macro */ +/* -------------------------------------------------------------------------- */ +const enum dspFilterTypeEnums { + NOFILTER, + HIGHPASS, + LOWPASS, + BANDPASS, + STOP +}; + +const enum dspWindowType { + RECTANGLE, + HANN, + HAMMING, + BLACKMAN, + FLATTOP, + KAISER +}; + +/* -------------------------------------------------------------------------- */ +/* typedef */ +/* -------------------------------------------------------------------------- */ +// 结构体来存储时域统计量 +typedef struct _BdspTimeEigen +{ + float max; // 最大值 + float min; // 最小值 + float ave; // 平均值 + float absAve; // 均值绝对值 + float absAveAmp; // 绝对平均幅值 + float XFG; // 方根幅值 + float rms; // 均方根 + float std; // 标准差 + float var; // 方差 + float peak2Valley; // 峰峰值 + float peakfactor; // 峰值因子 + float pulsefactor; // 脉冲因子 + float marginFactor; // 裕度因子 + float waveFactor; // 波形因子 + float skewness; // 偏度 + float kurtosis; // 峭度 + float skewnessFactor; // 偏度因子 + float kurtosisFactor; // 峭度因子 +} BdspTimeEigen; + +/* -------------------------------------------------------------------------- */ +/* function */ +/* -------------------------------------------------------------------------- */ +/** + * @brief 数据恢复计算函数 + * 根据输入数据和恢复系数计算实际物理量 + * 计算公式: outputData = adjustCoefficient * inputdata / sensitivity + offsetValue + * + * @param inputData 输入数据指针,指向原始采集数据 + * @param dataSize 数据长度 + * @param sensitivity 灵敏度 + * @param adjustCoefficient 数据校正系数 + * @param offsetValue 数据偏移量 + * @param outputData 输出数据指针,用于存储计算后的结果 + * @return int ERROR_CODE + */ +int bdsp_data_restore(float *inputData, uint32_t dataSize, float sensitivity, float adjustCoefficient, float offsetValue, float *outputData); + +/** + * @brief 计算时域统计量 + * + * @param inputData 输入数据指针 + * @param dataSize 数据长度 + * @param timeEigen 输出时域统计量指针 + * @return int ERROR_CODE + */ +int bdsp_calc_time_eigen(float *inputData, int dataSize, BdspTimeEigen *timeEigen); + +/** + * @brief 使用梯形积分法计算时域单次积分 + * + * @param inputData 输入数据指针 + * @param dataSize 数据长度 + * @param sampleRate 采样率(Hz) + * @param outputData 输出积分结果数组指针,需预先分配dataSize内存 + * @return int ERROR_CODE + */ +int bdsp_calc_time_intergration(const float *inputData, int dataSize, float sampleRate, float *outputData); + +/** + * @brief 获取恢复系数 + * + * @param windowType 窗类型 + * @param winAmpCompesationPara 幅值恢复系数 + * @param winEnergyCompesationPara 能量恢复系数 + */ +void bdsp_get_window_compesation_para(int windowType, float winAmpCompesationPara, float winEnergyCompesationPara); + +/** + * @brief 初始化窗系数 + * + * @param dataSize 数据长度 + * @param windowType 窗类型 + * @param windowPara kaiser窗应用系数 + * @param windowWeight 输出结果,指向窗系数指针,需预先分配dataSize内存 + * @return int ERROR_CODE + */ +int bdsp_calc_window_weight(int dataSize, int windowType, double windowPara, double *windowWeight); + +/** + * @brief 执行加窗 + * + * @param inputData 输入数据 + * @param windowWeight 窗系数 + * @param dataSize 数据长度 + * @param outputData 输出结果,指向窗系数指针,需预先分配dataSize内存 + * @return int ERROR_CODE + */ +int bdsp_data_windowed(const double *inputData, const double *windowWeight, int dataSize, double *outputData); + +/** + * @brief 计算滤波器系数 + * + * @param order 滤波阶数 + * @param lowerFreq 下限频率 + * @param UpperFreq 上限频率 + * @param fs 采样频率 + * @param mode 0-NOFILTER,1-HIGHPASS,2-LOWPASS,3-BANDPASS,4-STOP + * @param a den + * @param b num + * @param coeffLength 滤波器系数长度,带阻带通为2*order+1,高通低通为order+1,为order+1 + */ +void bdsp_calc_butter_coeff(int order, double lowerFreq, double upperFreq, double fs, int mode, double *a, double *b, int coeffLength); + +/** + * @brief 执行滤波 + * + * @param inputData 输入数据 + * @param dataSize 数据长度 + * @param b den + * @param a num + * @param coeffLength 滤波器参数长度:带阻带通为2*order+1,高通低通为order+1,为order+1 + * @param outputData 输出结果 + * @return int ERR_CODE + */ +int bdsp_filter(double *inputData, int dataSize, double *b, double *a, int coeffLength, double *outputData); + +#endif diff --git a/lib_bdsp/bdsp_ConvertFFTAmpDB.c b/lib_bdsp/bdsp_ConvertFFTAmpDB.c new file mode 100644 index 0000000000000000000000000000000000000000..c01b0ee256c61865f89ccbadc7f35d6a27f6118e --- /dev/null +++ b/lib_bdsp/bdsp_ConvertFFTAmpDB.c @@ -0,0 +1,21 @@ +/** + * 将FFT幅值转换为分贝值 + * + * @param FFTAmp 输入参数,FFT幅值数组指针 + * @param dBref 输入参数,分贝转换的参考值 + * @param FFTAmpDB 输出参数,转换后的分贝值数组指针 + * @param len 输入参数,数组长度 + * + * @return 返回0表示正常执行完成 + */ +int bdsp_ConvertFFTAmpDB(float *FFTAmp, float dBref, float *FFTAmpDB, int len) +{ + int i; + for(i = 0; i < len; i++) { + /* 将FFT幅值转换为分贝值 + * 计算公式: dB = 20 * log10(幅值/参考值) + */ + FFTAmpDB[i] = 20.0f * log10f(FFTAmp[i] / dBref); + } + return 0; +} \ No newline at end of file diff --git a/lib_bdsp/bdsp_calc_time_eigen.c b/lib_bdsp/bdsp_calc_time_eigen.c new file mode 100644 index 0000000000000000000000000000000000000000..50fb692f1eed0f9b3a551707391b82415d5a5ae9 --- /dev/null +++ b/lib_bdsp/bdsp_calc_time_eigen.c @@ -0,0 +1,163 @@ +#include +#include +#include "bdsp.h" + +// 计算均方根 +float calc_rms(float *x, int dataSize) +{ + float sum = 0.0f; + for (int i = 0; i < dataSize; i++) + { + sum += x[i] * x[i]; + } + return sqrt(sum / dataSize); +} + +// 计算标准差 +float calc_std_dev(float *x, int dataSize) +{ + float mean = 0.0f; + for (int i = 0; i < dataSize; i++) + { + mean += x[i]; + } + mean /= dataSize; + + float sum = 0.0f; + for (int i = 0; i < dataSize; i++) + { + sum += (x[i] - mean) * (x[i] - mean); + } + + return sqrt(sum / (dataSize - 1)); // 使用无偏估计 +} + +// 计算偏度 +float calc_skewness(float *x, int dataSize) +{ + float mean = 0.0f; + for (int i = 0; i < dataSize; i++) + { + mean += x[i]; + } + mean /= dataSize; + + float m3 = 0.0f; + float m2 = 0.0f; + for (int i = 0; i < dataSize; i++) + { + m3 += pow(x[i] - mean, 3); + m2 += pow(x[i] - mean, 2); + } + + m2 /= dataSize; + m3 /= dataSize; + + return m3 / pow(m2, 1.5f); // 偏度公式 +} + +// 计算峭度 +float calc_kurtosis(float *x, int dataSize) +{ + float mean = 0.0f; + for (int i = 0; i < dataSize; i++) + { + mean += x[i]; + } + mean /= dataSize; + + float m4 = 0.0f; + float m2 = 0.0f; + for (int i = 0; i < dataSize; i++) + { + m4 += pow(x[i] - mean, 4); + m2 += pow(x[i] - mean, 2); + } + + m2 /= dataSize; + m4 /= dataSize; + + return m4 / (m2 * m2) - 3.0f; // 峭度公式 +} + +// 计算时域统计量 +int bdsp_calc_time_eigen(float *inputdata, int dataSize, BdspTimeEigen *timeEigen) +{ + + // 最大值 + timeEigen->max = inputdata[0]; + timeEigen->min = inputdata[0]; + float sum = 0.0f; + for (int i = 0; i < dataSize; i++) + { + if (inputdata[i] > timeEigen->max) + { + timeEigen->max = inputdata[i]; + } + if (inputdata[i] < timeEigen->min) + { + timeEigen->min = inputdata[i]; + } + sum += inputdata[i]; + } + + // 平均值 + timeEigen->ave = sum / dataSize; + + // 均值绝对值 + timeEigen->absAve = fabs(timeEigen->ave); + + // 绝对平均幅值 + sum = 0.0f; + for (int i = 0; i < dataSize; i++) + { + sum += fabs(inputdata[i]); + } + timeEigen->absAveAmp = sum / dataSize; + + // 方根幅值 + float root_sum = 0.0f; + for (int i = 0; i < dataSize; i++) + { + root_sum += pow(fabs(inputdata[i]), 2); + } + timeEigen->XFG = sqrt(root_sum / dataSize); + + // 均方根 + timeEigen->rms = rms(inputdata, dataSize); + + // 标准差 + timeEigen->std = std_dev(inputdata, dataSize); + + // 方差 + timeEigen->var = timeEigen->std * timeEigen->std; + + // 峰峰值 + timeEigen->peak2Valley = timeEigen->max - timeEigen->min; + + // 峰值因子 + timeEigen->peakfactor = timeEigen->max / timeEigen->rms; + + // 脉冲因子 + timeEigen->pulsefactor = timeEigen->max / timeEigen->absAveAmp; + + // 裕度因子 + timeEigen->marginFactor = timeEigen->max / timeEigen->XFG; + + // 波形因子 + timeEigen->waveFactor = timeEigen->rms / timeEigen->absAveAmp; + + // 偏度因子 + timeEigen->skewnessFactor = skewness(inputdata, dataSize); + + // 峭度因子 + timeEigen->kurtosisFactor = kurtosis(inputdata, dataSize); + + // 偏度 + timeEigen->skewness = timeEigen->skewnessFactor * pow(timeEigen->std, 3); + + // 峭度 + timeEigen->kurtosis = timeEigen->kurtosisFactor * pow(timeEigen->std, 4); + + return T_SUCCESS; +} diff --git a/lib_bdsp/bdsp_calc_time_intergration.c b/lib_bdsp/bdsp_calc_time_intergration.c new file mode 100644 index 0000000000000000000000000000000000000000..ab0b14a258611c8cb3e1f1159a6381d5ff40a909 --- /dev/null +++ b/lib_bdsp/bdsp_calc_time_intergration.c @@ -0,0 +1,29 @@ +#include +#include "bdsp.h" + +int bdsp_calc_time_intergration(const float *inputData, int dataSize, float sampleRate, float *outputData) +{ + // 参数检查 + if (inputData == NULL || outputData == NULL) + { + return E_EMPTYPOINT; + } + if (dataSize <= 1 || sampleRate <= 0) + { + return E_PARAMINVALID; + } + + // 计算采样时间间隔 + float interval = 1.0f / sampleRate; + + // 设置初始值为0 + outputData[0] = 0.0f; + + // 使用梯形法则计算积分值 + for (int i = 1; i < dataSize; i++) + { + outputData[i] = outputData[i - 1] + 0.5f * interval * (inputData[i - 1] + inputData[i]); + } + + return T_SUCCESS; +} diff --git a/lib_bdsp/bdsp_calc_window_weight.c b/lib_bdsp/bdsp_calc_window_weight.c new file mode 100644 index 0000000000000000000000000000000000000000..072276c8f15cc4e66b42b06d835a6c40238b3522 --- /dev/null +++ b/lib_bdsp/bdsp_calc_window_weight.c @@ -0,0 +1,187 @@ +#include +#include +#include "bdsp.h" + +#define M_PI 3.14159265358979323846 + +static double i0(double x) +{ + // 计算零阶修正贝塞尔函数 + double ax = fabs(x); + double ans; + double y; + + if (ax < 3.75) + { + y = x / 3.75; + y *= y; + ans = 1.0 + y * (3.5156229 + y * (3.0899424 + y * (1.2067492 + y * (0.2659732 + y * (0.0360768 + y * 0.0045813))))); + } + else + { + y = 3.75 / ax; + ans = (exp(ax) / sqrt(ax)) * (0.39894228 + y * (0.01328592 + y * (0.00225319 + y * (-0.00157565 + y * (0.00916281 + y * (-0.02057706 + y * (0.02635537 + y * (-0.01647633 + y * 0.00392377)))))))); + } + return ans; +} + +void bdsp_get_window_compesation_para(int windowType, float winAmpCompesationPara, float winEnergyCompesationPara) +{ + switch (windowType) + { + case RECTANGLE: + winAmpCompesationPara = 1.000000f; + winEnergyCompesationPara = 1.000000f; + break; + case HANN: + winAmpCompesationPara = 2.000000f; + winEnergyCompesationPara = 1.632993f; + break; + case HAMMING: + winAmpCompesationPara = 1.851865f; + winEnergyCompesationPara = 1.586309f; + break; + case BLACKMAN: + winAmpCompesationPara = 2.380972f; + winEnergyCompesationPara = 1.811911f; + break; + case FLATTOP: + winAmpCompesationPara = 4.638709f; + winEnergyCompesationPara = 2.388970f; + break; + case KAISER: + winAmpCompesationPara = 2.480f; + winEnergyCompesationPara = 1.854f; + break; + default: + winAmpCompesationPara = 1.000000f; + winEnergyCompesationPara = 1.000000f; + break; + } +} + +int bdsp_calc_window_weight(int dataSize, int windowType, double windowPara, double *windowWeight) +{ + if (dataSize <= 0) + { + return E_PARAMINVALID; + } + + if (windowWeight == NULL) + { + return E_EMPTYPOINT; + } + + // 处理长度为1的特殊情况 + if (dataSize == 1) + { + windowWeight[0] = 1.0; + } + + // 校验窗口类型有效性 + if (windowType < RECTANGLE || windowType > KAISER) + { + windowType = HANN; + } + + switch (windowType) + { + case RECTANGLE: + { + // 矩形窗 + for (int i = 0; i < dataSize; i++) + { + windowWeight[i] = 1.0; + } + break; + } + case HANN: + { // 汉宁窗 + for (int i = 0; i < dataSize; i++) + { + double angle = 2 * M_PI * i / (dataSize - 1); + windowWeight[i] = 0.5 * (1 - cos(angle)); + } + break; + } + case HAMMING: + { // 海明窗 + for (int i = 0; i < dataSize; i++) + { + double angle = 2 * M_PI * i / (dataSize - 1); + windowWeight[i] = 0.54 - 0.46 * cos(angle); + } + break; + } + case BLACKMAN: + { // 布莱克曼窗 + for (int i = 0; i < dataSize; i++) + { + double angle = 2 * M_PI * i / (dataSize - 1); + windowWeight[i] = 0.42 - 0.5 * cos(angle) + 0.08 * cos(2 * angle); + } + break; + } + case FLATTOP: + { // 平顶窗 + const double a[5] = {0.21557895, 0.41663158, 0.277263158, + 0.083578947, 0.006947368}; + for (int i = 0; i < dataSize; i++) + { + double angle = 2 * M_PI * i / (dataSize - 1); + windowWeight[i] = a[0] - a[1] * cos(angle) + a[2] * cos(2 * angle) - a[3] * cos(3 * angle) + a[4] * cos(4 * angle); + } + break; + } + case KAISER: + { // 凯塞窗 + double beta = windowPara; + double denominator = i0(beta); + double alpha = (dataSize - 1) / 2.0; + + for (int i = 0; i < dataSize; i++) + { + double x = (i - alpha) / alpha; + x = 1 - x * x; // 1 - ((i-alpha)/alpha)^2 + x = (x > 0) ? sqrt(x) : 0; // 防止负值 + double numerator = i0(beta * x); + windowWeight[i] = numerator / denominator; + } + break; + } + } + + return T_SUCCESS; +} + +int bdsp_data_windowed(const double *inputData, const double *windowWeight, int dataSize, double *outputData) +{ + // 检查输入是否有效 + if (inputData == NULL || windowWeight == NULL || outputData == NULL) + { + return E_EMPTYPOINT; + } + if (dataSize <= 0) + { + return E_PARAMINVALID; + } + + // 逐点相乘 + for (int i = 0; i < dataSize; i++) + { + outputData[i] = inputData[i] * windowWeight[i]; + } + + return T_SUCCESS; +} + +// example +// int main() { +// // 生成1024点汉宁窗系数 +// double* window = bdsp_calc_WindowWeight(1024, 1, 0); + +// // 使用窗函数数据... + +// free(window); // 释放内存 +// return 0; +// } \ No newline at end of file diff --git a/lib_bdsp/bdsp_data_restore.c b/lib_bdsp/bdsp_data_restore.c new file mode 100644 index 0000000000000000000000000000000000000000..da74a3374795085b609a490c13f459f9176d6fee --- /dev/null +++ b/lib_bdsp/bdsp_data_restore.c @@ -0,0 +1,34 @@ +#include +#include "bdsp.h" + +int bdsp_data_restore(float *inputData, uint32_t dataSize, float sensitivity, float adjustCoefficient, float offsetValue, float *outputData) +{ + uint32_t i = 0; + // 参数有效性检查 + if (inputData == NULL || outputData == NULL) + { + return E_EMPTYPOINT; // 错误处理:任一指针为空时返回错误码 + } + + if (sensitivity == 0) + { + printf("channel sensitivity is ZERO!"); + return E_PARAMINVALID; + } + + if (adjustCoefficient == 0) + { + printf("channel adjust coeff is ZERO!"); + return E_PARAMINVALID; + } + // 数据恢复计算 + // 1. 原始数据乘以调整系数 + // 2. 除以灵敏度得到物理量 + // 3. 加上偏移值进行零点修正 + for (i = 0; i < dataSize; i++) + { + outputData[i] = adjustCoefficient * inputData[i] / sensitivity + offsetValue; + } + + return T_SUCCESS; // 计算成功返回0 +} \ No newline at end of file diff --git a/lib_bdsp/bdsp_filter.c b/lib_bdsp/bdsp_filter.c new file mode 100644 index 0000000000000000000000000000000000000000..b39f2a4cc8479e2dde87a50f6e5474805ee000a3 --- /dev/null +++ b/lib_bdsp/bdsp_filter.c @@ -0,0 +1,421 @@ +#include +#include +#include +#include +#include "bdsp.h" + +#define PI 3.14159265358979323846 + +// 复数结构体定义 +typedef struct +{ + double real; // 复数的实部 + double imag; // 复数的虚部 +} Complex; + +// 创建复数 +Complex c_Complex(double real, double imag) +{ + Complex z; + z.real = real; + z.imag = imag; + return z; +} + +// 复数加法 +Complex c_add(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real + z2.real; + answer.imag = z1.imag + z2.imag; + return answer; +} + +// 复数减法 +Complex c_sub(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real - z2.real; + answer.imag = z1.imag - z2.imag; + return answer; +} + +// 复数乘法 +Complex c_Mul(Complex z1, Complex z2) +{ + Complex answer; + answer.real = z1.real * z2.real - z1.imag * z2.imag; + answer.imag = z1.real * z2.imag + z1.imag * z2.real; + return answer; +} + +// 复数除法 +Complex c_Div(Complex z1, Complex z2) +{ + Complex answer; + double denominator = z2.real * z2.real + z2.imag * z2.imag; + answer.real = (z1.real * z2.real + z1.imag * z2.imag) / denominator; + answer.imag = (z1.imag * z2.real - z1.real * z2.imag) / denominator; + return answer; +} + +// 计算二项式系数 +void calc_bcof(int n, double *bcof) +{ + int m; + // 计算二项式系数 C(n,k) + bcof[0] = 1; + bcof[1] = n; + m = n / 2; + for (int i = 2; i <= m; ++i) + { + bcof[i] = (n - i + 1) * bcof[i - 1] / i; + bcof[n - i] = bcof[i]; // 利用对称性 + } + bcof[n - 1] = n; + bcof[n] = 1; +} + +// 二项式乘法运算 +void binomial_mult(int n, Complex *p, double *result) +{ + Complex *a = (Complex *)calloc(n + 1, sizeof(Complex)); + + // 初始化系数 + a[0] = c_Complex(1, 0); + a[1] = c_sub(c_Complex(0, 0), p[0]); + + // 计算多项式乘积 + for (int i = 1; i < n; i++) + { + for (int j = i + 1; j > 0; j--) + { + a[j] = c_sub(a[j], c_Mul(a[j - 1], p[i])); + } + } + + // 提取实部作为结果 + for (int i = 0; i < n + 1; i++) + { + result[i] = a[i].real; + } + + free(a); +} + +// 三项式乘法运算 +void trinominal_mult(int n, Complex *p, Complex *q, double *result) +{ + Complex *a = (Complex *)calloc(2 * n + 1, sizeof(Complex)); + + a[0] = c_Complex(1, 0); + a[1] = p[0]; + a[2] = q[0]; + for (int i = 1; i < n; i++) + { + for (int j = 2 * i + 2; j > 1; j--) + { + a[j] = c_add(a[j], c_Mul(a[j - 1], p[i])); + a[j] = c_add(a[j], c_Mul(a[j - 2], q[i])); + } + a[1] = c_add(a[1], p[i]); + } + for (int i = 0; i < 2 * n + 1; i++) + { + result[i] = a[i].real; + } + free(a); +} + +// 低通滤波器设计 +void calc_low(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + Complex Omegap = c_Complex(tan(PI * w[0] / 2), 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + // 双线性变换 + p[i] = c_Div(c_add(c_Complex(1, 0), c_Mul(Omegap, poles)), + c_sub(c_Complex(1, 0), c_Mul(Omegap, poles))); + temp = c_Div(Omegap, c_sub(c_Complex(1, 0), c_Mul(Omegap, poles))); + sf = c_Mul(sf, temp); + } + + // 计算最终的滤波器系数 + binomial_mult(order, p, a); + calc_bcof(order, b); + for (int i = 0; i < order + 1; i++) + { + b[i] = b[i] * sf.real; + } + + free(p); +} + +// 高通滤波器设计 +void calc_high(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + Complex Omegap = c_Complex(tan(PI * w[1] / 2), 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + // 高通变换 + p[i] = c_Div(c_add(poles, Omegap), c_sub(poles, Omegap)); + sf = c_Div(sf, c_sub(Omegap, poles)); + } + + // 计算最终的滤波器系数 + binomial_mult(order, p, a); + calc_bcof(order, b); + for (int i = 0; i < order + 1; i++) + { + if (i % 2 == 1) + { + b[i] = -b[i]; + } + b[i] = b[i] * sf.real; + } + + free(p); +} + +// 带通滤波器设计 +void calc_bandpass(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + double Omega1 = tan(PI * w[0] / 2); + double Omega3 = tan(PI * w[1] / 2); + double c = Omega1 * Omega3; + Complex d = c_Complex(Omega3 - Omega1, 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(order + 1, sizeof(Complex)); + Complex *q = (Complex *)calloc(order + 1, sizeof(Complex)); + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + p[i] = c_Div(c_Complex(2 * c - 2, 0), c_sub(c_Complex(1 + c, 0), c_Mul(poles, d))); + q[i] = c_Div(c_add(c_Complex(c + 1, 0), c_Mul(poles, d)), c_sub(c_Complex(c + 1, 0), c_Mul(poles, d))); + temp = c_Div(d, c_sub(c_Complex(1 + c, 0), c_Mul(poles, d))); + sf = c_Mul(sf, temp); + } + trinominal_mult(order, p, q, a); + calc_bcof(order, b); + for (int i = 2 * order; i > 1; i = i - 2) + { + if ((i / 2) % 2 == 1) + { + b[i] = -b[i / 2] * sf.real; + } + else + { + b[i] = b[i / 2] * sf.real; + } + b[i - 1] = 0.0; + } + b[0] = b[0] * sf.real; + free(p); + free(q); +} + +// 带阻滤波器设计 +void calc_stop(int order, double *a, double *b, double w[2]) +{ + double theta; + Complex poles, temp; + // 计算预畸变频率 + double Omega1 = tan(PI * w[0] / 2); + double Omega3 = tan(PI * w[1] / 2); + double c = Omega1 * Omega3; + Complex d = c_Complex(Omega3 - Omega1, 0); + Complex sf = c_Complex(1, 0); + Complex *p = (Complex *)calloc(2 * order + 1, sizeof(Complex)); + Complex *q = (Complex *)calloc(2 * order + 1, sizeof(Complex)); + + // 计算极点位置和传递函数系数 + Complex tempF; + for (int i = 0; i < order; i++) + { + theta = PI * (2 * i + order + 1) / 2 / order; + poles = c_Complex(cos(theta), sin(theta)); + temp = c_sub(d, c_Mul(poles, c_Complex(1 + c, 0))); + tempF = c_sub(c_sub(c_Complex(0, 0), d), c_Mul(poles, c_Complex(1 + c, 0))); + p[i] = c_Div(c_Mul(c_Complex(2 - 2 * c, 0), poles), temp); + q[i] = c_Div(tempF, temp); + sf = c_Mul(sf, temp); + } + + // 计算最终的滤波器系数 + trinominal_mult(order, p, q, a); + tempF = c_Div(c_Complex(2 * c - 2, 0), c_Complex(1 + c, 0)); + for (int i = 0; i < order; i++) + { + p[i] = tempF; + q[i] = c_Complex(1, 0); + sf = c_Div(sf, c_Complex(c + 1, 0)); + } + trinominal_mult(order, p, q, b); + for (int i = 0; i < 2 * order + 1; i++) + { + b[i] = b[i] / sf.real; + } + free(p); + free(q); +} + +// mode = 1,high; mode = 2, low;mode = 3,bandpass;mode = 4,stop +// 传进来的系数长度:带阻带通为2*order+1,高通低通为order+1,为order+1 + +void bdsp_calc_butter_coeff(int order, double lowerFreq, double upperFreq, double fs, int mode, double *a, double *b, int coeffLength) +{ + double w[2]; // 归一化截止频率 + + w[0] = lowerFreq / (fs / 2); + w[1] = upperFreq / (fs / 2); + + switch (mode) + { + case HIGHPASS: + calc_high(order, a, b, w); + coeffLength = order + 1; + break; + case LOWPASS: + calc_low(order, a, b, w); + coeffLength = order + 1; + break; + case BANDPASS: + calc_bandpass(order, a, b, w); + coeffLength = 2 * order + 1; + break; + case STOP: + calc_stop(order, a, b, w); + coeffLength = 2 * order + 1; + break; + default: + calc_high(order, a, b, w); + coeffLength = order + 1; + } +} + +int bdsp_filter(double *inputData, int dataSize, double *b, double *a, int coeffLength, double *outputData) +{ + if (b == NULL || a == NULL || inputData == NULL || outputData == NULL) + { + return E_EMPTYPOINT; + } + + outputData[0] = 0; + for (int i = 1; i < dataSize; i++) + { + outputData[i] = 0; + for (int j = 0; j < coeffLength && (i - j) >= 0; j++) + { + outputData[i] += b[j] * inputData[i - j]; + } + for (int j = 1; j < coeffLength && (i - j) >= 0; j++) + { + outputData[i] -= a[j] * outputData[i - j]; + } + } + + return T_SUCCESS; +} + +// 示例 +/* +int main() +{ + int order = 4; // 滤波器阶数 + int mode = 3; // 滤波器类型,1为高通,2为低通,3为带通, 4为带阻 + int coeffLength = 2 * order + 1; // 低通和高通为order+1,带阻和带通为2*order+1 + double *a = (double *)calloc(coeffLength, sizeof(double)); + double *b = (double *)calloc(coeffLength, sizeof(double)); + + // 设置截止频率(归一化频率,范围0-1) + double w[2] = {0.3, 0.4}; + + // 计算滤波器系数 + bdsp_butterCoeff(order, a, b, w, mode); + + // 打开文件以保存滤波器系数 + FILE *coeff_file = fopen("filter_coefficients.txt", "w"); + if (coeff_file == NULL) + { + printf("Error opening coefficient file!\n"); + return 1; + } + + // 写入滤波器系数 + fprintf(coeff_file, "分母系数 a[n]:\n"); + for (int i = 0; i <= 2 * order; i++) + { + fprintf(coeff_file, "a[%d] = %.10f\n", i, a[i]); + } + fprintf(coeff_file, "\n分子系数 b[n]:\n"); + for (int i = 0; i <= 2 * order; i++) + { + fprintf(coeff_file, "b[%d] = %.10f\n", i, b[i]); + } + fclose(coeff_file); + + // 示例:处理一些数据 + int dataLength = 1000; + double *input = (double *)malloc(dataLength * sizeof(double)); + double *output = (double *)malloc(dataLength * sizeof(double)); + + // 生成测试信号(例如:正弦波) + for (int i = 0; i < dataLength; i++) + { + input[i] = sin(2 * PI * 0.1 * (i + 1)) + sin(2 * PI * 0.6 * (i + 1)); + } + + // 进行滤波 + + bdsp_filter(coeffLength, b, a, input, output, dataLength); + + // 打开文件以保存滤波后的信号 + FILE *signal_file = fopen("filtered_signal.txt", "w"); + if (signal_file == NULL) + { + printf("Error opening signal file!\n"); + return 1; + } + + // 写入原始信号和滤波后的信号 + fprintf(signal_file, "Sample\tInput\tOutput\n"); + for (int i = 0; i < dataLength; i++) + { + fprintf(signal_file, "%d\t%.10f\t%.10f\n", i, input[i], output[i]); + } + fclose(signal_file); + + // 清理资源 + // freeFilter(filter); + free(input); + free(output); + free(a); + free(b); + + printf("Filter coefficients have been saved to 'filter_coefficients.txt'\n"); + printf("Filtered signal has been saved to 'filtered_signal.txt'\n"); + + return 0; +} +*/ diff --git a/lib_bdsp/dsp_common.h b/lib_bdsp/dsp_common.h new file mode 100644 index 0000000000000000000000000000000000000000..78eed15778f2ec84b57dccae6bea218e5873b0b6 --- /dev/null +++ b/lib_bdsp/dsp_common.h @@ -0,0 +1,14 @@ +#ifndef __DSP_COMMON_H__ +#define __DSP_COMMON_H__ + +typedef unsigned int uint32_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef signed char int8_t; + +#define T_SUCCESS 0 +#define E_PARAMINVALID 1 +#define E_MEMORYFAULT 2 +#define E_EMPTYPOINT 3 + +#endif diff --git a/mdsp_src/dsp.c b/mdsp_src/dsp.c new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/mdsp_src/mdsp.h b/mdsp_src/mdsp.h new file mode 100644 index 0000000000000000000000000000000000000000..61a0c1fb4789cc3433a5bb0ad73392f7b8a02db5 --- /dev/null +++ b/mdsp_src/mdsp.h @@ -0,0 +1,77 @@ +#ifndef __MDSP_H__ +#define __MDSP_H__ +#include "bdsp.h" + +/* -------------------------------------------------------------------------- */ +/* macro */ +/* -------------------------------------------------------------------------- */ +const enum dspFeatureEnums { + TIME_MAX = 0, + TIME_MIN, + TIME_AVE, + TIME_ABS_AVE, + TIME_ABS_AVE_AMP, + TIME_SR_AMP, + TIME_RMS, + TIME_SD, + TIME_VAR, + TIME_PPV, + TIME_CREST_FACTOR, + TIME_CURVE_FACTOR, + TIME_PULSE_FACTOR, + TIME_MARGIN_FACTOR, + TIME_SKEWNESS, + TIME_KURTOSIS, + TIME_SKEWNESS_FACTOR, + TIME_KURTOSIS_FACTOR, + + SPEC_RAWDATA, + SPEC_FFT_AMP, + SPEC_FFT_AMPDB, + SPEC_FFT_PHA, + SPEC_FFT_PWR, + SPEC_VELOCITY, + SPEC_DISPLACEMENT, + + FREQ_AMP_AVG, + FREQ_FC, + FREQ_MSF, + FREQ_AMP_VAR, + FREQ_AMP_STD, + FREQ_AMP_SKEWNESS, + FREQ_AMP_KURTOSIS, + FREQ_RMSF, + FREQ_FVAR, + FREQ_FSTD, + FREQ_FSIGMA, + FREQ_FSKEWNESS, + FREQ_FKURTOSIS, + FREQ_FSQRT, + FREQ_BASE_PHA, + FREQ_FEATURE_VALUE, + FREQ_PEAK_VALUE, + + FREQ_TOTALDB, + FREQ_HIGHDB, + FREQ_LOWDB, + FREQ_OCTAVE, + FREQ_VELOCITY_RMS, + FREQ_DISPLACEMENT_RMS, + INTENSITY, + FEATURE_END +}; + +/* -------------------------------------------------------------------------- */ +/* function */ +/* -------------------------------------------------------------------------- */ +/** + * @brief + * + * @param inputData 输入时域数据 + * @param dataSize 输入数据长度 + * @param dspConfig 下发配置结构体 + * @return int 初始化结果 + */ +int mdsp_ctx_init(const float *inputData, uint32_t dataSize, DspConfig *dspConfig); + +#endif diff --git a/mdsp_src/mdsp_config.h b/mdsp_src/mdsp_config.h new file mode 100644 index 0000000000000000000000000000000000000000..dcc2aeba8bde90108972d955d48d25cfb9f45762 --- /dev/null +++ b/mdsp_src/mdsp_config.h @@ -0,0 +1,73 @@ +#ifndef __DSP_CONFIG_H__ +#define __DSP_CONFIG_H__ +#include "mdsp.h" + +typedef struct _ChannelProperty +{ + uint32_t sampleMode; // ģʽ0-ʱ1-ȽǶȲ + uint32_t signalType; // źͣ0-źţ1-źţ2-źţ3-תźţ4- +} ChannelProperty; + +typedef struct _ChannelRestoreCoeff +{ + float adjustCoeff; + float offsetValue; + float sensitvity; +} ChannelRestoreCoeff; + +typedef struct _DspFilterConfig +{ + uint32_t filterType; // ˲ + uint32_t filterOrder; // ˲ + float filterLowerFreq; // ˲޽ֹƵ + float filterUpperFreq; // ˲޽ֹƵ +} DspFilterConfig; + +typedef struct _DspFeatFreqConfig +{ + uint32_t featureNumber; // Ԥ + float *featureFreqs; // ԤƵ +} DspFeatFreqConfig; + +typedef struct _DspFindPeakConfig +{ + uint32_t peakNumbers; // Ѱ + float minPeakHeight; // 趨ֵС߶ + uint32_t minPeakDistance; // 趨ֵС +} DspFindPeakConfig; + +/* ԤƵ */ +struct DspFrequencyChoice +{ + float analyzeLowerFreq; // Ƶ + float analyzeUpperFreq; // Ƶ +}; + +typedef struct _DspProcessingConfig +{ + uint32_t sensorAxis; // װ0-x1-y2-z + uint32_t sampleRate; // + float analyzeLowerFreq; // Ƶ + float analyzeUpperFreq; // Ƶ + DspFilterConfig FilterConfig; // ˲ + uint32_t windowType; // + uint32_t octaveType; // Ƶ + uint32_t weightingType; // Ȩ + uint32_t timeIntergralTimes; // ʱִ + uint32_t FreqIntergralTimes; // Ƶִ + uint32_t averageType; // Ƶƽͣ0-ƽ1-ƽ2-ָƽ3-ֵ + uint32_t averageTimes; // ƽ + float rpm; // תƵ/Ƶ + DspFeatFreqConfig featFreqConfig; // Ƶʼ + DspFindPeakConfig findPeakConfig; // Ѱ㷨 +} DspProcessingConfig; + +typedef struct _DspConfig +{ + ChannelProperty channelProperty; + ChannelRestoreCoeff channelRestoreCoeff; + DspProcessingConfig dspProcessingConfig; + uint8_t dspEnableFlags[FEATURE_END - 1]; +} DspConfig; + +#endif diff --git a/mdsp_src/mdsp_ctx.h b/mdsp_src/mdsp_ctx.h new file mode 100644 index 0000000000000000000000000000000000000000..af752533ef9a01801d25382be2d5169cab3404d8 --- /dev/null +++ b/mdsp_src/mdsp_ctx.h @@ -0,0 +1,92 @@ +#ifndef __MDSP_CTX_H__ +#define __MDSP_CTX_H__ + +#include "./mdsp_config.h" + +typedef struct _DspSinspecData +{ + /* ͨ */ + float *timeData; // ԭʼ + float *fftAmp; // FFTֵ + float *fftPha; // FFTλ + float *fftPwr; // + float *fftCeps; // + /* */ + float *velocityFFTAmp; // ٶ + float *distanceFFTAmp; // λ +} DspSinspecData; + +typedef struct _DspTimeEigenData +{ + /* ͨ */ + float timeMax; + float timeMin; + float timeAve; + float timeAbsAve; + float timeAbsAveAmp; + float timeSrAmp; + float timeRms; + float timeSd; + float timeVar; + float timePpv; + float timeCrestFactor; + float timeCurveFactor; + float timePulseFactor; + float timeMarginFactor; + float timeSkewness; + float timeKurtosis; + float timeSkewnessFactor; + float timeKurtosisFactor; + + /* λ */ + // DisTimeEigen *dis_time_eigen; + /* ٶ */ + // AccTimeEigen *acc_time_eigen; + /* */ + // SoundTimeEigen *sound_time_eigen; + /* ų */ + // MagTimeEigen *mag_time_eigen; + /* ӦӦ */ +} DspTimeEigenData; + +typedef struct _DspFreqEigenData +{ + +} DspFreqEigenData; + +typedef struct _DspOutput +{ + DspSinspecData *sinSpecData; + DspTimeEigenData *timeEigenData; + DspFreqEigenData *freqEigenData; +} DspOutput; + +typedef struct _DspFilterCoeff +{ + float *b; + float *a; + uint32_t coeffLength; +} DspFilterCoeff; + +typedef struct _DspWindowParams +{ + float winAmpCompesationPara; // ֵϵ + float winEnergyCompesationPara; // ϵ + float *windowCoeff; // ϵ +} DspWindowParams; + +typedef struct _DspContext +{ + uint32_t dataSize; + uint32_t fftLines; + float *timeData; + float *fftReals; + float *fftImags; + float *fftAmp; + float *fftPower; + DspConfig *dspConfig; + DspFilterCoeff *filterParams; + DspWindowParams *windowParams; +} DspContext; + +#endif diff --git a/mdsp_src/mdsp_init.c b/mdsp_src/mdsp_init.c new file mode 100644 index 0000000000000000000000000000000000000000..b0feca30a7d00208f317fab191bde199c1ab571b --- /dev/null +++ b/mdsp_src/mdsp_init.c @@ -0,0 +1,70 @@ +#include "mdsp.h" +#include "mdsp_ctx.h" +#include + +/* ת */ +static int mdsp_ctx_get_config(const DspConfig *dspConfig) +{ +} + +int mdsp_ctx_init(const float *inputData, uint32_t dataSize, const DspConfig *dspConfig, DspContext *dspContext) +{ + int err_code = T_SUCCESS; + + dspContext->dataSize = dataSize; + dspContext->fftLines = (uint32_t)dataSize / 2; + dspContext->timeData = (float *)malloc(dspContext->dataSize * sizeof(float)); + if (dspContext->timeData == NULL) + { + printf("ctx timedata memory error!\n"); + return E_MEMORYFAULT; + } + + dspContext->fftReals = (float *)malloc(dspContext->dataSize * sizeof(float)); + if (dspContext->fftImags == NULL) + { + printf("ctx fftimags memory error!\n"); + return E_MEMORYFAULT; + } + + dspContext->fftImags = (float *)malloc(dspContext->dataSize * sizeof(float)); + if (dspContext->fftImags == NULL) + { + printf("ctx fftimags memory error!\n"); + return E_MEMORYFAULT; + } + + dspContext->fftAmp = (float *)malloc(dspContext->fftLines * sizeof(float)); + if (dspContext->fftAmp == NULL) + { + printf("ctx fftamp memory error!\n"); + return E_MEMORYFAULT; + } + + dspContext->fftPower = (float *)malloc(dspContext->fftLines * sizeof(float)); + if (dspContext->fftPower == NULL) + { + printf("ctx fftamp memory error!\n"); + return E_MEMORYFAULT; + } + + DspProcessingConfig *initConfig = &(dspContext->dspConfig->dspProcessingConfig); + // if (dspContext->dspConfig->dspProcessingConfig.FilterConfig.filterType == HIGHPASS) + // { + /* ˲ϵ */ + + bdsp_calc_butter_coeff(initConfig->FilterConfig.filterOrder, + (double)initConfig->FilterConfig.filterLowerFreq, + (double)initConfig->FilterConfig.filterUpperFreq, + initConfig->sampleRate, + initConfig->FilterConfig.filterType, + dspContext->filterParams->a, + dspContext->filterParams->b, + dspContext->filterParams->coeffLength); + // } + + dspContext->windowParams->windowCoeff = (float *)malloc(dspContext->dataSize * 4); + /* ɴϵ */ + err_code = bdsp_calc_window_weight(dspContext->dataSize, initConfig->windowType, 1, dspContext->windowParams->windowCoeff); + bdsp_get_window_compesation_para(initConfig->windowType, dspContext->windowParams->winAmpCompesationPara, dspContext->windowParams->winEnergyCompesationPara); +} diff --git a/mdsp_src/mdsp_process.c b/mdsp_src/mdsp_process.c new file mode 100644 index 0000000000000000000000000000000000000000..0343ae21b0ff285087596c58598cedcc12c64af7 --- /dev/null +++ b/mdsp_src/mdsp_process.c @@ -0,0 +1,65 @@ +#include "lib_bdsp/bdsp.h" +#include "mdsp_ctx.h" +#include "mdsp.h" + +int mdsp_data_restore(DspContext *ctx, DspOutput *dspOutput) +{ + int ret; + + ret = bdsp_data_restore(ctx->timeData, ctx->dataSize, + ctx->dspConfig->channelRestoreCoeff.sensitvity, + ctx->dspConfig->channelRestoreCoeff.adjustCoeff, + ctx->dspConfig->channelRestoreCoeff.offsetValue, + ctx->timeData); + + return ret; +} + +int mdsp_data_filter(DspContext *ctx, DspOutput *dspOutput) +{ +} + +int mdsp_calc_time_eigen_data(DspContext *ctx, DspOutput *dspOutput) +{ + int ret; + BdspTimeEigen timeEigen; + + bdsp_calc_time_eigen(ctx->timeData, ctx->dataSize, &timeEigen); + if (ctx->dspConfig->dspEnableFlags[TIME_MAX]) + { + dspOutput->timeEigenData->timeMax = timeEigen.max; + } + if (ctx->dspConfig->dspEnableFlags[TIME_MIN]) + { + dspOutput->timeEigenData->timeMin = timeEigen.min; + } + if (ctx->dspConfig->dspEnableFlags[TIME_AVE]) + { + dspOutput->timeEigenData->timeAve = timeEigen.ave; + } + if (ctx->dspConfig->dspEnableFlags[TIME_AVE]) + { + dspOutput->timeEigenData->timeAve = timeEigen.ave; + } +} + +int mdsp_calc_time_intergration(DspContext *ctx, DspOutput *dspOutput) +{ + int ret; + + if (ctx->dspConfig->dspProcessingConfig.FreqIntergralTimes == 1) + { + // if (dspOutput->sinSpecData->velocityFFTAmp) + } +} + +int mdsp_data_windowing(DspContext *ctx, DspOutput *dspOutput) +{ +} + +int mdsp_data_process(DspContext *ctx, DspOutput *dspOutput) +{ + mdsp_data_restore(ctx, dspOutput); + + +} \ No newline at end of file