From bff24e8301ed8f6accd16b93d91e84bffa28bc04 Mon Sep 17 00:00:00 2001 From: louissun Date: Fri, 14 Aug 2026 15:35:05 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E4=B8=80=E4=B8=AApy=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=8C=E5=9C=A8=E7=A8=B3=E6=80=81=E5=90=8E=E8=AE=B0?= =?UTF-8?q?=E5=BD=95=E3=80=81=E8=BE=93=E5=87=BA=E5=88=B0=E7=BB=88=E7=AB=AF?= =?UTF-8?q?=EF=BC=9A=20=E8=AF=A5=E6=AC=A1=E8=B0=83=E8=8A=82=E7=94=A8?= =?UTF-8?q?=E7=9A=84kp=EF=BC=8Cki=EF=BC=8Ckd=E5=8F=82=E6=95=B0=E4=BB=A5?= =?UTF-8?q?=E5=8F=8A=E6=8E=A7=E5=88=B6=E6=95=88=E6=9E=9C=E5=A6=82=E4=BD=95?= =?UTF-8?q?=EF=BC=8C=E5=8C=85=E6=8B=AC=E8=B0=83=E8=8A=82=E6=97=B6=E9=97=B4?= =?UTF-8?q?=EF=BC=88=E8=B0=83=E8=8A=82=E8=87=B3=E7=A8=B3=E6=80=81=E8=8A=B1?= =?UTF-8?q?=E7=9A=84=E6=97=B6=E9=97=B4=EF=BC=8C=E7=A8=B3=E6=80=81=E7=94=A8?= =?UTF-8?q?=E4=B8=A4=E4=B8=AA=E6=9D=A1=E4=BB=B6=E5=88=A4=E6=96=AD=EF=BC=9A?= =?UTF-8?q?=E7=94=A8=E6=BB=91=E5=8A=A8=E6=97=B6=E9=97=B4=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E7=9A=84=E6=96=B9=E5=B7=AE/=E6=A0=87=E5=87=86=E5=B7=AE?= =?UTF-8?q?=E5=88=A4=E6=96=AD=EF=BC=8C=E6=88=96=E8=80=85=E7=94=A8=E6=BB=91?= =?UTF-8?q?=E5=8A=A8=E7=AA=97=E5=8F=A3=E5=9D=87=E5=80=BC=E4=BB=8B=E4=BA=8E?= =?UTF-8?q?=E7=9B=AE=E6=A0=87=E5=80=BC=E4=B8=8A=E4=B8=8B2%=E8=AF=AF?= =?UTF-8?q?=E5=B7=AE=E5=B8=A6=E4=B9=8B=E9=97=B4=EF=BC=89=E3=80=81=E8=B6=85?= =?UTF-8?q?=E8=B0=83=E9=87=8F=EF=BC=88=E8=AE=B0=E5=BD=95=E7=BB=9D=E5=AF=B9?= =?UTF-8?q?=E6=95=B0=E5=80=BC=E5=92=8C=E7=9B=B8=E5=AF=B9=E7=9B=AE=E6=A0=87?= =?UTF-8?q?=E5=80=BC=E7=9A=84=E7=99=BE=E5=88=86=E6=AF=94=EF=BC=89=E3=80=81?= =?UTF-8?q?=E8=AF=A5=E6=AC=A1=E6=8E=A7=E5=88=B6=E6=89=80=E8=AE=BE=E7=BD=AE?= =?UTF-8?q?=E7=9A=84=E6=8E=A7=E5=88=B6=E8=8C=83=E5=9B=B4=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- __pycache__/config.cpython-311.pyc | Bin 0 -> 3635 bytes __pycache__/controllers.cpython-311.pyc | Bin 0 -> 9835 bytes __pycache__/data_logger.cpython-311.pyc | Bin 0 -> 9550 bytes __pycache__/flow_control.cpython-311.pyc | Bin 0 -> 19503 bytes __pycache__/main.cpython-311.pyc | Bin 0 -> 14097 bytes .../performance_reporter.cpython-311.pyc | Bin 0 -> 7139 bytes config.py | 8 + main.py | 27 ++++ performance_reporter.py | 150 ++++++++++++++++++ 9 files changed, 185 insertions(+) create mode 100644 __pycache__/config.cpython-311.pyc create mode 100644 __pycache__/controllers.cpython-311.pyc create mode 100644 __pycache__/data_logger.cpython-311.pyc create mode 100644 __pycache__/flow_control.cpython-311.pyc create mode 100644 __pycache__/main.cpython-311.pyc create mode 100644 __pycache__/performance_reporter.cpython-311.pyc create mode 100644 performance_reporter.py diff --git a/__pycache__/config.cpython-311.pyc b/__pycache__/config.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6e3201d94a211e3a1ca85c25777d24276bc267af GIT binary patch literal 3635 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 G*?$4*I^a+M literal 0 HcmV?d00001 diff --git a/__pycache__/data_logger.cpython-311.pyc b/__pycache__/data_logger.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1d28bb1d55bbac281394c119b9f27b8868eda15e GIT binary patch literal 9550 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 OA4~aPe@Cg*%l`*Rt%=b9 literal 0 HcmV?d00001 diff --git a/__pycache__/flow_control.cpython-311.pyc b/__pycache__/flow_control.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e0f9a269d5e06fcaa7b510871cbd45ada97c52e GIT binary patch literal 19503 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 Sp^KNMk68M*%iLxC@_ztVGRBqw literal 0 HcmV?d00001 diff --git a/__pycache__/main.cpython-311.pyc b/__pycache__/main.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5c231f4ca57bea36ff03c70cc5f4878b810cb80e GIT binary patch literal 14097 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 P0qMG+{7ct= literal 0 HcmV?d00001 diff --git a/__pycache__/performance_reporter.cpython-311.pyc b/__pycache__/performance_reporter.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca94e29fe595d8bce7af2574ceb97b2139d3b362 GIT binary patch literal 7139 zcma(#{ZkuPk|SyK0TKuSHUuP)FpL|y)dUpHU)~wL+DH(8!$zr)#gC`2z{dkH>i`}%x!l_!rr&CVwC-+r6rQ!B|YbCZ{{v8(xSKh92lZW^cgI>qN;TiLmp?6tf3 zuWshQ`hEV+<=odF=DxVL{NSzvp1q#T&E8!8<_^rX^67idqrm{j1pTKuI`kUNhW*@= zN70q(WbWbh?3JW4?aEys`1>qBpZnzBtCht9Q1;LFfrHiCpXB~W%!sOXkt(U`q5Gv(1#X&x>+sgLOV!O`u7OXfB|X)WrW&DnV>dN zTF^cU!RHySr zw-dyVQlFd3PCm-V9)qA)ZrsZyrgHLvod5C1H@yMM6B^>WocS-l$o}bG_QCD!uit<2 z=thyo?h*|^%1-?nAeJ9rUH;~(ljVwdj$IksIJj#$HKJzX48PT0;dr!v;7*2`*xs)KWyCwgTR` z0UqTcmxu|tGnHBt0j;Wvmh7;wM;(mwj z2BIA}=CVn;kdKn|ph_<%nJ)SQ6zWtmm3E$FEN&&KURF2b4UEv9F<(Gdd_|x4ZR}%E zI1F+uSvfB=LUU{T#LChf=l2ChJe+TghH2_N!#;-Ps3^#!j-df0#jOGAK3%rNy9-m|Cn*5Nk_g5e|(&F3*}mYmNd) zDxSg}`WKkMgPYys8MklZOWdW=EkKQZ0M#T>XeJt)crt2QY<9%Y{mwdTg+@(fqsbos z`So|E-+>X!V#f}lr!U=cKFyM(#gF%m~CQE70%cjU0p;t9tFb#m?)Xfj3UN%~3BokUr zH3WhfRSj{yb6_{4shZjq8(o6vNZ(s5~HfKLCz-h<+PZA@)kutr_wF|j_8Z4+FuTx zP~Db_1RuBI|GC-$D=1qz(^TFnpP~G_G+Syvw_PPvL8nspRB3g}{x6%4GJFp|IY~ezyn8>l8aOot*{pk!0O_6Hw84;LIT`Dp5_vz2$5J5 zX{i(5>$Q#^ru27Jhfe@V_LIvHr9#*Of!Jno?~U?s9K)QcyAT7H2Rlk+1R>9Wr2WSe zE2Zff^lYng^}kStRQCtnXnrXEr)^Np5F?xKz5eQt@__(f(n&I5ltRm*W!2v93 z-7iR_kE6#}BPBQt}VLTLR2JMom$B`;L&y@pQH|Bj?IcQNH4DK}sx0Gb?hC+0Jl22#J7z&2` z^e`vs{B%I7#)*Lg-w+Fv(B6P#2tn9EUsyZEC7t(8ma!orWATV~nVBY;FeBe+Bod

!W+=0!x(0ey+YC`YQn2!}fdRL%wc6bpMEG@%w* zC6ciy^6}QcqmR9S$&P_0Cy6DqHF~H(XsQ}AmU{kJ#%zloiuW&=or2k!I3{);6gvCm zk*u{bc2?Z7D{Xa)RyR*BS{tGh@iS>_hiL6sBd}=O8oMAi?MmC+qRq`4fMD$Ol|%d? zg?xLLeE7qxB2Lk>*y&1ki@km6&I4lS0lr_fY+Gz>itFZnmUv0rz9;S2D?0Y3IC1~U zwBuyD@s!wjimy_!Go3v$N(RZb3Fhu(XR1+rv45erU+C@6badlryFBU;%w5UG6e+&& z>VoT4!S!lpTNjSDEtxD)%U?~c3#Qii>q%0u?@F88qRB0o+!g2kD(bcmJ?!O{Vt56I~6ApMVl zuvmF68cCb&qS+pQOA&if5!UFzxK=c`#*YARiN<+*(mUUtvWeUFq|JL$)K_B*=A(l7 zs0_U%TTtT6{6B-~r0aHzb-Q`}qV>7xuj1jfwM(>u*cWS?#oG3SK3&@_)^_u{C0T(m z+?lwLw(jD|OtXE~k_e}pcP1~SoA>cGi{@IMiw%D;kv2O-vm?>CVD3UOZcjNDdJhY| zhck93-yc1d*$z>kXmNrNuARJc@`His05AUvM#9n!7yt^7Y|I;+ksQ07g$-F5yRq%y z$5qF5sRjHjdY%mhZ`qZx3Fbt~d@ULNF(Bo?i{)=cR~~+xo4W}K3%CHo-8BEM1Qo#5YKaoYPGhDE)*n z;FhW2@kKD}sc0hPrc?|OvW$umsF*3u#Cqzc31dVL>i~aBRmm}giK?c|z=ImykE*e_ zOwUp=rpDRwSWU&48lB_VoPnx^gSN;QWd%s}E+O~UK@T2aaw)>;DI4^nuV3q}pVLtd z5!m^Pgs8@d;RZo%i5Q{Y8qrft(BB*}QP07B&CliO`{Oz0-NZr@W{`VZ0iYrI#o+A0*6!hPZI^4jSzh}l74r%pKhspZYL$ouHyyJUob1FVZWu{>J_LUs z{Hd~}0mdB65gaE+gT8>PTJ|Z-e(W(8Q(+Q`SqsSsc@f`OcucAZUZ5EWCxV;@!WOB9 zew$-x81QiLB~?*Ah92U4!9Y16r1>O0Bu8kL#m%Y)Ad2H+Fu2$}`Y47&=Kz5HPjGdU zM8>v7v~|JhTEA7S-@zL*)&__s;3&d&CvRLb*T>E-m|F#N>!Q6qp-Y@e9=r8M+P+7$ z@8M5n?0XZGVBf1g(AC_{ALox}Y8qn~7HS+qjYGjZn;c1Z?MvHV674S`;{L>lVBfDk zD&ms8{d?#-_~T2>T}eZ_*`3;wZhnccfs{tgt^%pC^&~pyd*+`P>P~<=we`r=1M-pS zk-4HPv$bXV-1K>&ZU^|@A{f$e$Il9uUFw4r_n`xSS*SaLwD!qWrlCn}=oRYrBC^t@ z3<8B8YLcYbb5OAKt53$_j{jV+xYY;A_G{u}h}4gMAL>+9c`MW46zYy5`O>H5@__+h%GS8VA`o1Pa<&kLnTIbGCK0rmiT zSM(ZB15j0-E|=Q0l_}7&tWHEz>4zfP5jaQwRr4Bgm4LG!d=jVnZMf%c$N(UOOEUn6 zFitKRA@S$sI7ZTk7+-*MkxHzt_tO_>KNt$^a_7$3-XDKDAnz$V_T z6gE&=3|8o?*-5A-)n7qt(3=VbRvko38`x)Ii$mX5AU3HE@6xvx2(|j9MyJOBqpYs( z(eEq}YIR0KBF4r_SsX6OWng{*FUdR<^!pW8#LBr<#s%HX3s}kPujJ{O>7XK=!^|51 zf?*ZQK?R#zqbX=f4GGgiWg#?e0^ulsGK6_j{$&W8P= next_status_time or result.status != "OK": logger.info(format_status(result)) @@ -221,6 +241,13 @@ def run(target_flow_slm): recorder.close() exit_code = max(exit_code, 7) logger.exception("保存控制数据曲线图失败;CSV 数据仍保留") + + if reporter is not None: + try: + reporter.finalize() + except Exception: + logger.exception("生成控制性能报告时发生异常") + logger.info("程序结束,退出码=%d", exit_code) return exit_code diff --git a/performance_reporter.py b/performance_reporter.py new file mode 100644 index 0000000..4e0f765 --- /dev/null +++ b/performance_reporter.py @@ -0,0 +1,150 @@ +"""控制性能报告:在达到稳态后输出 PID 参数、调节时间、超调量和控制范围。 + +本模块只负责观测每个控制周期产出的 ControlStepResult,用滑动时间窗口判断 +稳态,并在首次进入稳态时打印一份一次性报告;不参与任何控制计算。 +""" + +from collections import deque +import math +import statistics + + +class PerformanceReporter: + """逐周期观测流量,判定稳态并输出控制性能报告。 + + 稳态判定采用两个条件同时满足(AND): + 1. 滑窗均值落在目标流量 ±band_pct% 误差带内; + 2. 滑窗标准差低于 std_pct% 目标流量阈值。 + 报告只在首次判定稳态时输出一次。 + """ + + def __init__( + self, + pid, + *, + window_s, + band_pct, + std_pct, + flow_range_min_slm, + flow_range_max_slm, + initial_flow_slm=None, + logger=None, + ): + self.pid = pid + self.window_s = float(window_s) + self.band_pct = float(band_pct) + self.std_pct = float(std_pct) + self.flow_range_min_slm = float(flow_range_min_slm) + self.flow_range_max_slm = float(flow_range_max_slm) + self.initial_flow_slm = ( + None if initial_flow_slm is None else float(initial_flow_slm) + ) + self.logger = logger + + self.target_flow_slm = None + self.settling_time_s = None + self._first_timestamp = None + self._peak_flow_slm = None + self._min_flow_slm = None + self._window = deque() # 元素为 (elapsed_s, flow_slm) + self._reached = False + + def observe(self, result): + """喂入一个 ControlStepResult;达到稳态时自动输出一次报告。""" + if self._reached: + return + if result.status != "OK" or result.measured_flow_slm is None: + return + + flow = float(result.measured_flow_slm) + if not math.isfinite(flow): + return + target = float(result.target_flow_slm) + if target <= 0.0: + return + self.target_flow_slm = target + + if self._first_timestamp is None: + self._first_timestamp = float(result.timestamp) + elapsed_s = max(0.0, float(result.timestamp) - self._first_timestamp) + + if self.initial_flow_slm is None: + self.initial_flow_slm = flow + if self._peak_flow_slm is None or flow > self._peak_flow_slm: + self._peak_flow_slm = flow + if self._min_flow_slm is None or flow < self._min_flow_slm: + self._min_flow_slm = flow + + self._window.append((elapsed_s, flow)) + cutoff = elapsed_s - self.window_s + while self._window and self._window[0][0] < cutoff: + self._window.popleft() + + if len(self._window) < 2: + return + if self._window[-1][0] - self._window[0][0] < self.window_s: + return + + flows = [item[1] for item in self._window] + mean = statistics.mean(flows) + std = statistics.pstdev(flows) + + band = self.band_pct / 100.0 * target + std_threshold = self.std_pct / 100.0 * target + if abs(mean - target) <= band and std <= std_threshold: + self._reached = True + self.settling_time_s = elapsed_s + self._report() + + def finalize(self): + """运行结束调用;若始终未达到稳态则补一条提示日志。""" + if not self._reached and self.target_flow_slm is not None: + self._log("info", "本次运行未达到稳态,未生成控制性能报告") + + def _report(self): + target = self.target_flow_slm + initial = self.initial_flow_slm + peak = self._peak_flow_slm + minimum = self._min_flow_slm + + if initial < target: + overshoot_abs = max(0.0, peak - target) + extremum_text = f"峰值 {peak:.3f} SLM" + direction = "超出目标" + elif initial > target: + overshoot_abs = max(0.0, target - minimum) + extremum_text = f"谷值 {minimum:.3f} SLM" + direction = "低于目标" + else: + overshoot_abs = 0.0 + extremum_text = f"峰值 {peak:.3f} SLM" + direction = "无" + + overshoot_pct = overshoot_abs / target * 100.0 + + lines = [ + "===== 控制性能报告 =====", + ( + f"PID 参数: Kp={self.pid.kp:.3f} Ki={self.pid.ki:.3f} " + f"Kd={self.pid.kd:.3f}" + ), + f"目标流量: {target:.3f} SLM", + ( + f"控制范围: {self.flow_range_min_slm:.3f} ~ " + f"{self.flow_range_max_slm:.3f} SLM" + ), + f"调节时间(至稳态): {self.settling_time_s:.3f} s", + f"初始流量: {initial:.3f} SLM", + ( + f"超调量: {extremum_text},{direction} " + f"{overshoot_abs:+.3f} SLM ({overshoot_pct:+.2f}%)" + ), + "========================", + ] + self._log("info", "\n".join(lines)) + + def _log(self, level, message, *args): + if self.logger is not None: + getattr(self.logger, level)(message, *args) + else: + print(message)