diff --git a/mh-quartz/src/main/java/com/mh/quartz/domain/FuzzyLevel.java b/mh-quartz/src/main/java/com/mh/quartz/domain/FuzzyLevel.java new file mode 100644 index 0000000..9f5627e --- /dev/null +++ b/mh-quartz/src/main/java/com/mh/quartz/domain/FuzzyLevel.java @@ -0,0 +1,11 @@ +package com.mh.quartz.domain; + +/** + * @Classname FuzzyLevel + * Todo: + * @Date 2025-05-31 14:19 + * @Created by LJF + */ +public enum FuzzyLevel { + NB, NM, NS, ZO, PS, PM, PB; // 极小,较小,小,零,稍大,较大,极大 +} \ No newline at end of file diff --git a/mh-quartz/src/main/java/com/mh/quartz/task/AHUTask.java b/mh-quartz/src/main/java/com/mh/quartz/task/AHUTask.java index 80b4499..24dc4bc 100644 --- a/mh-quartz/src/main/java/com/mh/quartz/task/AHUTask.java +++ b/mh-quartz/src/main/java/com/mh/quartz/task/AHUTask.java @@ -93,10 +93,6 @@ public class AHUTask { continue; } - // 初始化PID参数(可动态调整) -// PIDParams params = new PIDParams(2.5, 0.1, 0.5); - PIDParams params = new PIDParams(new BigDecimal(kp).doubleValue(), new BigDecimal(ki).doubleValue(), new BigDecimal(kd).doubleValue()); // Kp, Ki, Kd - // 过滤获取回风温度设置值 Optional second = collectionParamsManages .stream() @@ -106,10 +102,12 @@ public class AHUTask { continue; } // 得出回风温度设置值 - double backTemp = second.get().getCurValue().doubleValue(); + double backTempSet = second.get().getCurValue().doubleValue(); // 设定目标温度(夏季制冷24℃) - AHUPIDControlUtil pid = new AHUPIDControlUtil(params, backTemp); + AHUPIDControlUtil controller = new AHUPIDControlUtil(); + + System.out.println("开始模糊PID控制循环:"); // 过滤获取当前回风温度 Optional third = collectionParamsManages @@ -123,7 +121,7 @@ public class AHUTask { double temp = third.get().getCurValue().doubleValue(); // 2. 计算水阀开度(时间间隔1秒) - double valveOpening1 = pid.calculate(temp, 1.0); + double valveOpening1 = controller.compute(backTempSet, temp, 60.0); int valveOpening = new BigDecimal(valveOpening1).intValue(); // 过滤获取水阀调节参数 @@ -143,8 +141,8 @@ public class AHUTask { changeValues.add(new OrderEntity(collectionParamsManage.getId(), String.valueOf(valveOpening), Integer.parseInt(collectionParamsManage.getParamType()), collectionParamsManage.getOtherName())); sendOrderToMqtt(changeValues); // 3. 应用水阀开度(实际应用发送给执行机构) - log.info("回风温度: {} ℃ | 水阀开度: {} % | P:{}, I:{} D:{} ", - temp, valveOpening, params.getKp(), params.getKi(), params.getKd()); + log.info("回风温度: {} ℃ | 水阀开度: {} % ", + temp, valveOpening); } } diff --git a/mh-quartz/src/main/java/com/mh/quartz/util/AHUPIDControlUtil.java b/mh-quartz/src/main/java/com/mh/quartz/util/AHUPIDControlUtil.java index 227fa65..38756a5 100644 --- a/mh-quartz/src/main/java/com/mh/quartz/util/AHUPIDControlUtil.java +++ b/mh-quartz/src/main/java/com/mh/quartz/util/AHUPIDControlUtil.java @@ -1,5 +1,6 @@ package com.mh.quartz.util; +import com.mh.quartz.domain.FuzzyLevel; import com.mh.quartz.domain.PIDParams; /** @@ -11,46 +12,70 @@ import com.mh.quartz.domain.PIDParams; */ public class AHUPIDControlUtil { - // PID控制器核心实现 - private PIDParams params; - private double setPoint; // 目标温度 - private double prevError; // 上次误差 - private double integral; // 积分累积值 - private double minOutput = 0; // 输出下限(0%) - private double maxOutput = 100; // 输出上限(100%) - - public AHUPIDControlUtil(PIDParams params, double setPoint) { - this.params = params; - this.setPoint = setPoint; - } + private double kp = 2.0, ki = 0.1, kd = 0.0; + private double integral = 0; + private double previousError = 0; + + // 模糊增益修正比例 + private double deltaKpScale = 0.5; + private double deltaKiScale = 0.01; + private double deltaKdScale = 0.01; + + public double compute(double setTemp, double currentTemp, double deltaTime) { + double error = setTemp - currentTemp; + double dError = (error - previousError) / deltaTime; - // 计算水阀开度百分比 (0-100%) - public double calculate(double currentTemp, double deltaTime) { - // 1. 计算当前误差 - double error = setPoint - currentTemp; + // 模糊映射 + FuzzyLevel eLevel = toFuzzyLevel(error); + FuzzyLevel ecLevel = toFuzzyLevel(dError); - // 2. 比例项计算 - double proportional = params.getKp() * error; + // 获取PID参数调整 + FuzzyLevel kpAdjust = FuzzyRuleBase.getKpAdjust(eLevel, ecLevel); + FuzzyLevel kiAdjust = kpAdjust; // 简化处理 + FuzzyLevel kdAdjust = kpAdjust; - // 3. 积分项计算(带抗饱和) - integral += params.getKi() * error * deltaTime; - // 积分限幅防止超调 - integral = Math.max(minOutput, Math.min(maxOutput, integral)); + kp += fuzzyDeltaToValue(kpAdjust, deltaKpScale); + ki += fuzzyDeltaToValue(kiAdjust, deltaKiScale); + kd += fuzzyDeltaToValue(kdAdjust, deltaKdScale); - // 4. 微分项计算(带低通滤波) - double derivative = params.getKd() * (error - prevError) / deltaTime; - prevError = error; // 更新误差记录 + // 限幅 + kp = Math.max(0, Math.min(kp, 10)); + ki = Math.max(0, Math.min(ki, 1)); + kd = Math.max(0, Math.min(kd, 1)); - // 5. 综合输出(0-100%) - double output = proportional + integral + derivative; + // PID 计算 + integral += error * deltaTime; + double output = kp * error + ki * integral + kd * dError; +// System.out.println("计算输出值:" + output + ",误差:" + error + ",误差变化:" + dError); + previousError = error; + + // 输出冷冻水阀开度,限制在0~100% + return Math.max(0, Math.min(100, Math.abs(output))); + } - // 6. 输出限幅 - return Math.max(minOutput, Math.min(maxOutput, output)); + // 将数值误差映射为模糊等级 + public static FuzzyLevel toFuzzyLevel(double value) { + if (value <= -3) return FuzzyLevel.NB; + else if (value <= -2) return FuzzyLevel.NM; + else if (value <= -1) return FuzzyLevel.NS; + else if (value <= 1) return FuzzyLevel.ZO; + else if (value <= 2) return FuzzyLevel.PS; + else if (value <= 3) return FuzzyLevel.PM; + else return FuzzyLevel.PB; } - // 更新设定温度 - public void setSetPoint(double setPoint) { - this.setPoint = setPoint; + // 将模糊等级转为实际数值调整量 + public static double fuzzyDeltaToValue(FuzzyLevel level, double scale) { + switch (level) { + case NB: return -3 * scale; + case NM: return -2 * scale; + case NS: return -1 * scale; + case ZO: return 0; + case PS: return 1 * scale; + case PM: return 2 * scale; + case PB: return 3 * scale; + default: return 0; + } } } diff --git a/mh-quartz/src/main/java/com/mh/quartz/util/FuzzyRuleBase.java b/mh-quartz/src/main/java/com/mh/quartz/util/FuzzyRuleBase.java new file mode 100644 index 0000000..5fc61ad --- /dev/null +++ b/mh-quartz/src/main/java/com/mh/quartz/util/FuzzyRuleBase.java @@ -0,0 +1,29 @@ +package com.mh.quartz.util; + +import com.mh.quartz.domain.FuzzyLevel; + +/** + * @Classname FuzzyRuleBase + * Todo: + * @Date 2025-05-31 14:20 + * @Created by LJF + */ +public class FuzzyRuleBase { + + // ΔKp 规则:根据误差 e 与误差变化 ec 得到修正量 + private static final FuzzyLevel[][] kpRuleTable = { + {FuzzyLevel.PB, FuzzyLevel.PM, FuzzyLevel.PS, FuzzyLevel.ZO, FuzzyLevel.NS, FuzzyLevel.NM, FuzzyLevel.NB}, + {FuzzyLevel.PM, FuzzyLevel.PS, FuzzyLevel.ZO, FuzzyLevel.NS, FuzzyLevel.NM, FuzzyLevel.NB, FuzzyLevel.NB}, + {FuzzyLevel.PS, FuzzyLevel.ZO, FuzzyLevel.NS, FuzzyLevel.NM, FuzzyLevel.NB, FuzzyLevel.NB, FuzzyLevel.NB}, + {FuzzyLevel.ZO, FuzzyLevel.ZO, FuzzyLevel.ZO, FuzzyLevel.ZO, FuzzyLevel.ZO, FuzzyLevel.ZO, FuzzyLevel.ZO}, + {FuzzyLevel.NS, FuzzyLevel.ZO, FuzzyLevel.PS, FuzzyLevel.PM, FuzzyLevel.PB, FuzzyLevel.PB, FuzzyLevel.PB}, + {FuzzyLevel.NM, FuzzyLevel.NS, FuzzyLevel.ZO, FuzzyLevel.PS, FuzzyLevel.PM, FuzzyLevel.PB, FuzzyLevel.PB}, + {FuzzyLevel.NB, FuzzyLevel.NB, FuzzyLevel.NS, FuzzyLevel.ZO, FuzzyLevel.PS, FuzzyLevel.PM, FuzzyLevel.PB} + }; + + public static FuzzyLevel getKpAdjust(FuzzyLevel e, FuzzyLevel ec) { + return kpRuleTable[e.ordinal()][ec.ordinal()]; + } + + // 可扩展为不同规则表:getKiAdjust(), getKdAdjust() +} \ No newline at end of file