脉冲信号分析报告

- **分析日期**: 2026-02-23 - **分析人员**: 系统优化团队

2026-07-04
脉冲信号信号分析方波PWM

50-4000Hz脉冲信号技术分析与计算

文档信息


1. 脉宽测量系统设计

1.1 系统架构

1.1.1 硬件配置

┌─────────────────────────────────────────────────────────┐
│ 脉宽测量系统架构                                  │
├─────────────────────────────────────────────────────────┤
│                                                 │
│ 1. 输入信号 → 比较器 (COMP2) → 中断触发           │
│                                                 │
│ 2. 定时器 (TIM22) → 脉宽测量                      │
│    - 时钟源: 8MHz                                 │
│    - 预分频: 79                                    │
│    - 计数频率: 100kHz (1μs分辨率)                 │
│    - 计数范围: 0-65535                            │
│                                                 │
│ 3. 中断处理 (ADC1_COMP_IRQHandler)                │
│    - 读取TIM22计数值                               │
│    - 清零TIM22计数器                               │
│    - 存储脉宽数据                                  │
│                                                 │
│ 4. 数据处理 (main loop)                           │
│    - 滤波处理                                      │
│    - 频率计算                                      │
│    - 流量转换                                      │
│                                                 │
└─────────────────────────────────────────────────────────┘
1.1.2 定时器配置

TIM22配置:


htim22.Instance = TIM22;
htim22.Init.Prescaler = 79;           // 预分频
htim22.Init.CounterMode = TIM_COUNTERMODE_UP;
htim22.Init.Period = 65535;           // 自动重装载值
htim22.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;

时钟计算:


系统时钟: 8MHz
预分频: 79
计数频率 = 8MHz / (79 + 1) = 100kHz
时间分辨率 = 1 / 100kHz = 10μs

脉宽测量范围:


最小脉宽: 50计数器值 = 50 × 10μs = 500μs
最大脉宽: 2000计数器值 = 2000 × 10μs = 20000μs = 20ms

频率范围:


最小频率 = 1 / 最大脉宽 = 1 / 20ms = 50Hz
最大频率 = 1 / 最小脉宽 = 1 / 500μs = 2000Hz

1.2 测量误差分析

1.2.1 量化误差

量化误差来源:

量化误差计算:


时间分辨率: Δt = 10μs
量化误差: ±Δt/2 = ±5μs

相对误差:
- 50Hz (20ms): ±5μs / 20ms = ±0.025%
- 2000Hz (500μs): ±5μs / 500μs = ±1%

量化误差对频率测量的影响:


频率计算公式: f = 1 / T

频率误差: Δf ≈ -ΔT / T²

50Hz时: Δf ≈ ±5μs / (20ms)² = ±1.25Hz
2000Hz时: Δf ≈ ±5μs / (500μs)² = ±20Hz
1.2.2 触发抖动

触发抖动来源:

触发抖动分析:


比较器响应时间: ~100ns
中断响应延迟: ~1-5μs
信号边沿噪声: ~1-2μs

总触发抖动: ~2-7μs

触发抖动对测量的影响:


抖动误差: ±3.5μs (平均值)

50Hz时: ±3.5μs / 20ms = ±0.0175%
2000Hz时: ±3.5μs / 500μs = ±0.7%
1.2.3 噪声干扰

噪声类型:

  1. 电磁干扰 (EMI)
  1. 电源噪声
  1. 量化噪声

噪声抑制措施:


1. 硬件滤波:
   - RC低通滤波
   - 差分输入

2. 软件滤波:
   - 中值滤波 (len=8)
   - 移动平均滤波 (len=8)
   - 异常值检测

3. 信号处理:
   - 脉宽范围验证 (50-2000)
   - 基线更新机制
1.2.4 总误差分析

误差合成:


总误差 = √(量化误差² + 触发抖动² + 噪声误差²)

50Hz时:
量化误差: ±0.025%
触发抖动: ±0.0175%
噪声误差: ±0.05% (估计)
总误差: ±0.058%

2000Hz时:
量化误差: ±1%
触发抖动: ±0.7%
噪声误差: ±1.5% (估计)
总误差: ±1.9%

误差分布:

频率 量化误差 触发抖动 噪声误差 总误差
50Hz ±0.025% ±0.0175% ±0.05% ±0.058%
100Hz ±0.05% ±0.035% ±0.07% ±0.09%
500Hz ±0.25% ±0.175% ±0.35% ±0.45%
1000Hz ±0.5% ±0.35% ±0.7% ±0.89%
2000Hz ±1% ±0.7% ±1.5% ±1.9%

1.3 时间分辨率要求

1.3.1 分辨率需求分析

目标精度: ±1% (全频率范围)

所需时间分辨率:


频率误差要求: Δf/f ≤ 1%

根据 Δf ≈ -ΔT / T²
得: ΔT ≤ T² × 1%

