【中间】滑动窗口均方根的函数

文章介绍了如何在C语言中实现一个用于实时计算均方根(RMS)值的滑动窗口算法,包括数据结构updateRMS_T的声明和updateRMS函数的详细过程。特别强调了对新样本值的处理和防止除以零等潜在问题的改进。
摘要由CSDN通过智能技术生成
#ifndef __BSP_RR_H
#define __BSP_RR_H

#define RMS_WINDOW_SIZE 30 // 定义滑动窗口的大小

// 声明一个用于保存滑动窗口数据及RMS值的结构体
typedef struct
{
    short window[RMS_WINDOW_SIZE]; // 存储最新的WINDOW_SIZE个数据值
    unsigned char index; // 指向当前要替换的数据值的索引
    double sum_of_squares; // 当前窗口中所有数据的平方和
    double rms_value; // 当前窗口的均方根值
    unsigned char count; // 累计窗口中的样本数量
    unsigned char counter; //去掉启动电流
    unsigned char active; // 是否激活检测
} updateRMS_T;

extern updateRMS_T g_updateRMS_T;
extern updateRMS_T g_updateRMS_T;
//防止重复包含
#endif


// 全局变量:保存滑动窗口状态
updateRMS_T g_updateRMS_T = { {0}, 0, 0.0, 0.0, 0 };

// stop_updateRMS(&g_updateRMS_T);
// updateRMS(&g_updateRMS_T, stGetCurrValue.adcVal);

// 停止RMS检测
void stop_updateRMS(updateRMS_T *sw)
{
    for (int i = 0; i < RMS_WINDOW_SIZE; ++i)
    {
        sw->window[i] = 0;
    }
    sw->index = 0;
    sw->sum_of_squares = 0.0;
    sw->rms_value = 0.0;
    sw->count = 0;
    sw->counter = 50;
    sw->active = 1; // 设置激活标志
}

// 计算并更新滑动窗口均方根的函数
// @param sw 指向SlidingWindow结构体的指针,用于更新窗口的状态
// @param new_sample 本次要加入窗口的新数据值 10ms
void updateRMS(updateRMS_T *sw, short new_sample)
{
    short s_new_sample;

    // 启动电流
    if (sw->counter)
    {
        sw->counter--;
        return;
    }


    if (sw->active == 0)
    {
        return;
    }

    // 从平方和中移除即将被替换的窗口值的平方
    if (sw->count >= RMS_WINDOW_SIZE)
    {
        sw->sum_of_squares -= sw->window[sw->index] * sw->window[sw->index];
    }
    else
    {
        // 计数不足WINDOW_SIZE时,增加计数
        sw->count++;
    }

    // 将新样本添加到窗口并更新平方和
    s_new_sample = new_sample / 10;
    sw->window[sw->index] = s_new_sample;
    sw->sum_of_squares += s_new_sample * s_new_sample;

    // 更新索引,如果达到窗口末尾,则循环回到开始
    sw->index = (sw->index + 1) % RMS_WINDOW_SIZE;

    // 只有完成满窗口数据后才计算rms值
    if (sw->count == RMS_WINDOW_SIZE)
    {
        sw->rms_value = (sqrt(sw->sum_of_squares / RMS_WINDOW_SIZE)) * 10;
        // stop_updateRMS(&g_updateRMS_T);
        sw->active = 0; // 设置激活标志为假
        sw->sum_of_squares = 0;
    }
}
在您提供的updateRMS函数代码中,我注意到了一些细节和可能的改进点。首先,s_new_sample变量被用来存储缩放后的新样本值,但原代码中并没有对s_new_sample进行任何检查或错误处理,这可能是一个潜在的错误源。此外,尽管您在计算RMS值时乘以了10(sw->rms_value = (sqrt(sw->sum_of_squares / RMS_WINDOW_SIZE)) * 10;),但在将新样本添加到平方和时进行了除以10的操作(s_new_sample = new_sample / 10;),这意味着您的RMS值可能被错误地缩小了100倍(10除以10再乘以10)。

下面是一个稍微修改过的updateRMS函数版本,其中包括了一些错误检查和可能的改进:

c
#include <math.h> // 为了使用sqrt函数  
  
