diff --git a/InkJetPrinter.cpp b/InkJetPrinter.cpp index 3731840..783ada6 100644 --- a/InkJetPrinter.cpp +++ b/InkJetPrinter.cpp @@ -367,51 +367,57 @@ struct DualModePIDParams { int stable_count_req; // 需要稳定的次数 // 模式切换阈值 - float switch_threshold; // 切换到精准模式的误差阈值 + float switch_threshold; // 切换到精准模式的误差阈值 + float switch_hysteresis; // 模式切换滞后带宽,避免反复切换 + float deadzone; // 死区:误差小于此值时不调整 }; -// 无分流管设备参数 +// 无分流管设备参数(调整后:降低增益,增加稳定性) static DualModePIDParams params_no_reclaim = { - // 快速模式 - 0.10f, // fast_Kp + // 快速模式:降低Kp和Kd,避免超调 + 0.06f, // fast_Kp (从0.10降到0.06) 0.0f, // fast_Ki - 0.05f, // fast_Kd - 10.0f, // fast_maxDelta - 8, // fast_cycle (800ms) + 0.02f, // fast_Kd (从0.05降到0.02) + 8.0f, // fast_maxDelta (从10.0降到8.0) + 10, // fast_cycle (从8增加到10,即1000ms) - // 精准模式 - 0.025f, // precision_Kp - 0.010f, // precision_Ki - 0.03f, // precision_Kd - 3.0f, // precision_maxDelta - 10, // precision_cycle (1000ms) - 250.0f, // integral_limit + // 精准模式:降低Ki,减缓积分速度 + 0.018f, // precision_Kp (从0.025降到0.018) + 0.005f, // precision_Ki (从0.010降到0.005) + 0.015f, // precision_Kd (从0.03降到0.015) + 2.5f, // precision_maxDelta (从3.0降到2.5) + 12, // precision_cycle (从10增加到12,即1200ms) + 150.0f, // integral_limit (从250降到150) 10, // stable_threshold 10, // stable_count_req - 50.0f // switch_threshold + 80.0f, // switch_threshold (从50增加到80,扩大快速模式工作范围) + 15.0f, // switch_hysteresis (滞后带宽:从快速切到精准需要err<80,从精准切回快速需要err>95) + 8.0f // deadzone (死区:误差±8以内不调整) }; -// 有分流管设备参数 +// 有分流管设备参数(调整后) static DualModePIDParams params_with_reclaim = { // 快速模式 - 0.12f, // fast_Kp + 0.08f, // fast_Kp (从0.12降到0.08) 0.0f, // fast_Ki - 0.08f, // fast_Kd - 12.0f, // fast_maxDelta - 8, // fast_cycle (800ms) + 0.03f, // fast_Kd (从0.08降到0.03) + 10.0f, // fast_maxDelta (从12.0降到10.0) + 10, // fast_cycle (从8增加到10,即1000ms) // 精准模式 - 0.035f, // precision_Kp - 0.015f, // precision_Ki - 0.05f, // precision_Kd - 4.0f, // precision_maxDelta - 10, // precision_cycle (1000ms) - 300.0f, // integral_limit + 0.025f, // precision_Kp (从0.035降到0.025) + 0.008f, // precision_Ki (从0.015降到0.008) + 0.020f, // precision_Kd (从0.05降到0.020) + 3.0f, // precision_maxDelta (从4.0降到3.0) + 12, // precision_cycle (从10增加到12,即1200ms) + 180.0f, // integral_limit (从300降到180) 15, // stable_threshold 8, // stable_count_req - 50.0f // switch_threshold + 80.0f, // switch_threshold (从50增加到80) + 15.0f, // switch_hysteresis + 10.0f // deadzone (死区:误差±10以内不调整) }; // PID控制器状态 @@ -651,14 +657,35 @@ void InkJetPrinter::pressureAdj() // --------------------------------------------------------------- // 双模式PID控制:根据误差大小自动切换快速/精准模式 - // 快速模式:大偏差快速收敛,周期800ms - // 精准模式:小偏差精准稳压,周期1000ms,等待压力稳定后调整 + // 快速模式:大偏差快速收敛,周期1000ms + // 精准模式:小偏差精准稳压,周期1200ms,等待压力稳定后调整 + // 带死区和模式切换滞后,避免频繁调整和模式抖动 // --------------------------------------------------------------- - // 判断当前应该使用哪种模式 + // 计算误差 float error = (float)(target - actual); float abs_error = (error < 0) ? -error : error; - bool use_precision = (abs_error <= params.switch_threshold); + + // 死区控制:误差很小时不调整,避免频繁微调 + if(abs_error < params.deadzone) + { + sysPara->para.gearPumpValue = (unsigned short)(int)u; + sysPara->devOp->WriteMoterPump(); + return; + } + + // 模式切换逻辑(带滞后,避免在阈值附近反复切换) + bool use_precision; + if(pid_ctrl.in_precision_mode) + { + // 当前在精准模式,需要误差大于阈值+滞后才切回快速模式 + use_precision = (abs_error <= params.switch_threshold + params.switch_hysteresis); + } + else + { + // 当前在快速模式,误差小于阈值即切到精准模式 + use_precision = (abs_error <= params.switch_threshold); + } int cycle = use_precision ? params.precision_cycle : params.fast_cycle; @@ -696,6 +723,7 @@ void InkJetPrinter::pressureAdj() // 压力已稳定,执行调速,重置计数 pid_ctrl.adjust_skip = 0; pid_ctrl.stable_count = 0; + pid_ctrl.in_precision_mode = true; // 精准模式使用平均压力计算 float delta_u = DualModePID_Calculate((float)target, (float)avgPressure, params, @@ -716,6 +744,7 @@ void InkJetPrinter::pressureAdj() // 快速模式:立即调整,重置计数 pid_ctrl.adjust_skip = 0; pid_ctrl.stable_count = 0; + pid_ctrl.in_precision_mode = false; // 快速模式使用瞬时压力计算 float delta_u = DualModePID_Calculate((float)target, (float)actual, params, @@ -737,7 +766,6 @@ void InkJetPrinter::pressureAdj() } - static bool firstTime = true; extern void MySleep(unsigned int msec); extern unsigned char test_flag;