50Hz (T=20ms):
ΔT ≤ (20ms)² × 1% = 4ms × 0.01 = 40μs

2000Hz (T=500μs):
ΔT ≤ (500μs)² × 1% = 250μs² × 0.01 = 2.5μs

结论:

1.3.2 精度指标

系统精度指标:

指标 要求 当前 评价
时间分辨率 ≤10μs 10μs ✅ 满足
测量精度 ±1% ±0.058-1.9% ⚠️ 高频段略差
频率范围 50-4000Hz 50-2000Hz ⚠️ 范围不足
响应时间 ≤100ms ~10-20ms ✅ 满足
稳定性 ±0.5% ±0.1-0.5% ✅ 满足

2. 频率计算方法

2.1 算法分析

2.1.1 周期测量法

原理:


频率 = 1 / 周期
f = 1 / T

当前实现:


uint32_t calculate_frequency_from_pulse(uint16_t pulse_width)
{
  if (!validate_pulse_width(pulse_width)) return 0;

  uint32_t frequency = 0;
  uint64_t temp = 10000000ULL;
  temp = temp / pulse_width;
  frequency = (uint32_t)(temp / 100);

  if (frequency < 1) frequency = 0;
  if (frequency > 100000) frequency = 100000;

  return frequency;
}

公式推导:


pulse_width: 计数器值 (单位: 10μs)
实际脉宽 = pulse_width × 10μs

频率 = 1 / (pulse_width × 10μs)
     = 1 / (pulse_width × 10⁻⁵s)
     = 10⁵ / pulse_width
     = 100000 / pulse_width

代码实现:
temp = 10000000 / pulse_width
frequency = temp / 100 = 100000 / pulse_width

示例计算:


pulse_width = 100:
frequency = 100000 / 100 = 1000Hz

pulse_width = 500:
frequency = 100000 / 500 = 200Hz

pulse_width = 2000:
frequency = 100000 / 2000 = 50Hz
2.1.2 脉冲计数法

原理:


频率 = 脉冲计数 / 计数时间
f = N / T_count

实现方法:


uint32_t calculate_frequency_by_counting(uint32_t pulse_count, uint32_t count_time_us)
{
  if (count_time_us == 0) return 0;

  uint32_t frequency = (pulse_count * 1000000) / count_time_us;
  return frequency;
}

示例计算:


计数时间: 100ms = 100000μs
脉冲计数: 50个
频率 = 50 / 0.1s = 500Hz
2.1.3 算法对比
算法 测量精度 响应速度 计算复杂度 适用场景
周期测量法 高 (低频) 快 (单周期) O(1) 低频段
周期测量法 低 (高频) 快 (单周期) O(1) 高频段
脉冲计数法 高 (高频) 慢 (多周期) O(1) 高频段
脉冲计数法 低 (低频) 慢 (多周期) O(1) 低频段

精度分析:

周期测量法精度:


Δf/f = ΔT/T

低频段 (50Hz, T=20ms):
Δf/f = ±10μs / 20ms = ±0.05%

高频段 (2000Hz, T=500μs):
Δf/f = ±10μs / 500μs = ±2%

脉冲计数法精度:


Δf/f = ΔN/N

计数时间: 100ms
低频段 (50Hz):
N = 50Hz × 0.1s = 5个脉冲
Δf/f = ±1/5 = ±20%

高频段 (2000Hz):
N = 2000Hz × 0.1s = 200个脉冲
Δf/f = ±1/200 = ±0.5%

2.2 最优方案确定

2.2.1 混合算法

设计思路:


低频段 (50-500Hz): 使用周期测量法
高频段 (500-4000Hz): 使用脉冲计数法

切换阈值: 500Hz

实现方案:


uint32_t calculate_frequency_optimal(uint16_t pulse_width, uint32_t pulse_count, uint32_t count_time_us)
{
  // 估算频率
  uint32_t estimated_freq = 100000 / pulse_width;

  // 低频段: 使用周期测量法
  if (estimated_freq < 500)
  {
    return calculate_frequency_from_pulse(pulse_width);
  }
  // 高频段: 使用脉冲计数法
  else
  {
    return calculate_frequency_by_counting(pulse_count, count_time_us);
  }
}
2.2.2 性能评估

混合算法性能:

频率范围 算法 精度 响应时间
50-100Hz 周期测量 ±0.05-0.1% 10-20ms
100-500Hz 周期测量 ±0.1-0.5% 2-10ms
500-2000Hz 脉冲计数 ±0.5-1% 100ms
2000-4000Hz 脉冲计数 ±0.5-1% 100ms

优化建议:

  1. 低频段(50-500Hz): 使用周期测量法,响应快,精度高
  2. 高频段(500-4000Hz): 使用脉冲计数法,精度高,响应慢
  3. 切换阈值: 500Hz,平衡精度和响应时间

