以下是一个在 STM32 中实现既对小波动的重量变化稳定处理,又能对大波动的重量变化及时响应的算法示例:
#include <stdint.h>
#define SMOOTHING_FACTOR_SMALL 0.9 // 小波动平滑系数
#define SMOOTHING_FACTOR_LARGE 0.1 // 大波动平滑系数
#define WEIGHT_THRESHOLD 10 // 区分大波动和小波动的阈值
uint32_t stableWeight(uint32_t newWeight) {
static uint32_t currentWeight = 0;
static uint32_t previousWeight = 0;
int32_t weightDiff = newWeight - previousWeight;
if (abs(weightDiff) <= WEIGHT_THRESHOLD) {
// 小波动,进行平滑处理
currentWeight = (uint32_t)((float)currentWeight * SMOOTHING_FACTOR_SMALL + (float)newWeight * (1.0 - SMOOTHING_FACTOR_SMALL));
} else {
// 大波动,快速响应
currentWeight = (uint32_t)((float)currentWeight * SMOOTHING_FACTOR_LARGE + (float)newWeight * (1.0 - SMOOTHING_FACTOR_LARGE));
}
previousWeight = newWeight;
return currentWeight;
}
你可以在主程序中不断调用这个函数来处理从 HX711 读取到的重量数据。
解释如下:
-
定义了两个平滑系数和一个重量阈值。
SMOOTHING_FACTOR_SMALL
用于小波动的平滑处理,值越接近 1 平滑效果越强;SMOOTHING_FACTOR_LARGE
用于大波动的快速响应,值越接近 0 对新值的响应越快;WEIGHT_THRESHOLD
用于区分大波动和小波动。 -
stableWeight
函数接收新的重量值作为参数。首先计算新重量与上一次重量的差值。如果差值小于等于阈值,认为是小波动,使用SMOOTHING_FACTOR_SMALL
进行平滑处理,即当前重量是上一次的重量和新重量的加权平均。如果差值大于阈值,认为是大波动,使用SMOOTHING_FACTOR_LARGE
进行快速响应处理。 -
最后更新当前重量和上一次重量,以便下次调用函数时使用。
可以优化上述算法性能的方法:
一、数据滤波
- 均值滤波:
- 除了上述算法中的平滑处理,还可以使用均值滤波进一步减少噪声对重量数据的影响。
- 例如,连续读取多个重量值,计算它们的平均值作为当前的输入值传递给算法。这样可以降低随机噪声引起的小波动。
- 代码示例:
#define NUM_FILTER_SAMPLES 5
uint32_t filterWeight() {
uint32_t sum = 0;
for (int i = 0; i < NUM_FILTER_SAMPLES; i++) {
sum += readHX711();
}
return sum / NUM_FILTER_SAMPLES;
}
- 在主程序中,先调用
filterWeight
函数获取滤波后的重量值,再将其传递给stableWeight
函数进行稳定化处理。
- 中值滤波:
- 对于存在脉冲噪声或异常值的情况,中值滤波可能更有效。
- 连续读取多个重量值,将它们排序后取中间值作为当前的输入值。
- 代码示例:
#define NUM_FILTER_SAMPLES 5
uint32_t filterWeightMedian() {
uint32_t samples[NUM_FILTER_SAMPLES];
for (int i = 0; i < NUM_FILTER_SAMPLES; i++) {
samples[i] = readHX711();
}
for (int i = 0; i < NUM_FILTER_SAMPLES - 1; i++) {
for (int j = i + 1; j < NUM_FILTER_SAMPLES; j++) {
if (samples[i] > samples[j]) {
uint32_t temp = samples[i];
samples[i] = samples[j];
samples[j] = temp;
}
}
}
return samples[NUM_FILTER_SAMPLES / 2];
}
二、动态调整平滑系数
- 根据波动情况调整:
- 目前的算法使用固定的平滑系数,但可以根据实际的重量波动情况动态调整平滑系数,以更好地适应不同的场景。
- 例如,当检测到连续的小波动时,可以逐渐增加平滑系数,使算法对小波动的处理更加稳定;当出现大波动后,可以逐渐降低平滑系数,以便更快地响应后续的变化。
- 代码示例:
#define SMOOTHING_FACTOR_INCREMENT 0.01
#define SMOOTHING_FACTOR_DECREMENT 0.05
uint32_t stableWeightDynamic(uint32_t newWeight) {
static uint32_t currentWeight = 0;
static uint32_t previousWeight = 0;
int32_t weightDiff = newWeight - previousWeight;
static float smoothingFactor = SMOOTHING_FACTOR_SMALL;
if (abs(weightDiff) <= WEIGHT_THRESHOLD) {
// 小波动,逐渐增加平滑系数
smoothingFactor += SMOOTHING_FACTOR_INCREMENT;
if (smoothingFactor > 1.0) smoothingFactor = 1.0;
currentWeight = (uint32_t)((float)currentWeight * smoothingFactor + (float)newWeight * (1.0 - smoothingFactor));
} else {
// 大波动,快速响应并降低平滑系数
smoothingFactor -= SMOOTHING_FACTOR_DECREMENT;
if (smoothingFactor < SMOOTHING_FACTOR_LARGE) smoothingFactor = SMOOTHING_FACTOR_LARGE;
currentWeight = (uint32_t)((float)currentWeight * smoothingFactor + (float)newWeight * (1.0 - smoothingFactor));
}
previousWeight = newWeight;
return currentWeight;
}
三、硬件优化
-
电源稳定性:
- 确保重量传感器和 STM32 系统的电源稳定,减少电源波动对重量测量的影响。
- 可以使用稳压电源模块、电源滤波器等设备来提高电源的质量。
-
信号隔离:
- 对重量传感器的信号进行隔离,防止外部干扰信号影响测量结果。
- 可以使用信号隔离器、光耦等设备来实现信号隔离。
-
硬件滤波:
- 在硬件电路中添加滤波器,对重量传感器的输出信号进行滤波处理。
- 例如,可以使用 RC 滤波器、低通滤波器等电路来去除高频噪声。
四、算法优化
- 减少计算量:
- 优化算法中的计算部分,减少不必要的计算量。例如,在计算平滑处理时,可以使用移位和加法操作代替乘法操作,以提高计算效率。
- 代码示例:
uint32_t stableWeightOptimized(uint32_t newWeight) {
static uint32_t currentWeight = 0;
static uint32_t previousWeight = 0;
int32_t weightDiff = newWeight - previousWeight;
if (abs(weightDiff) <= WEIGHT_THRESHOLD) {
// 小波动,进行平滑处理
currentWeight = currentWeight + ((newWeight - currentWeight) >> 1);
} else {
// 大波动,快速响应
currentWeight = currentWeight + ((newWeight - currentWeight) >> 3);
}
previousWeight = newWeight;
return currentWeight;
}
- 在上述代码中,使用移位操作代替了乘法操作,减少了计算量。
-
并行处理:
- 如果 STM32 芯片支持并行处理,可以将重量数据的读取、滤波和稳定化处理等任务分配到不同的硬件模块或处理器核心上进行并行处理,以提高算法的执行速度。
-
算法复杂度分析:
- 对算法的时间复杂度和空间复杂度进行分析,找出算法中的瓶颈部分,并进行优化。
- 例如,可以使用更高效的数据结构、算法或编程技巧来降低算法的复杂度。
以下是一个在代码中实现自适应阈值算法的示例:
#include <stdint.h>
#define INITIAL_THRESHOLD 10 // 初始阈值
#define THRESHOLD_ADJUSTMENT_FACTOR 0.8 // 阈值调整因子
uint32_t stableWeightWithAdaptiveThreshold(uint32_t newWeight) {
static uint32_t currentWeight = 0;
static uint32_t previousWeight = 0;
static uint32_t threshold = INITIAL_THRESHOLD;
int32_t weightDiff = newWeight - previousWeight;
if (abs(weightDiff) <= threshold) {
// 小波动,进行平滑处理
currentWeight = (uint32_t)((float)currentWeight * 0.9 + (float)newWeight * 0.1);
} else {
// 大波动,快速响应并调整阈值
threshold = (uint32_t)(threshold * THRESHOLD_ADJUSTMENT_FACTOR);
currentWeight = newWeight;
}
previousWeight = newWeight;
return currentWeight;
}
在这个示例中:
-
定义了初始阈值
INITIAL_THRESHOLD
和阈值调整因子THRESHOLD_ADJUSTMENT_FACTOR
。 -
在函数
stableWeightWithAdaptiveThreshold
中,首先计算新重量与上一次重量的差值。如果差值小于等于当前阈值,认为是小波动,进行平滑处理(这里简单使用了加权平均的方式)。如果差值大于阈值,认为是大波动,直接将新重量作为当前重量,并调整阈值为当前阈值乘以调整因子。 -
最后更新当前重量和上一次重量,以便下次调用函数时使用。
你可以在主程序中不断调用这个函数来处理从重量传感器读取到的重量数据。随着重量数据的变化,阈值会自动调整以适应不同的波动情况。