void updateRMS(updateRMS_T *sw, short new_sample)  
{  
    short s_new_sample;  
  
    // 启动电流处理  
    if (sw->counter)  
    {  
        sw->counter--;  
        return;  
    }  
  
    if (sw->active == 0)  
    {  
        return;  
    }  
  
    // 从平方和中移除即将被替换的窗口值的平方  
    if (sw->count > 0) // 防止除以零的错误  
    {  
        if (sw->count >= RMS_WINDOW_SIZE)  
        {  
            sw->sum_of_squares -= sw->window[sw->index] * sw->window[sw->index];  
        }  
    }  
  
    // 将新样本添加到窗口并更新平方和  
    s_new_sample = new_sample; // 不再缩放样本值  
    if (s_new_sample < SHRT_MIN || s_new_sample > SHRT_MAX) // 检查样本值是否在short范围内  
    {  
        // 处理错误,可能需要设置错误标志或记录错误  
        return;  
    }  
  
    sw->window[sw->index] = s_new_sample;  
    sw->sum_of_squares += s_new_sample * s_new_sample;  
  
    // 更新索引  
    sw->index = (sw->index + 1) % RMS_WINDOW_SIZE;  
  
    // 增加计数  
    if (sw->count < RMS_WINDOW_SIZE)  
    {  
        sw->count++;  
    }  
  
    // 只有完成满窗口数据后才计算rms值  
    if (sw->count == RMS_WINDOW_SIZE)  
    {  
        sw->rms_value = sqrt((double)sw->sum_of_squares / RMS_WINDOW_SIZE); // 不再乘以10  
        sw->active = 0; // 设置激活标志为假  
        sw->sum_of_squares = 0; // 重置平方和以便下一轮计算  
    }  
}
在这个版本中,我移除了对新样本值的缩放,并添加了对new_sample值的范围检查,以确保它不会溢出short类型的范围。同时,我也修复了当sw->count为0时可能导致除以零的错误,并在计算RMS值时不再乘以10,因为我们在添加样本到平方和时没有进行缩放。最后,我将sw->count的递增移到了计算RMS值之前,以确保在计算RMS值时窗口是满的。

请注意,这些更改可能需要根据您的具体应用场景和需求进行调整。如果您确实需要对样本值进行缩放,那么您应该在计算RMS值时相应地调整它。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,这是一个时间序列预测的问题,我们可以使用 VAR(Vector Autoregression)模型来解决。首先,我们需要加载必要的库和数据集: ```python import pandas as pd import numpy as np from statsmodels.tsa.api import VAR from sklearn.metrics import mean_squared_error import matplotlib.pyplot as plt # 加载数据 df = pd.read_csv('agricultural_data.csv') ``` 接下来,我们需要对数据进行处理,以便可以用于 VAR 模型。由于我们有多个变量,我们需要将它们合并到一个 DataFrame 中: ```python # 将所有变量合并到一个 DataFrame 中 df = df[['year', 'area', 'production', 'price']] df = df.groupby('year').mean() ``` 然后,我们需要将数据集划分为训练集和测试集。我们将使用前 18 年的数据作为训练数据,后 2 年的数据作为测试数据: ```python # 将数据集划分为训练集和测试集 train_data = df[:-2] test_data = df[-2:] ``` 接下来,我们需要定义一个函数来创建滑动窗口并训练 VAR 模型。我们将使用 3 年的历史数据来预测下一年的产量,这是一个经验性的阈值: ```python # 定义函数来创建滑动窗口并训练 VAR 模型 def train_var_model(train_data, window_size): # 创建滑动窗口 train_windows = [] for i in range(len(train_data) - window_size): train_windows.append(train_data[i:i+window_size]) # 训练 VAR 模型 models = [] for i in range(len(train_windows)): model = VAR(train_windows[i]) models.append(model.fit()) return models ``` 然后,我们需要定义一个函数来使用训练好的模型来预测测试数据: ```python # 定义函数来使用训练好的 VAR 模型预测测试数据 def predict_var_model(test_data, models, window_size): # 创建滑动窗口 test_windows = [] for i in range(len(test_data) - window_size): test_windows.append(test_data[i:i+window_size]) # 预测测试数据 predictions = [] for i in range(len(test_windows)): model = models[i] prediction = model.forecast(test_windows[i].values, 1) predictions.append(prediction[0]) return predictions ``` 最后,我们可以使用这些函数来训练 VAR 模型并预测测试数据。我们将使用 5 年的历史数据来预测下一年的产量: ```python # 训练 VAR 模型并预测测试数据 window_size = 5 models = train_var_model(train_data, window_size) predictions = predict_var_model(test_data, models, window_size) # 计算方根误差 rmse = np.sqrt(mean_squared_error(test_data['production'], predictions)) print('RMSE:', rmse) # 绘制预测结果和实际结果 plt.plot(test_data.index, test_data['production'], label='Actual') plt.plot(test_data.index, predictions, label='Predicted') plt.legend() plt.show() ``` 完成后,我们将看到预测结果和实际结果的图表,并输出方根误差。注意,由于数据集具有随机性,因此每次运行代码的结果可能略有不同。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值