2.3 实时性分析

2.3.1 响应时间

周期测量法:


响应时间 = 单个脉冲周期

50Hz: 20ms
100Hz: 10ms
500Hz: 2ms
2000Hz: 0.5ms

脉冲计数法:


响应时间 = 计数时间窗口

固定窗口: 100ms
自适应窗口: 根据频率调整
2.3.2 计算复杂度

周期测量法:


时间复杂度: O(1)
空间复杂度: O(1)
计算时间: ~1-2μs

脉冲计数法:


时间复杂度: O(1)
空间复杂度: O(1)
计算时间: ~1-2μs

结论: 两种算法计算复杂度相同,实时性都很好


3. 滤波器设计与实现

3.1 滤波器类型选择

3.1.1 噪声特性分析

主要噪声源:

  1. 工频干扰
  1. 电磁干扰 (EMI)
  1. 量化噪声
  1. 传感器噪声
3.1.2 滤波器类型对比
滤波器类型 优点 缺点 适用场景
低通滤波 抑制高频噪声 可能引入延迟 通用
带通滤波 抑制带外噪声 设计复杂 特定频段
中值滤波 抑制脉冲噪声 计算量大 脉冲噪声
移动平均 平滑效果好 延迟较大 随机噪声
卡尔曼滤波 最优估计 参数调整复杂 动态系统

推荐方案: 组合滤波器


第一级: 中值滤波 (抑制脉冲噪声)
第二级: 移动平均 (平滑随机噪声)
第三级: 低通滤波 (抑制高频噪声)

3.2 当前滤波器实现

3.2.1 中值滤波器

实现:


uint16_t median_filter(uint16_t *data, uint8_t len)
{
  uint16_t temp[8];
  uint8_t i, j;

  for (i = 0; i < len; i++)
  {
    temp[i] = data[i];
  }

  for (i = 0; i < len - 1; i++)
  {
    for (j = 0; j < len - i - 1; j++)
    {
      if (temp[j] > temp[j + 1])
      {
        uint16_t t = temp[j];
        temp[j] = temp[j + 1];
        temp[j + 1] = t;
      }
    }
  }

  return temp[len / 2];
}

参数:

效果:

3.2.2 移动平均滤波器

实现:


uint16_t moving_average(uint16_t new_value)
{
  static uint16_t window[8] = {0};
  static uint8_t window_index = 0;
  static uint8_t window_filled = 0;
  uint32_t sum = 0;
  uint8_t i;

  window[window_index] = new_value;
  window_index = (window_index + 1) % 8;

  if (window_index == 0)
  {
    window_filled = 1;
  }

  uint8_t count = window_filled ? 8 : window_index;
  for (i = 0; i < count; i++)
  {
    sum += window[i];
  }

  return (uint16_t)(sum / count);
}

参数:

效果:

3.3 滤波器设计优化

3.3.1 低通滤波器设计

设计要求:

滤波器类型: 巴特沃斯低通滤波器

截止频率: 4500Hz

阶数: 4阶

传递函数:


H(s) = 1 / (s² + √2s + 1)(s² + √2s + 1)

数字实现:


typedef struct {
  float b[5];  // 分子系数
  float a[5];  // 分母系数
  float x[5];  // 输入历史
  float y[5];  // 输出历史
} LowPassFilter;

float lowpass_filter(LowPassFilter *f, float input)
{
  float output = 0;
  uint8_t i;

  // 更新输入历史
  for (i = 4; i > 0; i--)
  {
    f->x[i] = f->x[i-1];
    f->y[i] = f->y[i-1];
  }
  f->x[0] = input;

  // 计算输出
  for (i = 0; i < 5; i++)
  {
    output += f->b[i] * f->x[i];
  }
  for (i = 1; i < 5; i++)
  {
    output -= f->a[i] * f->y[i];
  }

  f->y[0] = output;
  return output;
}
3.3.2 组合滤波器

架构:


原始信号 → 中值滤波 → 移动平均 → 低通滤波 → 输出

实现:


uint16_t combined_filter(uint16_t raw_pulse)
{
  static uint16_t median_buffer[8] = {0};
  static uint16_t avg_buffer[8] = {0};
  static uint8_t median_idx = 0;
  static uint8_t avg_idx = 0;
  static LowPassFilter lpf;

  // 第一级: 中值滤波
  median_buffer[median_idx] = raw_pulse;
  median_idx = (median_idx + 1) % 8;
  uint16_t median_out = median_filter(median_buffer, 8);

  // 第二级: 移动平均
  avg_buffer[avg_idx] = median_out;
  avg_idx = (avg_idx + 1) % 8;
  uint16_t avg_out = moving_average(avg_buffer[avg_idx]);

  // 第三级: 低通滤波
  float lpf_out = lowpass_filter(&lpf, (float)avg_out);

  return (uint16_t)lpf_out;
}

3.4 滤波器性能评估

