目录
前置说明
1 全局参数头文件 global_param.h 新增波形 / FFT 相关定义
2 SPI 底层新增读取整周期原始波形 fpga_spi.h/fpga_spi.c
fpga_spi.h 新增接口声明
fpga_spi.c 波形读取实现
3 FFT 基波提取独立模块 fft_meter.c/fft_meter.h
fft_meter.h
fft_meter.c 完整 FFT 运算 + 计量算法
4 主函数 main.c 整合 FFT 校准检定分支
5 Flash 校准参数存储 ct_cal_flash.c 不变(复用原有)
6 工程关键配置要点(保证 FFT 精度与实时性)
7 计量逻辑说明(完全基于原始采样,无 FPGA 预处理数据参与)
前置说明
- 硬件链路:FPGA
ad4134_spi_capture_opt输出ch_data[0~5]6 通道 24bit 有符号原始采样,一周期点数PERIOD_POINTS=1024/512/256; - 依赖库:ARM CMSIS-DSP 硬件 FFT 浮点库,STM32H7 开启 FPU 双精度;
- 计量逻辑:读取整周期原始波形 → FFT 提取 50Hz 基波幅值 / 相位 → JJG169-2010 计算比值误差、相位角差 → 温漂线性补偿;
- 双模式兼容:主线快速检定使用 FPGA 预处理 IQ 幅值相位,溯源校准模式使用原始波形 FFT 独立计算做比对校验。
1 全局参数头文件 global_param.h 新增波形 / FFT 相关定义
#ifndef GLOBAL_PARAM_H #define GLOBAL_PARAM_H #include "stdint.h" #include "math.h" #include "arm_math.h" // 与FPGA顶层严格同步三档采样点数 #define SAMPLE_256 256 #define SAMPLE_512 512 #define SAMPLE_1024 1024 #define PERIOD_POINTS SAMPLE_1024 // 0.02级互感器检定误差阈值 JJG169 #define FI_LIMIT 0.02f #define DELTA_LIMIT 1.0f // 6工位互感器定义 #define STATION_NUM 6 #define FPGA_FRAME_LEN 32 #define PHASE_MAX 65536U #define RAD_TO_MIN 3437.7468f // FFT最大缓存长度 #define SAMPLE_MAX_LEN 1024 // 单工位校准参数结构体 typedef struct{ float rated_kn; // 额定变比 float k_f; // 比差温漂系数 %/℃ float k_delta; // 角差温漂系数 '/℃ float fi_offset; // 固定比差偏移 float delta_offset; // 固定角偏移 }CT_Cal_t; // FFT基波提取结果 typedef struct{ float32_t amp; // 基波幅值 float32_t phase; // 基波相位 [-π,π] rad }FFT_Result_t; // 主线FPGA预处理检定结果 typedef struct{ uint8_t valid; float fi; float delta_min; uint16_t mag_x; uint16_t ph_x; float temp; uint8_t is_pass; }CT_Result_t; extern CT_Cal_t ct_cal[STATION_NUM]; extern CT_Result_t ct_res[STATION_NUM]; extern float env_temp; extern uint16 std_mag; extern uint16 std_ph; // FFT全局缓存 extern int32_t raw_wave_buf[STATION_NUM][SAMPLE_MAX_LEN]; extern FFT_Result_t fft_res[STATION_NUM]; // DSP FFT全局句柄 extern arm_cfft_instance_f32 fft_handle; extern float32_t fft_in_buf[SAMPLE_MAX_LEN]; extern float32_t fft_mag_buf[SAMPLE_MAX_LEN/2]; #endif2 SPI 底层新增读取整周期原始波形 fpga_spi.h/fpga_spi.c
fpga_spi.h 新增接口声明
// 读取指定工位一整周期PERIOD_POINTS点24bit原始采样波形 HAL_StatusTypeDef FPGA_ReadRawWave(uint16_t station, int32_t *wave_out);fpga_spi.c 波形读取实现
HAL_StatusTypeDef FPGA_ReadRawWave(uint16_t station, int32_t *wave_out) { if(FPGA_SPI_SendReq(CMD_READ_RAW, station) != HAL_OK) { return HAL_ERROR; } uint16_t point_cnt = 0; uint16_t frame_offset = 4; // 循环解析SPI帧内24bit采样数据,填充整周期波形 while(point_cnt < PERIOD_POINTS) { if(frame_offset + 2 >= FPGA_FRAME_LEN) { if(FPGA_SPI_SendReq(CMD_READ_RAW, station) != HAL_OK) return HAL_ERROR; frame_offset = 4; } // 拼接24bit有符号采样:3字节大端 int32_t raw_24 = ((int32_t)rx_buf[frame_offset+2] << 16) | ((int32_t)rx_buf[frame_offset+1] << 8) | rx_buf[frame_offset]; // 24bit符号扩展至32bit if(raw_24 & 0x00800000) raw_24 |= 0xFF000000; wave_out[point_cnt++] = raw_24; frame_offset += 3; } return HAL_OK; }3 FFT 基波提取独立模块 fft_meter.c/fft_meter.h
fft_meter.h
#ifndef FFT_METER_H #define FFT_METER_H #include "global_param.h" // 初始化FFT句柄,程序启动调用一次 void FFT_Init_Handle(void); // 输入32bit原始波形数组,输出50Hz基波幅值、相位 void FFT_Calc_Fundamental(int32_t *wave_in, FFT_Result_t *fft_out); // 基于FFT基波结果计算补偿后比差 % float Calc_RatioError_FFT(float32_t std_amp, float32_t test_amp, uint16_t st, float temp); // 基于FFT基波相位计算补偿后角差 单位:分 ' float Calc_PhaseDelta_FFT(float32_t std_phase, float32_t test_phase, uint16_t st, float temp); // 0.02级合格判定 uint8_t Check002Class_FFT(float fi, float delta); #endiffft_meter.c 完整 FFT 运算 + 计量算法
#include "fft_meter.h" arm_cfft_instance_f32 fft_handle; float32_t fft_in_buf[SAMPLE_MAX_LEN]; float32_t fft_mag_buf[SAMPLE_MAX_LEN/2]; void FFT_Init_Handle(void) { arm_cfft_init_f32(&fft_handle, PERIOD_POINTS); } void FFT_Calc_Fundamental(int32_t *wave_in, FFT_Result_t *fft_out) { uint16_t i; // 1. 24bit有符号原始采样转浮点FFT输入 for(i = 0; i < PERIOD_POINTS; i++) { fft_in_buf[i] = (float32_t)wave_in[i]; } // 2. 复数FFT运算(实数输入,虚部初始0) arm_cfft_f32(&fft_handle, fft_in_buf, 0, 1); // 3. 计算各频点幅值 arm_cmplx_mag_f32(fft_in_buf, fft_mag_buf, PERIOD_POINTS / 2); // 采样率 Fs = 50 * PERIOD_POINTS,频率分辨率 F_res = Fs / PERIOD_POINTS = 50Hz // 0:直流分量,1:50Hz基波 uint16_t fund_idx = 1; float32_t I = fft_in_buf[2 * fund_idx]; float32_t Q = fft_in_buf[2 * fund_idx + 1]; // 4. 基波幅值、反正切相位 fft_out->amp = sqrtf(I * I + Q * Q); fft_out->phase = atan2f(Q, I); // [-π, π] } // JJG169-2010 比差公式 FFT波形版 float Calc_RatioError_FFT(float32_t std_amp, float32_t test_amp, uint16_t st, float temp) { float Kn = ct_cal[st].rated_kn; float fi_raw = (Kn * std_amp - test_amp) / test_amp * 100.0f; // 温漂线性补偿 + 出厂固定偏移 float fi_comp = fi_raw + ct_cal[st].k_f * temp + ct_cal[st].fi_offset; return fi_comp; } // 相位差换算角差(单位分) float Calc_PhaseDelta_FFT(float32_t std_phase, float32_t test_phase, uint16_t st, float temp) { float delta_rad = std_phase - test_phase; // 相位区间修正 [-π, π],消除0/2π跳变 if(delta_rad > M_PI) delta_rad -= 2.0f * M_PI; if(delta_rad < -M_PI) delta_rad += 2.0f * M_PI; // 弧度转分 float delta_min = delta_rad * RAD_TO_MIN; // 温漂+出厂偏移补偿 float delta_comp = delta_min + ct_cal[st].k_delta * temp + ct_cal[st].delta_offset; return delta_comp; } uint8_t Check002Class_FFT(float fi, float delta) { if(fi > FI_LIMIT || fi < -FI_LIMIT) return 0; if(delta > DELTA_LIMIT || delta < -DELTA_LIMIT) return 0; return 1; }4 主函数 main.c 整合 FFT 校准检定分支
#include "fft_meter.h" // 全局波形缓存 int32_t raw_wave_buf[STATION_NUM][SAMPLE_MAX_LEN]; FFT_Result_t fft_res[STATION_NUM]; int main(void) { // CubeMX初始化省略 CT_Cal_FlashLoad(); FFT_Init_Handle(); // 初始化FFT硬件句柄 HAL_TIM_Base_Start_IT(&htim8); TFT_Init(); while(1) { ETH_UploadTask(); PrintTask(); // 校准模式按键触发:读取原始波形FFT双路比对 if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0) == GPIO_PIN_RESET) { Run_FFT_Calibration_Mode(); } HAL_Delay(10); } } // 校准模式:读取6通道原始波形,FFT独立计算误差,与FPGA结果比对 void Run_FFT_Calibration_Mode(void) { uint16_t st; // 1. 读取6工位一周期原始24bit采样波形 for(st = 0; st < STATION_NUM; st++) { if(FPGA_ReadRawWave(st, raw_wave_buf[st]) != HAL_OK) { continue; } // 2. FFT提取基波幅值相位 FFT_Calc_Fundamental(raw_wave_buf[st], &fft_res[st]); } // 标准通道(工位0)基波基准 float32_t fft_std_amp = fft_res[0].amp; float32_t fft_std_ph = fft_res[0].phase; // 3. 循环计算6工位FFT比差、角差 for(st = 0; st < STATION_NUM; st++) { float fi_fft = Calc_RatioError_FFT(fft_std_amp, fft_res[st].amp, st, env_temp); float delta_fft = Calc_PhaseDelta_FFT(fft_std_amp, fft_res[st].phase, st, env_temp); uint8_t pass = Check002Class_FFT(fi_fft, delta_fft); // 存入缓存,屏幕/上位机双路比对显示 TFT_Show_FFT_Compare(st, fi_fft, delta_fft, pass); ETH_Save_FFT_Result(st, fi_fft, delta_fft); } } // TIM8 100ms主线检定(原有FPGA预处理方案不变) void TIM8_UP_IRQHandler(void) { // 原有主线代码省略,不改动实时检定逻辑 }5 Flash 校准参数存储 ct_cal_flash.c 不变(复用原有)
6 工程关键配置要点(保证 FFT 精度与实时性)
- CubeMX 内核配置
- 内核时钟 480MHz,开启 L1 I/D Cache;
- FPU:双精度浮点
fpv5_dp; - 添加 CMSIS-DSP 库,全局宏定义
ARM_MATH_DSP;
- 编译器宏编译选项添加:
-mfloat-abi=hard -mfpu=fpv5-dp-dp -DARM_MATH_DSP - 内存分配FFT 大缓存
fft_in_buf/raw_wave_buf放置外部 FMC SRAM,避免 RAM 溢出; - 两种工作模式分工
- 正常检定:使用 FPGA 预处理
iq_mag/phase_out,100ms 快速刷新界面; - 溯源校准 / 出厂标定:按键触发 FFT 模式,基于原始 24bit 波形独立计算,与 FPGA 结果比对,验证整机 0.02 级精度。
- 正常检定:使用 FPGA 预处理
7 计量逻辑说明(完全基于原始采样,无 FPGA 预处理数据参与)
- 数据源头:FPGA AD4134 24bit 差分原始采样,无 FPGA 内部解调、滤波、CORDIC 处理;
- 频谱提取:STM32 硬件 FFT 提取 50Hz 工频基波,自动滤除 3/5/7 次谐波干扰;
- 幅值相位:纯软件反正切、开方计算,独立一套计量链路;
- 误差标准:严格遵循 JJG169-2010 电流互感器检定规程公式;
- 温漂补偿:复用同一套多点标定温漂系数,抵消互感器与模拟电路温度漂移;
- 双路校验:FFT 软件计算结果与 FPGA 硬件锁相结果同时显示,用于整机精度溯源标定。