#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
// 定义常量
#define LOW_COOK_WINDOW_SIZE 20 // 滑动窗口大小,10个样本点(10秒)
#define LOW_COOK_SLOPE_THRESHOLD 0.12f // 斜率平缓的阈值
#define LOW_COOK_SAMPLE_INTERVAL 10 // 采样间隔,单位为100ms
#define LOW_COOK_DEFAULT_TIME_DIFFERENCE 10.0f // 默认时间间隔为10秒
#define MIN_TIME_DIFFERENCE 1.0f // 最小时间间隔为1秒
#define MAX_TIME_DIFFERENCE (LOW_COOK_WINDOW_SIZE - 1) // 最大时间间隔为窗口大小减1
// 定义加热系统结构
typedef struct
{
float slope;
float data[LOW_COOK_WINDOW_SIZE]; // 滑动窗口数据
unsigned char count; // 当前样本数量
bool slope_event; // 斜率事件
unsigned char tim_count; // 时间片计数器
unsigned char state; // 状态机
unsigned char slope_status; // 状态
} low_cook_heating_system_t;
// 全局变量
low_cook_heating_system_t low_cooksystem;
// 初始化加热系统
void low_cook_init_heating_system(low_cook_heating_system_t *system)
{
system->slope = 0.0f;
system->tim_count = 0;
system->state = 0;
system->count = 0;
system->slope_event = false;
system->slope_status = 1; // 样本不足
for (unsigned char i = 0; i < LOW_COOK_WINDOW_SIZE; i++)
{
system->data[i] = 0.0f;
}
}
// 添加样本点到滑动窗口,100ms调用一次,1S存数据一次
void low_cook_add_sample(low_cook_heating_system_t *system, float temperature)
{
if (++system->tim_count < LOW_COOK_SAMPLE_INTERVAL)
{
return;
}
system->tim_count = 0;
if (system->count < LOW_COOK_WINDOW_SIZE)
{
// 如果窗口未满,直接添加到末尾
system->data[system->count++] = temperature;
}
else
{
// 如果窗口已满,丢弃最旧的数据,将最新的数据添加到最后的位置
for (unsigned char i = 1; i < LOW_COOK_WINDOW_SIZE; i++)
{
system->data[i - 1] = system->data[i];
}
system->data[LOW_COOK_WINDOW_SIZE - 1] = temperature;
}
}
// 计算温度斜率
float low_cook_calculate_slope(low_cook_heating_system_t *system, float time_difference)
{
// 限制 time_difference 在合理范围内
if (time_difference < MIN_TIME_DIFFERENCE || time_difference > MAX_TIME_DIFFERENCE)
{
system->slope_status = 2; // 时间间隔超出范围
return 0.0f;
}
unsigned char interval_samples = (unsigned char)(time_difference); // 计算需要的样本间隔
if (system->count < LOW_COOK_WINDOW_SIZE || interval_samples >= system->count)
{
system->slope_status = 1; // 样本不足
return 0.0f;
}
// 获取最新样本点和 interval_samples 前的样本点
float current = system->data[system->count - 1];
float previous = system->data[system->count - 1 - interval_samples];
system->slope_status = 0; // 成功计算斜率
// 计算并返回斜率
return (current - previous) / time_difference;
}
void low_cook_update_slope(float time_difference)
{
// 添加新的温度数据到系统中
low_cook_add_sample(&low_cooksystem, stheat.temperature);
// 计算斜率
low_cooksystem.slope = low_cook_calculate_slope(&low_cooksystem, time_difference);
if ((low_cooksystem.slope_status == 0) && (stheat.temperature > 35))
{
// 判断斜率是否平缓
low_cooksystem.slope_event = (fabsf(low_cooksystem.slope) < LOW_COOK_SLOPE_THRESHOLD);
}
}
// 更新斜率
// if (low_cooksystem.state == 0)
// {
// low_cook_update_slope(18);
// if (low_cooksystem.slope_event)
// {
// pid.setpointOuter = stheat.setTemp;
// low_cooksystem.state = 1;
// }
// else
// {
// pid.setpointOuter = 165;
// }
// }
#include <stdio.h>
#include <stdbool.h>
// 定义一个用于表示斜坡发生器状态的结构体
typedef struct RampGenerator
{
float currentValue; // 当前值
float targetValue; // 目标值
float step; // 每个控制周期应当改变的数值大小
bool isBusy; // 指示斜坡发生器是否正在调整中
} RampGenerator;
// 一个周期内对斜坡发生器状态的更新
void rampIterate(RampGenerator *ramp)
{
// printf("Current Value Updated: %f\n", ramp->currentValue); // 添加此行代码以在每次迭代后打印当前值
if (ramp->currentValue < ramp->targetValue)
{ // 如果当前值小于目标值
ramp->currentValue += ramp->step; // 增大当前值
if (ramp->currentValue > ramp->targetValue)
{ // 避免超调
ramp->currentValue = ramp->targetValue;
}
}
else if (ramp->currentValue > ramp->targetValue)
{ // 如果当前值大于目标值
ramp->currentValue -= ramp->step; // 减小当前值
if (ramp->currentValue < ramp->targetValue)
{ // 避免超调
ramp->currentValue = ramp->targetValue;
}
}
}
// 初始化斜坡发生器
void rampInit(RampGenerator *ramp, float startValue, float targetValue, float time, float cycleTime)
{
ramp->currentValue = startValue;
ramp->targetValue = targetValue;
if (time != 0 && cycleTime != 0)
{
ramp->step = (targetValue - startValue) * (cycleTime / time);
if (ramp->step < 0)
{
ramp->step = -ramp->step; // 确保 step 为正
}
}
else
{
ramp->step = 0; // 出错情况下设置为0,避免非法操作
}
}
rampInit(&myRamp, stheat.setTemp * 2, stheat.setTemp, val, 0.1f); //
rampIterate(&myRamp);
#if low_temp_cook_1
// 算法1
Temp_error = stheat.setTemp - stheat.temperature;
if (Temp_error > 0)
{
val = Temp_error * 10; // 1度10秒
}
rampInit(&myRamp, stheat.setTemp * 2, stheat.setTemp, val, 0.1f); //
#endif
#if low_temp_cook_2
// 将stheat.temperature的值从90到0的范围映射到20到360的范围,6分钟
// val = map(stheat.temperature, 90, 0, 20, 360);
rampInit(&myRamp, stheat.setTemp * 2, stheat.setTemp, val, 0.1f); //
#endif
#if low_temp_cook_1
rampIterate(&myRamp);
if (myRamp.currentValue > 162)
{
tempValue = 162;
}
else
{
tempValue = myRamp.currentValue;
}
pid.setpointOuter = tempValue;
if (myRamp.currentValue != stheat.setTemp)
{
pid.KpOuter = 33;
pid.KiOuter = 0.2;
pid.KpInner = 33;
pid.KiInner = 0.1;
}
else
{
Temp_error = stheat.setTemp - stheat.temperature;
// 根据误差模糊调整PID参数
if (Temp_error > 10)
{
pid.KpOuter = 33;
pid.KiOuter = 0.2;
pid.KpInner = 33;
pid.KiInner = 0.1;
}
else if (Temp_error > 5)
{
pid.KpOuter = 28;
pid.KiOuter = 0.2;
pid.KpInner = 33;
pid.KiInner = 0.1;
}
else
{
pid.KpOuter = 10;
pid.KiOuter = 0.15;
pid.KpInner = 15;
pid.KiInner = 0.1;
}
pid.KdInner = 0;
}
#endif
计算斜率,判断斜率
于 2024-07-01 08:44:32 首次发布