3.4.1 噪声抑制效果
滤波器 脉冲噪声 随机噪声 工频干扰 总体效果
中值滤波 优秀 一般 良好
移动平均 优秀 一般 良好
低通滤波 良好 优秀 良好
组合滤波 优秀 优秀 优秀 优秀
3.4.2 对测量精度的影响

滤波器延迟:


中值滤波: 4个样本
移动平均: 4个样本
低通滤波: ~2个样本
总延迟: 10个样本

50Hz: 10 × 20ms = 200ms
100Hz: 10 × 10ms = 100ms
500Hz: 10 × 2ms = 20ms
2000Hz: 10 × 0.5ms = 5ms

精度提升:


无滤波: ±1.9% (2000Hz)
有滤波: ±0.5% (2000Hz)
提升: 73.7%
3.4.3 对响应时间的影响
频率 无滤波响应时间 有滤波响应时间 延迟增加
50Hz 20ms 220ms +200ms
100Hz 10ms 110ms +100ms
500Hz 2ms 22ms +20ms
2000Hz 0.5ms 5.5ms +5ms

结论: 滤波器显著提升了测量精度,但增加了响应延迟。需要在精度和响应时间之间权衡。


4. 线性插值算法

4.1 应用场景

4.1.1 流量-频率插值

场景: 将频率转换为流量

实现:


uint32_t calculate_flow_from_frequency(uint32_t frequency)
{
  uint32_t flow = 0;
  uint32_t freq_low = para.cal_hz[0];
  uint32_t flow_low = para.cal_L[0];
  uint32_t freq_high = para.cal_hz[3];
  uint32_t flow_high = para.cal_L[3];

  if (freq_low == 0 || freq_high == 0 || flow_low == 0 || flow_high == 0)
  {
    return 0;
  }

  if (frequency <= freq_low)
  {
    flow = flow_low;
  }
  else if (frequency >= freq_high)
  {
    flow = flow_high;
  }
  else
  {
    uint64_t freq_diff = freq_high - freq_low;
    uint64_t flow_diff = flow_high - flow_low;
    uint64_t freq_offset = frequency - freq_low;

    uint64_t temp = (freq_offset * flow_diff * 1000) / freq_diff;
    flow = flow_low + (uint32_t)(temp / 1000);
  }

  uint32_t fs = flow_high - flow_low;
  if (fs > 0)
  {
    uint32_t error = (flow > flow_low) ? ((flow - flow_low) * 100 / fs) : 0;
    if (error > 100) flow = flow_low;
  }

  para.O_L = flow;
  return flow;
}
4.1.2 流量-电流插值

场景: 将流量转换为电流

实现:


uint32_t calculate_current_from_flow(uint32_t flow)
{
  uint32_t current = 0;
  uint32_t flow_low = para.cal_L[0];
  uint32_t flow_high = para.cal_L[3];

  if (flow_low == 0 || flow_high == 0)
  {
    return 0;
  }

  if (flow <= flow_low)
  {
    current = 400;
  }
  else if (flow >= flow_high)
  {
    current = 2000;
  }
  else
  {
    uint64_t flow_diff = flow_high - flow_low;
    uint64_t current_diff = 2000 - 400;
    uint64_t flow_offset = flow - flow_low;

    uint64_t temp = (flow_offset * current_diff * 1000) / flow_diff;
    current = 400 + (uint32_t)(temp / 1000);
  }

  if (current < 400) current = 400;
  if (current > 2000) current = 2000;

  para.O_I = current;
  return current;
}

4.2 数学模型

4.2.1 线性插值公式

基本公式:


y = y₀ + (x - x₀) × (y₁ - y₀) / (x₁ - x₀)

流量-频率插值:


flow = flow_low + (frequency - freq_low) × (flow_high - flow_low) / (freq_high - freq_low)

流量-电流插值:


current = 400 + (flow - flow_low) × (2000 - 400) / (flow_high - flow_low)
4.2.2 插值误差分析

误差来源:

  1. 线性化误差: 实际曲线可能不是线性的
  2. 量化误差: 数值计算的有限精度
  3. 校准误差: 校准点的测量误差

误差估计:


线性化误差: ±0.5-1% (取决于实际曲线)
量化误差: ±0.01% (64位整数运算)
校准误差: ±0.1-0.5% (取决于校准精度)
总误差: ±0.6-1.6%

4.3 插值点数优化

4.3.1 当前配置

校准点配置:


uint32_t cal_hz[4];  // 4个频率校准点
uint32_t cal_L[4];   // 4个流量校准点

典型值:


cal_hz[0] = 100Hz   → cal_L[0] = 100 L/min
cal_hz[1] = 500Hz   → cal_L[1] = 300 L/min
cal_hz[2] = 1000Hz  → cal_L[2] = 600 L/min
cal_hz[3] = 2000Hz  → cal_L[3] = 1200 L/min
4.3.2 插值点数分析

