递推算法计算信号特征

admin2024-07-01  16

在线算法(在线计算或递推计算)能够在不存储全部数据的情况下逐步更新信号的特征信息,非常适合资源受限的单片机应用场景。
用途:单片机边采集ADC边计算,最终将采集的信号特征计算结果。平台通过长期监控信号特征来确定采集的设备工作正常。用途机台长期监控。

以下是几种常见的信号特征信息计算及其对应的在线算法:

1. 均值(Mean)

递推均值公式
mean n = ( n − 1 ) ⋅ mean n − 1 + x n n \text{mean}_n = \frac{(n-1) \cdot \text{mean}_{n-1} + x_n}{n} meann=n(n1)meann1+xn
其中,( n ) 是当前采样点的数量,( x_n ) 是第 ( n ) 个采样值,( \text{mean}_{n-1} ) 是前 ( n-1 ) 个采样值的均值。

2. 均方根(RMS, Root Mean Square)

递推 RMS 公式:
RMS n = ( n − 1 ) ⋅ ( RMS n − 1 ) 2 + x n 2 n \text{RMS}_n = \sqrt{\frac{(n-1) \cdot (\text{RMS}_{n-1})^2 + x_n^2}{n}} RMSn=n(n1)(RMSn1)2+xn2

3. 方差(Variance)

递推方差公式:
var n = ( n − 1 ) ⋅ var n − 1 + ( x n − mean n ) ( x n − mean n − 1 ) n \text{var}_n = \frac{(n-1) \cdot \text{var}_{n-1} + (x_n - \text{mean}_n)(x_n - \text{mean}_{n-1})}{n} varn=n(n1)varn1+(xnmeann)(xnmeann1)

4. 标准差(Standard Deviation)

标准差是方差的平方根:
stddev n = var n \text{stddev}_n = \sqrt{\text{var}_n} stddevn=varn

5. 峰峰值(Peak-to-Peak Value)

更新最大值和最小值:

if (x_n > max) max = x_n;
if (x_n < min) min = x_n;

峰峰值计算公式:
peak-to-peak = max − min \text{peak-to-peak} = \text{max} - \text{min} peak-to-peak=maxmin

6. 平均绝对偏差(Mean Absolute Deviation, MAD)

递推平均绝对偏差公式:
MAD n = ( n − 1 ) ⋅ MAD n − 1 + ∣ x n − mean n ∣ n \text{MAD}_n = \frac{(n-1) \cdot \text{MAD}_{n-1} + |x_n - \text{mean}_n|}{n} MADn=n(n1)MADn1+xnmeann

7. 信号功率(Power)

递推信号功率公式:
power n = ( n − 1 ) ⋅ power n − 1 + x n 2 n \text{power}_n = \frac{(n-1) \cdot \text{power}_{n-1} + x_n^2}{n} powern=n(n1)powern1+xn2

8. 信号能量(Energy)

信号能量是所有样本平方的累加和:
energy n = energy n − 1 + x n 2 \text{energy}_n = \text{energy}_{n-1} + x_n^2 energyn=energyn1+xn2

示例代码更新

以下是使用递推算法计算上述信号特征信息的示例代码:

#include "stm32f0xx_hal.h"
#include <math.h>

// 全局变量
volatile uint32_t count = 0;
volatile float mean = 0;
volatile float variance = 0;
volatile float stddev = 0;
volatile float max = -FLT_MAX;
volatile float min = FLT_MAX;
volatile float mad = 0;
volatile float power = 0;
volatile float energy = 0;
volatile uint8_t trigger_active = 0;

// ADC 和定时器句柄
ADC_HandleTypeDef hadc;
TIM_HandleTypeDef htim;

// 初始化 ADC
void ADC_Init(void) {
    __HAL_RCC_ADC1_CLK_ENABLE();
    hadc.Instance = ADC1;
    hadc.Init.Resolution = ADC_RESOLUTION_12B;
    hadc.Init.ScanConvMode = DISABLE;
    hadc.Init.ContinuousConvMode = DISABLE;
    hadc.Init.DiscontinuousConvMode = DISABLE;
    hadc.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T1_TRGO;
    hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc.Init.NbrOfConversion = 1;
    HAL_ADC_Init(&hadc);

    // 配置 ADC 通道
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_0;
    sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
    HAL_ADC_ConfigChannel(&hadc, &sConfig);
}

// 初始化定时器
void TIM_Init(void) {
    __HAL_RCC_TIM1_CLK_ENABLE();
    htim.Instance = TIM1;
    htim.Init.Prescaler = 8000 - 1;  // 1 MHz 时钟,1 kHz 采样率
    htim.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim.Init.Period = 1000 - 1;     // 1 kHz
    htim.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&htim);

    // 配置定时器触发 ADC
    TIM_MasterConfigTypeDef sMasterConfig = {0};
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim, &sMasterConfig);
}

// ADC 转换完成中断服务函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) {
    if (trigger_active) {
        uint32_t adc_value = HAL_ADC_GetValue(hadc);
        float x_n = (float)adc_value;

        // 更新样本计数
        count++;

        // 计算均值
        float old_mean = mean;
        mean = ((count - 1) * mean + x_n) / count;

        // 计算方差
        variance = ((count - 1) * variance + (x_n - mean) * (x_n - old_mean)) / count;
        stddev = sqrt(variance);

        // 更新最大值和最小值
        if (x_n > max) max = x_n;
        if (x_n < min) min = x_n;

        // 计算平均绝对偏差
        mad = ((count - 1) * mad + fabs(x_n - mean)) / count;

        // 计算信号功率
        power = ((count - 1) * power + x_n * x_n) / count;

        // 计算信号能量
        energy += x_n * x_n;
    }
}

// 触发信号检测函数
void check_trigger_signal(void) {
    if (/* 检测到触发信号 */) {
        trigger_active = 1;
        HAL_ADC_Start_IT(&hadc);
        HAL_TIM_Base_Start(&htim);
    } else {
        trigger_active = 0;
        HAL_ADC_Stop_IT(&hadc);
        HAL_TIM_Base_Stop(&htim);
    }
}

// 主函数
int main(void) {
    HAL_Init();
    ADC_Init();
    TIM_Init();

    while (1) {
        check_trigger_signal();
        // 其他处理
    }
}

在这个示例代码中,我们展示了如何使用递推算法来计算多个信号特征信息,包括均值、方差、标准差、最大值、最小值、平均绝对偏差、信号功率和能量。这些算法在每次新的采样点到达时更新,无需存储所有数据,适用于单片机环境。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明原文出处。如若内容造成侵权/违法违规/事实不符,请联系SD编程学习网:675289112@qq.com进行投诉反馈,一经查实,立即删除!