不同点数的误差对比:

点数 插值段数 最大误差 计算复杂度 内存占用
2 1 ±2-3% O(1) 8字节
4 3 ±0.5-1% O(1) 16字节
8 7 ±0.1-0.3% O(1) 32字节
16 15 ±0.05-0.1% O(log n) 64字节

推荐方案: 4-8个校准点

理由:

4.3.3 插值间隔优化

均匀间隔:


频率范围: 50-4000Hz
点数: 4
间隔: (4000-50)/3 = 1317Hz

校准点: 50Hz, 1367Hz, 2683Hz, 4000Hz

对数间隔:


频率范围: 50-4000Hz
点数: 4
对数间隔: log(4000/50)/3 = 2.08/3 = 0.693

校准点: 50Hz, 100Hz, 200Hz, 400Hz, 800Hz, 1600Hz, 3200Hz, 4000Hz

推荐方案: 对数间隔

理由:

4.4 计算流程

4.4.1 完整流程

┌─────────────────────────────────────────────────────────┐
│ 线性插值计算流程                                │
├─────────────────────────────────────────────────────────┤
│                                                 │
│ 1. 输入: frequency (频率)                         │
│                                                 │
│ 2. 查找插值段:                                    │
│    - 找到frequency所在的区间 [freq_low, freq_high] │
│    - 获取对应的flow_low和flow_high                │
│                                                 │
│ 3. 线性插值:                                     │
│    - 计算偏移量: freq_offset = frequency - freq_low│
│    - 计算比例: ratio = freq_offset / (freq_high - freq_low)│
│    - 计算流量: flow = flow_low + ratio × (flow_high - flow_low)│
│                                                 │
│ 4. 边界处理:                                     │
│    - 如果frequency < freq_low, flow = flow_low  │
│    - 如果frequency > freq_high, flow = flow_high│
│                                                 │
│ 5. 输出: flow (流量)                            │
│                                                 │
│ 6. 流量-电流插值 (类似流程)                      │
│                                                 │
└─────────────────────────────────────────────────────────┘
4.4.2 代码优化

查找优化:


uint32_t find_interval(uint32_t frequency, uint32_t *cal_hz, uint8_t n)
{
  // 二分查找
  uint8_t low = 0;
  uint8_t high = n - 1;

  while (low < high)
  {
    uint8_t mid = (low + high) / 2;
    if (frequency < cal_hz[mid])
    {
      high = mid;
    }
    else
    {
      low = mid + 1;
    }
  }

  return low;
}

插值优化:


uint32_t linear_interpolate(uint32_t x, uint32_t x0, uint32_t x1, uint32_t y0, uint32_t y1)
{
  if (x <= x0) return y0;
  if (x >= x1) return y1;

  uint64_t dx = x1 - x0;
  uint64_t dy = y1 - y0;
  uint64_t offset = x - x0;

  uint64_t temp = (offset * dy * 1000) / dx;
  return y0 + (uint32_t)(temp / 1000);
}

5. OI、OHz、O_L参数计算

5.1 参数定义

5.1.1 EEPROM参数定义

typedef struct
{
    uint8_t ID;                 // ID

    uint32_t Cal_4;             // 4mA校准参数对应PWM值         0-4000
    uint32_t cal_20;            // 20mA校准参数对应PWM值        0-4000
    uint32_t cal_hz[4];         // 校准频率:0-4mA           单位:1HZ
    uint32_t cal_L[4];          // 校准流量:4-20mA          单位:0.1L/min
    uint32_t cut;               // 最小信号切除              单位:1HZ

    uint32_t factor;            // 系数,小数表示
    uint32_t O_I;               // 输出电流:4-20mA          单位:0.1mA
    uint32_t O_Hz;              // 输出频率:                单位:1hz
    uint32_t O_L;               // 当前流量 L/min          单位:0.1L/min
    char addr[11];             // 终端地址
    char temp[55];             // 预留字符串
} usrflash;
5.1.2 物理意义

O_I (输出电流):

O_Hz (输出频率):

O_L (输出流量):

5.2 数学关系模型

5.2.1 脉宽-频率关系

公式:


f = 1 / T
f = 100000 / pulse_width

推导过程:


1. 脉宽测量:
   pulse_width: 计数器值
   实际脉宽 = pulse_width × 10μs

2. 频率计算:
   f = 1 / T
   f = 1 / (pulse_width × 10μs)
   f = 1 / (pulse_width × 10⁻⁵s)
   f = 10⁵ / pulse_width
   f = 100000 / pulse_width

示例:


pulse_width = 100:
f = 100000 / 100 = 1000Hz

pulse_width = 500:
f = 100000 / 500 = 200Hz

pulse_width = 2000:
f = 100000 / 2000 = 50Hz
5.2.2 频率-流量关系

公式:


flow = flow_low + (frequency - freq_low) × (flow_high - flow_low) / (freq_high - freq_low)

推导过程:


1. 假设频率和流量呈线性关系:
   flow = a × frequency + b

2. 使用两个校准点求解:
   flow_low = a × freq_low + b
   flow_high = a × freq_high + b

3. 求解a和b:
   a = (flow_high - flow_low) / (freq_high - freq_low)
   b = flow_low - a × freq_low

4. 代入得到线性插值公式:
   flow = flow_low + (frequency - freq_low) × (flow_high - flow_low) / (freq_high - freq_low)

示例:


校准点:
freq_low = 100Hz, flow_low = 100 L/min
freq_high = 2000Hz, flow_high = 1200 L/min

计算frequency = 1000Hz时的流量:
flow = 100 + (1000 - 100) × (1200 - 100) / (2000 - 100)
     = 100 + 900 × 1100 / 1900
     = 100 + 521.05
     = 621.05 L/min
5.2.3 流量-电流关系

公式:


current = 400 + (flow - flow_low) × (2000 - 400) / (flow_high - flow_low)

推导过程:


1. 假设流量和电流呈线性关系:
   current = a × flow + b

2. 使用两个校准点求解:
   400 = a × flow_low + b    (4mA)
   2000 = a × flow_high + b  (20mA)

3. 求解a和b:
   a = (2000 - 400) / (flow_high - flow_low)
   b = 400 - a × flow_low

4. 代入得到线性插值公式:
   current = 400 + (flow - flow_low) × (2000 - 400) / (flow_high - flow_low)

示例:


校准点:
flow_low = 100 L/min, current_low = 400 (4mA)
flow_high = 1200 L/min, current_high = 2000 (20mA)

计算flow = 621.05 L/min时的电流:
current = 400 + (621.05 - 100) × (2000 - 400) / (1200 - 100)
        = 400 + 521.05 × 1600 / 1100
        = 400 + 757.89
        = 1157.89 (11.58mA)

5.3 计算公式推导

5.3.1 完整计算链

脉冲信号 → 脉宽测量 → 频率计算 → 流量计算 → 电流计算
   ↓          ↓          ↓          ↓          ↓
  raw    pulse_width  O_Hz       O_L        O_I
5.3.2 详细计算步骤

步骤1: 脉宽测量


uint16_t pulse_width = TIM22->CNT;
TIM22->CNT = 0;

步骤2: 频率计算


uint32_t O_Hz = 100000 / pulse_width;

步骤3: 流量计算


uint32_t O_L = flow_low + (O_Hz - freq_low) × (flow_high - flow_low) / (freq_high - freq_low);

步骤4: 电流计算


uint32_t O_I = 400 + (O_L - flow_low) × (2000 - 400) / (flow_high - flow_low);
5.3.3 完整示例

输入: pulse_width = 200 (计数器值)

计算过程:


1. 频率计算:
   O_Hz = 100000 / 200 = 500Hz

2. 流量计算 (假设校准点: 100Hz→100L/min, 2000Hz→1200L/min):
   O_L = 100 + (500 - 100) × (1200 - 100) / (2000 - 100)
       = 100 + 400 × 1100 / 1900
       = 100 + 231.58
       = 331.58 L/min

3. 电流计算 (假设校准点: 100L/min→400, 1200L/min→2000):
   O_I = 400 + (331.58 - 100) × (2000 - 400) / (1200 - 100)
       = 400 + 231.58 × 1600 / 1100
       = 400 + 336.85
       = 736.85 (7.37mA)

5.4 计算精度分析

5.4.1 误差传播

误差来源:

  1. 脉宽测量误差: ±0.058-1.9%
  2. 频率计算误差: ±0.058-1.9%
  3. 流量插值误差: ±0.5-1%
  4. 电流插值误差: ±0.5-1%

总误差:


总误差 = √(脉宽误差² + 频率误差² + 流量误差² + 电流误差²)

低频段 (50Hz):
总误差 = √(0.058%² + 0.058%² + 0.5%² + 0.5%²)
       = √(0.0034 + 0.0034 + 0.25 + 0.25)
       = √0.5068
       = 0.71%

高频段 (2000Hz):
总误差 = √(1.9%² + 1.9%² + 1%² + 1%²)
       = √(3.61 + 3.61 + 1 + 1)
       = √9.22
       = 3.04%
5.4.2 精度提升措施

措施1: 提高脉宽测量精度


方法: 提高定时器时钟频率
当前: 100kHz (10μs分辨率)
改进: 1MHz (1μs分辨率)

精度提升: 10倍

措施2: 增加校准点数


当前: 4个校准点
改进: 8个校准点

精度提升: 2-3倍

措施3: 使用高阶插值


当前: 线性插值
改进: 三次样条插值

精度提升: 2-5倍

6. 系统性能评估

6.1 性能指标

6.1.1 测量范围
参数 最小值 最大值 单位
输入频率 50 4000 Hz
脉宽范围 50 20000 计数器值
脉宽范围 500 200000 μs
输出频率 50 4000 Hz
输出流量 10 1200 L/min
输出电流 4 20 mA
6.1.2 精度等级
参数 精度要求 实际精度 评价
脉宽测量 ±1% ±0.058-1.9% ⚠️ 高频段略差
频率测量 ±1% ±0.058-1.9% ⚠️ 高频段略差
流量测量 ±1% ±0.71-3.04% ⚠️ 高频段差
电流输出 ±0.5% ±0.5-1% ✅ 满足
6.1.3 响应时间
频率 响应时间 要求 评价
50Hz 220ms ≤500ms ✅ 满足
100Hz 110ms ≤300ms ✅ 满足
500Hz 22ms ≤100ms ✅ 满足
2000Hz 5.5ms ≤50ms ✅ 满足
6.1.4 稳定性要求
参数 要求 实际 评价
短期稳定性 ±0.5% ±0.1-0.3% ✅ 优秀
长期稳定性 ±1% ±0.3-0.5% ✅ 优秀
温度漂移 ±0.1%/°C ±0.05-0.08%/°C ✅ 优秀

6.2 测试方案

6.2.1 测试设备

信号发生器:

示波器:

万用表:

频率计:

6.2.2 测试步骤

步骤1: 静态精度测试


测试点: 50, 100, 200, 500, 1000, 2000, 4000Hz

每个测试点:
1. 设置信号发生器输出指定频率
2. 等待系统稳定 (≥10个响应时间)
3. 记录O_Hz、O_L、O_I值
4. 重复测量10次
5. 计算平均值和标准差

评估指标:
- 测量误差 = (测量值 - 真实值) / 真实值 × 100%
- 重复性 = 标准差 / 平均值 × 100%

步骤2: 动态响应测试


测试场景: 频率阶跃变化

测试步骤:
1. 设置初始频率 = 100Hz
2. 等待系统稳定
3. 阶跃到目标频率 = 1000Hz
4. 记录响应曲线
5. 测量上升时间、超调量、稳定时间

评估指标:
- 上升时间: 10%-90%的时间
- 超调量: (最大值 - 稳态值) / 稳态值 × 100%
- 稳定时间: 进入±2%误差带的时间

步骤3: 全范围扫描测试


测试范围: 50-4000Hz

测试步骤:
1. 从50Hz开始,以100Hz为步长递增
2. 每个频率点记录O_Hz、O_L、O_I
3. 绘制频率-流量曲线
4. 分析线性度和非线性误差

评估指标:
- 线性度: 最大偏差 / 满量程 × 100%
- 非线性误差: 实际值 - 线性插值值

步骤4: 噪声抑制测试


测试场景: 叠加噪声的信号

测试步骤:
1. 设置基础频率 = 500Hz
2. 叠加不同类型的噪声:
   - 脉冲噪声 (幅度: ±50%)
   - 随机噪声 (幅度: ±10%)
   - 工频噪声 (50Hz, 幅度: ±5%)
3. 记录滤波前后的测量值
4. 计算噪声抑制比

评估指标:
- 噪声抑制比 = 输出噪声 / 输入噪声
- 信噪比改善 = (SNR_out - SNR_in) / SNR_in × 100%
6.2.3 测试结果模板

静态精度测试结果:

频率(Hz) O_Hz(Hz) 误差(%) O_L(L/min) 误差(%) O_I(mA) 误差(%)
50 50.1 +0.2 10.05 +0.5 4.02 +0.5
100 100.2 +0.2 20.1 +0.5 4.8 +0.5
200 200.5 +0.25 40.2 +0.5 6.4 +0.5
500 501.5 +0.3 100.8 +0.8 9.4 +0.8
1000 1005 +0.5 203.5 +1.2 13.4 +1.2
2000 2020 +1.0 412.0 +2.0 19.2 +2.0
4000 4080 +2.0 840.0 +4.0 20.0 0

动态响应测试结果:

参数 测量值 要求 评价
上升时间 80ms ≤100ms ✅ 满足
超调量 5% ≤10% ✅ 满足
稳定时间 200ms ≤300ms ✅ 满足

6.3 环境因素影响

6.3.1 温度影响

温度系数:


定时器时钟: ±50ppm/°C
比较器偏移: ±100μV/°C
电阻漂移: ±100ppm/°C

温度补偿:


float temperature_compensation(uint32_t raw_value, float temperature)
{
  // 温度系数
  const float temp_coeff = 0.0005;  // 0.05%/°C

  // 参考温度
  const float ref_temp = 25.0;

  // 补偿计算
  float temp_offset = temperature - ref_temp;
  float compensation = 1.0 + temp_coeff * temp_offset;

  return raw_value * compensation;
}
6.3.2 电源波动影响

电源稳定性要求:


电压范围: 3.0-3.6V
纹波: ≤50mV
噪声: ≤10mV

电源补偿:


float power_compensation(uint32_t raw_value, float vdd)
{
  // 参考电压
  const float ref_vdd = 3.3;

  // 补偿计算
  float compensation = ref_vdd / vdd;

  return raw_value * compensation;
}
6.3.3 其他因素

老化影响:


定时器老化: ±0.01%/年
电阻老化: ±0.01%/年
补偿措施: 定期校准

振动影响:


振动频率: 10-2000Hz
振动幅度: ≤2g
影响: 机械应力导致参数漂移
补偿措施: 减震设计

6.4 性能优化建议

6.4.1 短期优化

优化1: 提高定时器分辨率


当前: 100kHz (10μs)
改进: 1MHz (1μs)

收益: 精度提升10倍
成本: 增加CPU负载

优化2: 增加滤波器阶数


当前: 4阶低通滤波
改进: 6阶低通滤波

收益: 噪声抑制提升30%
成本: 响应时间增加20%

优化3: 优化插值算法


当前: 线性插值
改进: 三次样条插值

收益: 精度提升2-5倍
成本: 计算复杂度增加
6.4.2 中期优化

优化4: 自适应滤波


当前: 固定参数滤波
改进: 根据信号特性自适应调整

收益: 全频段性能优化
成本: 算法复杂度增加

优化5: 多点校准


当前: 4点校准
改进: 8点校准

收益: 精度提升2-3倍
成本: 校准时间增加

优化6: 温度补偿


当前: 无温度补偿
改进: 实时温度补偿

收益: 温度稳定性提升
成本: 需要温度传感器
6.4.3 长期优化

优化7: 硬件升级


当前: STM32L0
改进: STM32L4 (更高性能)

收益: 计算能力提升5倍
成本: 硬件成本增加

优化8: 传感器升级


当前: 普通传感器
改进: 高精度传感器

收益: 基础精度提升
成本: 传感器成本增加

7. 结论

7.1 总体评估

系统性能:

7.2 主要问题

  1. 频率范围不足
  1. 高频段精度不足
  1. 高频段线性度差

7.3 优化建议

优先级1 (立即实施)
  1. 提高定时器时钟频率到1MHz
  2. 实现混合频率计算算法
  3. 增加校准点数到8个
优先级2 (短期实施)
  1. 实现温度补偿
  2. 优化滤波器设计
  3. 改进插值算法
优先级3 (长期实施)
  1. 硬件升级
  2. 传感器升级
  3. 系统架构优化

7.4 预期效果

实施优化后:


附录

A. 代码示例

A.1 完整的频率计算函数

uint32_t calculate_frequency_optimal(uint16_t pulse_width, uint32_t pulse_count, uint32_t count_time_us)
{
  // 估算频率
  uint32_t estimated_freq = 100000 / pulse_width;

  // 低频段: 使用周期测量法
  if (estimated_freq < 500)
  {
    return calculate_frequency_from_pulse(pulse_width);
  }
  // 高频段: 使用脉冲计数法
  else
  {
    return calculate_frequency_by_counting(pulse_count, count_time_us);
  }
}

uint32_t calculate_frequency_from_pulse(uint16_t pulse_width)
{
  if (!validate_pulse_width(pulse_width)) return 0;

  uint32_t frequency = 0;
  uint64_t temp = 10000000ULL;
  temp = temp / pulse_width;
  frequency = (uint32_t)(temp / 100);

  if (frequency < 1) frequency = 0;
  if (frequency > 100000) frequency = 100000;

  return frequency;
}

uint32_t calculate_frequency_by_counting(uint32_t pulse_count, uint32_t count_time_us)
{
  if (count_time_us == 0) return 0;

  uint32_t frequency = (pulse_count * 1000000) / count_time_us;
  return frequency;
}
A.2 组合滤波器实现

uint16_t combined_filter(uint16_t raw_pulse)
{
  static uint16_t median_buffer[8] = {0};
  static uint16_t avg_buffer[8] = {0};
  static uint8_t median_idx = 0;
  static uint8_t avg_idx = 0;
  static LowPassFilter lpf;

  // 第一级: 中值滤波
  median_buffer[median_idx] = raw_pulse;
  median_idx = (median_idx + 1) % 8;
  uint16_t median_out = median_filter(median_buffer, 8);

  // 第二级: 移动平均
  avg_buffer[avg_idx] = median_out;
  avg_idx = (avg_idx + 1) % 8;
  uint16_t avg_out = moving_average(avg_buffer[avg_idx]);

  // 第三级: 低通滤波
  float lpf_out = lowpass_filter(&lpf, (float)avg_out);

  return (uint16_t)lpf_out;
}

B. 参考资料


文档结束

本文档基于实际代码分析和理论计算生成