From 81b0ad0124847f083990d574dc8d20961ec6e713 Mon Sep 17 00:00:00 2001
From: baoshiwei <baoshiwei@shlanbao.cn>
Date: 星期三, 01 四月 2026 14:12:55 +0800
Subject: [PATCH] feat(参数调节): 添加优化版挤出机参数调节页面
---
app/pages/metered_weight_advanced.py | 6
app/pages/metered_weight_correlation.py | 448 ++++++++++++++++++++
app/pages/optimized_parameter_adjustment.py | 811 ++++++++++++++++++++++++++++++++++++
dashboard.py | 10
4 files changed, 1,271 insertions(+), 4 deletions(-)
diff --git a/app/pages/metered_weight_advanced.py b/app/pages/metered_weight_advanced.py
index 5a9dea8..3676644 100644
--- a/app/pages/metered_weight_advanced.py
+++ b/app/pages/metered_weight_advanced.py
@@ -141,11 +141,11 @@
if 'ma_steady_window' not in st.session_state:
st.session_state['ma_steady_window'] = 20
if 'ma_steady_threshold' not in st.session_state:
- st.session_state['ma_steady_threshold'] = 0.5
+ st.session_state['ma_steady_threshold'] = 1.5
# 榛樿鐗瑰緛鍒楄〃锛堜笉鍐嶅厑璁哥敤鎴烽�夋嫨锛�
- default_features = ['铻烘潌杞��', '鏈哄ご鍘嬪姏', '娴佺▼涓婚��', '铻烘潌娓╁害',
- '鍚庢満绛掓俯搴�', '鍓嶆満绛掓俯搴�', '鏈哄ご娓╁害']
+ default_features = ['铻烘潌杞��', '鏈哄ご鍘嬪姏', '娴佺▼涓婚��', '鍚庢満绛掓俯搴�']
+
# 瀹氫箟鍥炶皟鍑芥暟
def update_dates(qs):
diff --git a/app/pages/metered_weight_correlation.py b/app/pages/metered_weight_correlation.py
index 0afb421..d6d862f 100644
--- a/app/pages/metered_weight_correlation.py
+++ b/app/pages/metered_weight_correlation.py
@@ -6,6 +6,118 @@
from datetime import datetime, timedelta
from app.services.extruder_service import ExtruderService
from app.services.main_process_service import MainProcessService
+from app.services.data_processing_service import DataProcessingService
+
+# 绋虫�佽瘑鍒被瀹氫箟
+class SteadyStateDetector:
+ def __init__(self):
+ self.data_processor = DataProcessingService()
+
+ def preprocess_data(self, df, weight_col='metered_weight', window_size=20):
+ if df is None or df.empty:
+ return df
+
+ df_processed = df.copy()
+
+ df_processed[weight_col] = df_processed[weight_col].ffill().bfill()
+ df_processed['smoothed_weight'] = df_processed[weight_col]
+ df_processed['rolling_std'] = df_processed[weight_col].rolling(window=window_size, min_periods=1).std()
+ df_processed['rolling_mean'] = df_processed[weight_col].rolling(window=window_size, min_periods=1).mean()
+
+ return df_processed
+
+ def detect_steady_state(self, df, weight_col='smoothed_weight', window_size=20, std_threshold=0.5, duration_threshold=60):
+ if df is None or df.empty:
+ return df, []
+
+ df['time'] = pd.to_datetime(df['time'])
+ df['time_diff'] = df['time'].diff().dt.total_seconds().fillna(0)
+ df['is_steady'] = 0
+
+ df['window_std'] = df['smoothed_weight'].rolling(window=window_size, min_periods=5).std()
+ df['window_mean'] = df['smoothed_weight'].rolling(window=window_size, min_periods=5).mean()
+ df['fluctuation_range'] = (df['window_std'] / df['window_mean']) * 100
+ df['fluctuation_range'] = df['fluctuation_range'].fillna(0)
+
+ df.loc[(df['fluctuation_range'] < std_threshold) & (df['smoothed_weight'] >= 0.1), 'is_steady'] = 1
+
+ steady_segments = []
+ current_segment = {}
+
+ for i, row in df.iterrows():
+ if row['is_steady'] == 1:
+ if not current_segment:
+ current_segment = {
+ 'start_time': row['time'],
+ 'start_idx': i,
+ 'weights': [row['smoothed_weight']]
+ }
+ else:
+ current_segment['weights'].append(row['smoothed_weight'])
+ else:
+ if current_segment:
+ current_segment['end_time'] = df.loc[i-1, 'time'] if i > 0 else df.loc[i, 'time']
+ current_segment['end_idx'] = i-1
+ duration = (current_segment['end_time'] - current_segment['start_time']).total_seconds()
+
+ if duration >= duration_threshold:
+ weights_array = np.array(current_segment['weights'])
+ current_segment['duration'] = duration
+ current_segment['mean_weight'] = np.mean(weights_array)
+ current_segment['std_weight'] = np.std(weights_array)
+ current_segment['min_weight'] = np.min(weights_array)
+ current_segment['max_weight'] = np.max(weights_array)
+ current_segment['fluctuation_range'] = (current_segment['std_weight'] / current_segment['mean_weight']) * 100
+
+ confidence = 100 - (current_segment['fluctuation_range'] / std_threshold) * 50
+ confidence = max(50, min(100, confidence))
+ current_segment['confidence'] = confidence
+
+ steady_segments.append(current_segment)
+
+ current_segment = {}
+
+ if current_segment:
+ current_segment['end_time'] = df['time'].iloc[-1]
+ current_segment['end_idx'] = len(df) - 1
+ duration = (current_segment['end_time'] - current_segment['start_time']).total_seconds()
+
+ if duration >= duration_threshold:
+ weights_array = np.array(current_segment['weights'])
+ current_segment['duration'] = duration
+ current_segment['mean_weight'] = np.mean(weights_array)
+ current_segment['std_weight'] = np.std(weights_array)
+ current_segment['min_weight'] = np.min(weights_array)
+ current_segment['max_weight'] = np.max(weights_array)
+ current_segment['fluctuation_range'] = (current_segment['std_weight'] / current_segment['mean_weight']) * 100
+
+ confidence = 100 - (current_segment['fluctuation_range'] / std_threshold) * 50
+ confidence = max(50, min(100, confidence))
+ current_segment['confidence'] = confidence
+
+ steady_segments.append(current_segment)
+
+ for segment in steady_segments:
+ df.loc[segment['start_idx']:segment['end_idx'], 'is_steady'] = 1
+
+ return df, steady_segments
+
+ def get_steady_state_metrics(self, steady_segments):
+ if not steady_segments:
+ return {}
+
+ avg_duration = np.mean([seg['duration'] for seg in steady_segments])
+ avg_fluctuation = np.mean([seg['fluctuation_range'] for seg in steady_segments])
+ avg_confidence = np.mean([seg['confidence'] for seg in steady_segments])
+ total_steady_duration = sum([seg['duration'] for seg in steady_segments])
+
+ return {
+ 'total_steady_segments': len(steady_segments),
+ 'average_steady_duration': avg_duration,
+ 'average_fluctuation_range': avg_fluctuation,
+ 'average_confidence': avg_confidence,
+ 'total_steady_duration': total_steady_duration
+ }
def show_metered_weight_correlation():
# 鍒濆鍖栨湇鍔�
@@ -14,6 +126,11 @@
# 椤甸潰鏍囬
st.title("绫抽噸鐩稿叧鎬у垎鏋�")
+
+ # 鍒濆鍖栨湇鍔�
+ extruder_service = ExtruderService()
+ main_process_service = MainProcessService()
+ steady_state_detector = SteadyStateDetector()
# 鍒濆鍖栦細璇濈姸鎬佺敤浜庢棩鏈熷悓姝�
if 'mc_start_date' not in st.session_state:
@@ -24,6 +141,16 @@
st.session_state['mc_quick_select'] = "鏈�杩�7澶�"
if 'mc_time_offset' not in st.session_state:
st.session_state['mc_time_offset'] = 0.0
+
+ # 鍒濆鍖栫ǔ鎬佽瘑鍒浉鍏冲弬鏁�
+ if 'mc_ss_window_size' not in st.session_state:
+ st.session_state['mc_ss_window_size'] = 20
+ if 'mc_ss_std_threshold' not in st.session_state:
+ st.session_state['mc_ss_std_threshold'] = 1.5
+ if 'mc_ss_duration_threshold' not in st.session_state:
+ st.session_state['mc_ss_duration_threshold'] = 60
+ if 'mc_use_steady_only' not in st.session_state:
+ st.session_state['mc_use_steady_only'] = False
# 瀹氫箟鍥炶皟鍑芥暟
def update_dates(qs):
@@ -114,6 +241,55 @@
st.session_state['mc_time_offset'] = time_offset
with offset_cols[2]:
st.write(f"褰撳墠鍋忕Щ: {time_offset} 鍒嗛挓")
+
+ # 绋虫�佸弬鏁伴厤缃�
+ st.markdown("---")
+ steady_state_cols = st.columns(4)
+
+ with steady_state_cols[0]:
+ st.write("鈿欙笍 **绋虫�佸弬鏁伴厤缃�**")
+ window_size = st.slider(
+ "婊戝姩绐楀彛澶у皬 (绉�)",
+ min_value=5,
+ max_value=60,
+ value=st.session_state['mc_ss_window_size'],
+ step=5,
+ key="mc_ss_window_size",
+ help="鐢ㄤ簬骞虫粦鏁版嵁鍜岃绠楃粺璁$壒寰佺殑婊戝姩绐楀彛澶у皬"
+ )
+
+ with steady_state_cols[1]:
+ st.write("馃搹 **娉㈠姩闃堝�奸厤缃�**")
+ std_threshold = st.slider(
+ "鏍囧噯宸槇鍊�",
+ min_value=0.1,
+ max_value=2.0,
+ value=st.session_state['mc_ss_std_threshold'],
+ step=0.1,
+ key="mc_ss_std_threshold",
+ help="绫抽噸娉㈠姩鐨勬爣鍑嗗樊闃堝�硷紝浣庝簬姝ゅ�艰涓虹ǔ鎬�"
+ )
+
+ with steady_state_cols[2]:
+ st.write("鈴憋笍 **鎸佺画鏃堕棿閰嶇疆**")
+ duration_threshold = st.slider(
+ "绋虫�佹寔缁椂闂� (绉�)",
+ min_value=30,
+ max_value=300,
+ value=st.session_state['mc_ss_duration_threshold'],
+ step=10,
+ key="mc_ss_duration_threshold",
+ help="绋虫�佹寔缁殑鏈�灏忔椂闂达紝浣庝簬姝ゅ�间笉瑙嗕负绋虫�佹"
+ )
+
+ with steady_state_cols[3]:
+ st.write("馃幆 **鍒嗘瀽鏁版嵁閫夋嫨**")
+ use_steady_only = st.checkbox(
+ "浠呬娇鐢ㄧǔ鎬佹暟鎹�",
+ value=st.session_state['mc_use_steady_only'],
+ key="mc_use_steady_only",
+ help="鍕鹃�夊悗锛岀浉鍏虫�у垎鏋愪粎浣跨敤璇嗗埆鍑虹殑绋虫�佹暟鎹�"
+ )
# 杞崲涓篸atetime瀵硅薄
start_dt = datetime.combine(start_date, datetime.min.time())
@@ -264,6 +440,32 @@
return df_merged
+ # 鎵ц绋虫�佽瘑鍒�
+ df_extruder_steady, steady_segments = None, []
+ if df_extruder_filtered is not None and not df_extruder_filtered.empty:
+ # 鏁版嵁棰勫鐞�
+ df_processed = steady_state_detector.preprocess_data(
+ df_extruder_filtered,
+ weight_col='metered_weight',
+ window_size=st.session_state['mc_ss_window_size']
+ )
+
+ # 绋虫�佹娴�
+ df_extruder_steady, steady_segments = steady_state_detector.detect_steady_state(
+ df_processed,
+ weight_col='smoothed_weight',
+ window_size=st.session_state['mc_ss_window_size'],
+ std_threshold=st.session_state['mc_ss_std_threshold'],
+ duration_threshold=st.session_state['mc_ss_duration_threshold']
+ )
+
+ # 灏嗙ǔ鎬佹爣璁版坊鍔犲埌df_extruder_filtered涓紝浠ヤ究鍦ㄨ秼鍔垮浘涓娇鐢�
+ df_extruder_filtered = df_extruder_filtered.merge(
+ df_extruder_steady[['time', 'is_steady', 'smoothed_weight', 'fluctuation_range']],
+ on='time',
+ how='left'
+ )
+
# 鎵ц鏁版嵁鏁村悎
df_analysis = integrate_data(df_extruder_filtered, df_main_speed, df_temp)
@@ -273,6 +475,26 @@
# 閲嶅懡鍚嶇背閲嶅垪
df_analysis.rename(columns={'metered_weight': '绫抽噸'}, inplace=True)
+
+ # 濡傛灉閫夋嫨浠呬娇鐢ㄧǔ鎬佹暟鎹紝杩囨护鎺夐潪绋虫�佹暟鎹�
+ if st.session_state['mc_use_steady_only']:
+ # 纭繚df_analysis鍖呭惈is_steady鍒�
+ if 'is_steady' not in df_analysis.columns:
+ # 灏嗙ǔ鎬佹爣璁板悎骞跺埌鍒嗘瀽鏁版嵁涓�
+ df_analysis = df_analysis.merge(
+ df_extruder_steady[['time', 'is_steady']],
+ on='time',
+ how='left'
+ )
+ # 杩囨护绋虫�佹暟鎹�
+ df_analysis = df_analysis[df_analysis['is_steady'] == 1]
+ if df_analysis.empty:
+ st.warning("鏈壘鍒扮ǔ鎬佹暟鎹紝璇疯皟鏁寸ǔ鎬佸弬鏁版垨鍙栨秷'浠呬娇鐢ㄧǔ鎬佹暟鎹�'閫夐」銆�")
+ return
+
+ # 缂撳瓨绋虫�佹暟鎹埌浼氳瘽鐘舵��
+ st.session_state['cached_steady_segments'] = steady_segments
+ st.session_state['cached_extruder_steady'] = df_extruder_steady
# --- 鍘熷鏁版嵁瓒嬪娍鍥� ---
st.subheader("馃搱 鍘熷鏁版嵁瓒嬪娍鍥�")
@@ -360,6 +582,24 @@
yaxis='y5'
))
+ # 娣诲姞绋虫�佸尯鍩熸爣璁�
+ for segment in steady_segments:
+ # 鑾峰彇绫抽噸鏁版嵁鐨剏杞磋寖鍥达紝鐢ㄤ簬纭畾鐭╁舰楂樺害
+ y_min = df_extruder_filtered['metered_weight'].min() * 0.95
+ y_max = df_extruder_filtered['metered_weight'].max() * 1.05
+
+ fig_trend.add_shape(
+ type="rect",
+ x0=segment['start_time'],
+ y0=y_min,
+ x1=segment['end_time'],
+ y1=y_max,
+ fillcolor="rgba(0, 255, 0, 0.2)",
+ line=dict(color="rgba(0, 200, 0, 0.5)", width=1),
+ name="绋虫�佸尯鍩�",
+ layer="below"
+ )
+
# 閰嶇疆瓒嬪娍鍥惧竷灞�
fig_trend.update_layout(
title=f'鍘熷鏁版嵁瓒嬪娍 (绫抽噸鍚戝墠鍋忕Щ {st.session_state["mc_time_offset"]} 鍒嗛挓)',
@@ -423,6 +663,214 @@
# 鏄剧ず瓒嬪娍鍥�
selection = st.plotly_chart(fig_trend, width='stretch', config={'scrollZoom': True}, on_select='rerun' )
+ # 绋虫�佺粺璁℃寚鏍�
+ st.subheader("馃搳 绋虫�佽瘑鍒粺璁�")
+ steady_metrics = steady_state_detector.get_steady_state_metrics(steady_segments)
+ metrics_cols = st.columns(5)
+
+ with metrics_cols[0]:
+ st.metric(
+ "绋虫�佹鎬绘暟",
+ steady_metrics.get('total_steady_segments', 0),
+ help="璇嗗埆鍒扮殑绋虫�佹鏁伴噺"
+ )
+
+ with metrics_cols[1]:
+ st.metric(
+ "骞冲潎绋虫�佹椂闀�",
+ f"{steady_metrics.get('average_steady_duration', 0):.2f} 绉�",
+ help="鎵�鏈夌ǔ鎬佹鐨勫钩鍧囨寔缁椂闂�"
+ )
+
+ with metrics_cols[2]:
+ st.metric(
+ "骞冲潎娉㈠姩鑼冨洿",
+ f"{steady_metrics.get('average_fluctuation_range', 0):.2f}%",
+ help="绋虫�佹鍐呯背閲嶇殑骞冲潎娉㈠姩鑼冨洿锛堢浉瀵逛簬鍧囧�肩殑鐧惧垎姣旓級"
+ )
+
+ with metrics_cols[3]:
+ st.metric(
+ "骞冲潎缃俊搴�",
+ f"{steady_metrics.get('average_confidence', 0):.1f}%",
+ help="绋虫�佽瘑鍒粨鏋滅殑骞冲潎缃俊搴�"
+ )
+
+ with metrics_cols[4]:
+ st.metric(
+ "鎬荤ǔ鎬佹椂闀�",
+ f"{steady_metrics.get('total_steady_duration', 0)/60:.2f} 鍒嗛挓",
+ help="鎵�鏈夌ǔ鎬佹鐨勬�绘寔缁椂闂�"
+ )
+
+ # --- 绋虫�佹暟鎹秼鍔垮浘 ---
+ st.subheader("馃搳 绋虫�佹暟鎹秼鍔垮浘")
+
+ # 鍒涘缓绋虫�佹暟鎹秼鍔垮浘
+ if df_extruder_steady is not None and not df_extruder_steady.empty:
+ fig_steady = go.Figure()
+
+ # 娣诲姞鍘熷绫抽噸鏁版嵁
+ fig_steady.add_trace(go.Scatter(
+ x=df_extruder_steady['time'],
+ y=df_extruder_steady['metered_weight'],
+ name='鍘熷绫抽噸',
+ mode='lines',
+ opacity=0.6,
+ line=dict(color='lightblue', width=1)
+ ))
+
+ # 娣诲姞骞虫粦鍚庣殑绫抽噸鏁版嵁
+ fig_steady.add_trace(go.Scatter(
+ x=df_extruder_steady['time'],
+ y=df_extruder_steady['smoothed_weight'],
+ name='骞虫粦绫抽噸',
+ mode='lines',
+ line=dict(color='blue', width=2)
+ ))
+
+ # 娣诲姞娉㈠姩鑼冨洿锛堜綔涓洪潰绉浘锛�
+ fig_steady.add_trace(go.Scatter(
+ x=df_extruder_steady['time'],
+ y=df_extruder_steady['metered_weight'] + df_extruder_steady['rolling_std'],
+ name='娉㈠姩涓婇檺',
+ mode='lines',
+ line=dict(color='rgba(255,0,0,0)'),
+ showlegend=True
+ ))
+
+ fig_steady.add_trace(go.Scatter(
+ x=df_extruder_steady['time'],
+ y=df_extruder_steady['metered_weight'] - df_extruder_steady['rolling_std'],
+ name='娉㈠姩涓嬮檺',
+ mode='lines',
+ line=dict(color='rgba(255,0,0,0)'),
+ fill='tonexty',
+ fillcolor='rgba(255,0,0,0.1)'
+ ))
+
+ # 娣诲姞绋虫�佹爣璁�
+ fig_steady.add_trace(go.Scatter(
+ x=df_extruder_steady['time'],
+ y=df_extruder_steady['is_steady'] * (df_extruder_steady['metered_weight'].max() * 1.1),
+ name='绋虫�佹爣璁�',
+ mode='lines',
+ line=dict(color='green', width=1, dash='dash')
+ ))
+
+ # 閰嶇疆绋虫�佹暟鎹秼鍔垮浘甯冨眬
+ fig_steady.update_layout(
+ title="绋虫�佹暟鎹秼鍔垮垎鏋�",
+ xaxis=dict(
+ title='鏃堕棿',
+ rangeslider=dict(visible=True),
+ type='date'
+ ),
+ yaxis=dict(
+ title='绫抽噸 (Kg/m)',
+ title_font=dict(color='blue'),
+ tickfont=dict(color='blue')
+ ),
+ yaxis2=dict(
+ title='绋虫�佹爣璁�',
+ title_font=dict(color='green'),
+ tickfont=dict(color='green'),
+ overlaying='y',
+ side='right',
+ range=[-0.1, 1.1],
+ showgrid=False
+ ),
+ legend=dict(
+ orientation="h",
+ yanchor="bottom",
+ y=1.02,
+ xanchor="right",
+ x=1
+ ),
+ height=500,
+ margin=dict(l=100, r=100, t=100, b=100),
+ hovermode='x unified'
+ )
+
+ # 鏄剧ず绋虫�佹暟鎹秼鍔垮浘
+ st.plotly_chart(fig_steady, width='stretch', config={'scrollZoom': True})
+
+ # --- 绋虫�佸弬鏁扮浉鍏虫�ц秼鍔垮浘 ---
+ st.subheader("馃搱 绋虫�佸弬鏁扮浉鍏虫�ц秼鍔垮浘")
+
+ if df_analysis is not None and not df_analysis.empty:
+ # 鍒涘缓绋虫�佸弬鏁扮浉鍏虫�ц秼鍔垮浘
+ fig_steady_corr = go.Figure()
+
+ # 閫夋嫨鐩稿叧绯绘暟鏈�楂樼殑鍓�3涓弬鏁�
+ if '绫抽噸' in df_analysis.columns:
+ # 璁$畻鍚勫弬鏁颁笌绫抽噸鐨勭浉鍏崇郴鏁�
+ corr_with_weight = df_analysis.corr()[['绫抽噸']].sort_values('绫抽噸', ascending=False)
+ top_params = corr_with_weight.index[1:4] # 鎺掗櫎绫抽噸鏈韩锛屽彇鍓�3涓�
+
+ # 娣诲姞绫抽噸鏁版嵁
+ fig_steady_corr.add_trace(go.Scatter(
+ x=df_analysis['time'],
+ y=df_analysis['绫抽噸'],
+ name='绫抽噸',
+ mode='lines',
+ line=dict(color='blue', width=2),
+ yaxis='y'
+ ))
+
+ # 娣诲姞鐩稿叧鍙傛暟鏁版嵁
+ colors = ['red', 'green', 'orange']
+ for i, param in enumerate(top_params):
+ if param in df_analysis.columns:
+ fig_steady_corr.add_trace(go.Scatter(
+ x=df_analysis['time'],
+ y=df_analysis[param],
+ name=param,
+ mode='lines',
+ line=dict(color=colors[i], width=1.5),
+ yaxis=f'y{i+2}'
+ ))
+
+ # 閰嶇疆鍥捐〃甯冨眬
+ layout = {
+ 'title': f'绫抽噸涓庣浉鍏冲弬鏁拌秼鍔匡紙鍓�3涓浉鍏冲弬鏁帮級',
+ 'xaxis': {
+ 'title': '鏃堕棿',
+ 'rangeslider': dict(visible=True),
+ 'type': 'date'
+ },
+ 'yaxis': {
+ 'title': '绫抽噸 (Kg/m)',
+ 'title_font': dict(color='blue'),
+ 'tickfont': dict(color='blue')
+ },
+ 'legend': {
+ 'orientation': "h",
+ 'yanchor': "bottom",
+ 'y': 1.02,
+ 'xanchor': "right",
+ 'x': 1
+ },
+ 'height': 600,
+ 'margin': dict(l=100, r=200, t=100, b=100),
+ 'hovermode': 'x unified'
+ }
+
+ # 娣诲姞棰濆鐨剏杞撮厤缃�
+ for i, param in enumerate(top_params):
+ layout[f'yaxis{i+2}'] = {
+ 'title': param,
+ 'title_font': dict(color=colors[i]),
+ 'tickfont': dict(color=colors[i]),
+ 'overlaying': 'y',
+ 'side': 'right',
+ 'anchor': 'free',
+ 'position': 1 - (i+1)*0.15
+ }
+
+ fig_steady_corr.update_layout(layout)
+ st.plotly_chart(fig_steady_corr, width='stretch', config={'scrollZoom': True})
+
# 璋冭瘯杈撳嚭
# st.write("鍘熷 selection 瀵硅薄:", selection)
diff --git a/app/pages/optimized_parameter_adjustment.py b/app/pages/optimized_parameter_adjustment.py
new file mode 100644
index 0000000..750de02
--- /dev/null
+++ b/app/pages/optimized_parameter_adjustment.py
@@ -0,0 +1,811 @@
+import streamlit as st
+import plotly.express as px
+import plotly.graph_objects as go
+import pandas as pd
+import numpy as np
+import joblib
+import os
+from datetime import datetime
+from sklearn.preprocessing import MinMaxScaler
+
+# 椤甸潰鍑芥暟瀹氫箟
+def show_optimized_parameter_adjustment():
+ # 椤甸潰鏍囬
+ st.title("浼樺寲鐗堟尋鍑烘満鍙傛暟璋冭妭寤鸿")
+
+ # 娣诲姞鎿嶄綔鎸囧紩
+ with st.expander("馃摉 鎿嶄綔鎸囧紩", expanded=True):
+ st.markdown("""
+ 娆㈣繋浣跨敤浼樺寲鐗堟尋鍑烘満鍙傛暟璋冭妭寤鸿鍔熻兘锛佹湰鍔熻兘鍩轰簬澶氱洰鏍囦紭鍖栫畻娉曪紝鏍规嵁鎮ㄨ緭鍏ョ殑绫抽噸鏁版嵁鍜屽綋鍓嶅弬鏁帮紝涓烘偍鎻愪緵绉戝鍚堢悊鐨勫弬鏁拌皟鏁村缓璁��
+
+ **鎿嶄綔姝ラ锛�**
+ 1. 閫夋嫨涓�涓凡璁粌濂界殑妯″瀷
+ 2. 杈撳叆绫抽噸鏍囧噯鍊笺�佷笂涓嬮檺鍜屽綋鍓嶆尋鍑烘満鍙傛暟
+ 3. 杈撳叆褰撳墠瀹為檯绫抽噸娴嬮噺鍊�
+ 4. 璋冩暣浼樺寲鍙傛暟锛堝彲閫夛級
+ 5. 鐐瑰嚮"璁$畻浼樺寲璋冭妭寤鸿"鎸夐挳
+ 6. 鏌ョ湅绯荤粺鐢熸垚鐨勫弬鏁拌皟鏁村缓璁�
+
+ **娉ㄦ剰浜嬮」锛�**
+ - 璇风‘淇濊緭鍏ョ殑鍙傛暟鍊煎湪璁惧鍏佽鐨勮寖鍥村唴
+ - 浼樺寲绠楁硶浼氬钩琛$背閲嶅亸宸拰璋冩暣骞呭害
+ - 鍘嗗彶璋冭妭璁板綍鍙湪椤甸潰搴曢儴鏌ョ湅
+ """)
+
+ # 鍒濆鍖栦細璇濈姸鎬�
+ if 'optimized_adjustment_history' not in st.session_state:
+ st.session_state['optimized_adjustment_history'] = []
+
+ # 1. 妯″瀷閫夋嫨鍖哄煙
+ with st.expander("馃攳 妯″瀷閫夋嫨", expanded=True):
+ # 鍒涘缓妯″瀷鐩綍锛堝鏋滀笉瀛樺湪锛�
+ model_dir = "saved_models"
+ os.makedirs(model_dir, exist_ok=True)
+
+ # 鑾峰彇鎵�鏈夊凡淇濆瓨鐨勬ā鍨嬫枃浠�
+ model_files = [f for f in os.listdir(model_dir) if f.endswith('.joblib')]
+ model_files.sort(reverse=True) # 鏈�鏂扮殑妯″瀷鎺掑湪鍓嶉潰
+
+ if not model_files:
+ st.warning("灏氭湭淇濆瓨浠讳綍妯″瀷锛岃鍏堣缁冩ā鍨嬪苟淇濆瓨銆�")
+ return
+
+ # 妯″瀷閫夋嫨涓嬫媺妗�
+ selected_model_file = st.selectbox(
+ "閫夋嫨宸蹭繚瀛樼殑妯″瀷",
+ options=model_files,
+ help="閫夋嫨瑕佺敤浜庨娴嬬殑妯″瀷鏂囦欢"
+ )
+
+ # 鍔犺浇骞舵樉绀烘ā鍨嬩俊鎭�
+ if selected_model_file:
+ model_path = os.path.join(model_dir, selected_model_file)
+ model_info = joblib.load(model_path)
+
+ # 鏄剧ず妯″瀷鍩烘湰淇℃伅
+ st.subheader("馃搳 妯″瀷淇℃伅")
+ info_cols = st.columns(2)
+
+ with info_cols[0]:
+ st.metric("妯″瀷绫诲瀷", model_info['model_type'])
+ st.metric("鍒涘缓鏃堕棿", model_info['created_at'].strftime('%Y-%m-%d %H:%M:%S'))
+ st.metric("浣跨敤绋虫�佹暟鎹�", "鏄�" if model_info.get('use_steady_data', False) else "鍚�")
+
+ with info_cols[1]:
+ st.metric("R虏 寰楀垎", f"{model_info['r2_score']:.4f}")
+ st.metric("鍧囨柟璇樊 (MSE)", f"{model_info['mse']:.6f}")
+ st.metric("鍧囨柟鏍硅宸� (RMSE)", f"{model_info['rmse']:.6f}")
+
+ # 鏄剧ず妯″瀷鐗瑰緛
+ st.write("馃攽 妯″瀷浣跨敤鐨勭壒寰�:")
+ st.code(", ".join(model_info['features']))
+
+ # 濡傛灉鏄繁搴﹀涔犳ā鍨嬶紝鏄剧ず搴忓垪闀垮害
+ if 'sequence_length' in model_info:
+ st.metric("搴忓垪闀垮害", model_info['sequence_length'])
+
+ # 淇濆瓨妯″瀷淇℃伅鍒颁細璇濈姸鎬�
+ st.session_state['selected_model'] = model_info
+ st.session_state['selected_model_file'] = selected_model_file
+
+ # 2. 鍙傛暟杈撳叆鍖哄煙
+ st.subheader("馃摑 鍙傛暟杈撳叆")
+
+ # 2.1 绫抽噸鏍囧噯鍊笺�佷笂涓嬮檺杈撳叆
+ with st.expander("鈿栵笍 绫抽噸鏍囧噯涓庝笂涓嬮檺", expanded=True):
+ weight_cols = st.columns(3)
+
+ with weight_cols[0]:
+ standard_weight = st.number_input(
+ "鏍囧噯绫抽噸",
+ key="standard_weight",
+ value=5.20,
+ min_value=0.01,
+ max_value=10.0,
+ step=0.0001,
+ format="%.4f",
+ help="杈撳叆鐩爣绫抽噸鏍囧噯鍊�"
+ )
+ st.caption("鍗曚綅: Kg/m")
+
+ with weight_cols[1]:
+ upper_limit = st.number_input(
+ "绫抽噸涓婇檺",
+ key="upper_limit",
+ value=5.46,
+ min_value=standard_weight,
+ max_value=10.0,
+ step=0.0001,
+ format="%.4f",
+ help="杈撳叆绫抽噸鍏佽鐨勪笂闄愬��"
+ )
+ st.caption("鍗曚綅: Kg/m")
+
+ with weight_cols[2]:
+ lower_limit = st.number_input(
+ "绫抽噸涓嬮檺",
+ key="lower_limit",
+ value=5.02,
+ min_value=0.01,
+ max_value=standard_weight,
+ step=0.0001,
+ format="%.4f",
+ help="杈撳叆绫抽噸鍏佽鐨勪笅闄愬��"
+ )
+ st.caption("鍗曚綅: Kg/m")
+
+ # 2.2 鎸ゅ嚭鏈哄綋鍓嶅弬鏁拌緭鍏�
+ with st.expander("馃敡 鎸ゅ嚭鏈哄綋鍓嶅弬鏁�", expanded=True):
+ param_cols = st.columns(3)
+
+ with param_cols[0]:
+ current_screw_speed = st.number_input(
+ "铻烘潌杞��",
+ key="current_screw_speed",
+ value=230.0,
+ min_value=0.0,
+ max_value=500.0,
+ step=0.1,
+ help="杈撳叆褰撳墠铻烘潌杞��"
+ )
+ st.caption("鍗曚綅: rpm")
+
+ current_head_pressure = st.number_input(
+ "鏈哄ご鍘嬪姏",
+ key="current_head_pressure",
+ value=0.26,
+ min_value=0.0,
+ max_value=500.0,
+ format="%.4f",
+ step=1.0,
+ help="杈撳叆褰撳墠鏈哄ご鍘嬪姏"
+ )
+ st.caption("鍗曚綅: bar")
+
+ current_process_speed = st.number_input(
+ "娴佺▼涓婚��",
+ key="current_process_speed",
+ value=6.6,
+ min_value=0.0,
+ max_value=300.0,
+ step=0.1,
+ help="杈撳叆褰撳墠娴佺▼涓婚��"
+ )
+ st.caption("鍗曚綅: m/min")
+
+ with param_cols[1]:
+ current_screw_temperature = st.number_input(
+ "铻烘潌娓╁害",
+ key="current_screw_temperature",
+ value=79.9,
+ min_value=0.0,
+ max_value=300.0,
+ step=1.0,
+ help="杈撳叆褰撳墠铻烘潌娓╁害"
+ )
+ st.caption("鍗曚綅: 掳C")
+
+ current_rear_barrel_temperature = st.number_input(
+ "鍚庢満绛掓俯搴�",
+ key="current_rear_barrel_temperature",
+ value=79.9,
+ min_value=0.0,
+ max_value=300.0,
+ step=1.0,
+ help="杈撳叆褰撳墠鍚庢満绛掓俯搴�"
+ )
+ st.caption("鍗曚綅: 掳C")
+
+ with param_cols[2]:
+ current_front_barrel_temperature = st.number_input(
+ "鍓嶆満绛掓俯搴�",
+ key="current_front_barrel_temperature",
+ value=80.1,
+ min_value=0.0,
+ max_value=300.0,
+ step=1.0,
+ help="杈撳叆褰撳墠鍓嶆満绛掓俯搴�"
+ )
+ st.caption("鍗曚綅: 掳C")
+
+ current_head_temperature = st.number_input(
+ "鏈哄ご娓╁害",
+ key="current_head_temperature",
+ value=95.1,
+ min_value=0.0,
+ max_value=300.0,
+ step=1.0,
+ help="杈撳叆褰撳墠鏈哄ご娓╁害"
+ )
+ st.caption("鍗曚綅: 掳C")
+
+ # 2.3 褰撳墠瀹為檯绫抽噸娴嬮噺鍊艰緭鍏�
+ with st.expander("馃搹 褰撳墠瀹為檯绫抽噸", expanded=True):
+ actual_weight = st.number_input(
+ "褰撳墠瀹為檯绫抽噸",
+ key="actual_weight",
+ value=5.115,
+ min_value=0.01,
+ max_value=10.0,
+ step=0.0001,
+ format="%.4f",
+ help="杈撳叆褰撳墠瀹為檯娴嬮噺鐨勭背閲嶅��"
+ )
+ st.caption("鍗曚綅: Kg/m")
+
+ # 3. 浼樺寲鍙傛暟璁剧疆
+ st.subheader("鈿欙笍 浼樺寲鍙傛暟璁剧疆")
+
+ with st.expander("馃幆 澶氱洰鏍囦紭鍖栧弬鏁�", expanded=True):
+ # 鐩爣鏉冮噸璁剧疆
+ st.write("### 鐩爣鏉冮噸")
+ st.markdown("璋冩暣浠ヤ笅鏉冮噸鏉ュ钩琛$背閲嶅亸宸拰璋冩暣骞呭害鐨勯噸瑕佹�э細")
+ weight_cols = st.columns(2)
+
+ with weight_cols[0]:
+ weight_deviation = st.slider(
+ "绫抽噸鍋忓樊鏉冮噸",
+ min_value=0.1,
+ max_value=1.0,
+ value=0.8,
+ step=0.1,
+ help="鏉冮噸瓒婇珮锛岃秺浼樺厛鑰冭檻鍑忓皯绫抽噸鍋忓樊"
+ )
+
+ with weight_cols[1]:
+ weight_adjustment = st.slider(
+ "璋冩暣骞呭害鏉冮噸",
+ min_value=0.1,
+ max_value=1.0,
+ value=0.2,
+ step=0.1,
+ help="鏉冮噸瓒婇珮锛岃秺浼樺厛鑰冭檻鍑忓皯璋冩暣骞呭害"
+ )
+
+ # 璋冩暣鏉冮噸锛岀‘淇濇�诲拰涓�1
+ total_weight = weight_deviation + weight_adjustment
+ weight_deviation = weight_deviation / total_weight
+ weight_adjustment = weight_adjustment / total_weight
+
+ st.write(f"### 璋冩暣鍚庢潈閲嶏紙鎬诲拰涓�1锛�")
+ st.write(f"- 绫抽噸鍋忓樊鏉冮噸: {weight_deviation:.2f}")
+ st.write(f"- 璋冩暣骞呭害鏉冮噸: {weight_adjustment:.2f}")
+
+ # 鍙傛暟璋冩暣绾︽潫
+ st.write("### 鍙傛暟璋冩暣绾︽潫")
+ constraint_cols = st.columns(2)
+
+ with constraint_cols[0]:
+ max_screw_speed_adjust = st.slider(
+ "铻烘潌杞�熸渶澶ц皟鏁村箙搴�(%)",
+ min_value=5.0,
+ max_value=20.0,
+ value=15.0,
+ step=1.0,
+ help="鍗曟璋冩暣鐨勬渶澶х櫨鍒嗘瘮"
+ )
+
+ with constraint_cols[1]:
+ max_process_speed_adjust = st.slider(
+ "娴佺▼涓婚�熸渶澶ц皟鏁村箙搴�(%)",
+ min_value=3.0,
+ max_value=15.0,
+ value=10.0,
+ step=1.0,
+ help="鍗曟璋冩暣鐨勬渶澶х櫨鍒嗘瘮"
+ )
+
+ # 4. 璁$畻浼樺寲璋冭妭寤鸿
+ st.subheader("馃殌 璁$畻浼樺寲璋冭妭寤鸿")
+
+ if st.button("馃搳 璁$畻浼樺寲璋冭妭寤鸿", key="calculate_optimized_adjustment"):
+ # 鍙傛暟楠岃瘉
+ validation_errors = []
+
+ if standard_weight <= 0:
+ validation_errors.append("鏍囧噯绫抽噸蹇呴』澶т簬0")
+
+ if upper_limit <= standard_weight:
+ validation_errors.append("绫抽噸涓婇檺蹇呴』澶т簬鏍囧噯绫抽噸")
+
+ if lower_limit >= standard_weight:
+ validation_errors.append("绫抽噸涓嬮檺蹇呴』灏忎簬鏍囧噯绫抽噸")
+
+ if current_screw_speed <= 0:
+ validation_errors.append("铻烘潌杞�熷繀椤诲ぇ浜�0")
+
+ if current_process_speed <= 0:
+ validation_errors.append("娴佺▼涓婚�熷繀椤诲ぇ浜�0")
+
+ if actual_weight <= 0:
+ validation_errors.append("瀹為檯绫抽噸蹇呴』澶т簬0")
+
+ if validation_errors:
+ st.error("鍙傛暟杈撳叆閿欒锛�")
+ for error in validation_errors:
+ st.error(f"- {error}")
+ else:
+ with st.spinner("姝e湪璁$畻浼樺寲璋冭妭寤鸿..."):
+ # 鑾峰彇閫変腑鐨勬ā鍨�
+ if 'selected_model' not in st.session_state:
+ st.error("璇峰厛閫夋嫨涓�涓ā鍨�")
+ return
+
+ model_info = st.session_state['selected_model']
+ model = model_info['model']
+
+ # 妫�鏌ユ槸鍚︽湁缂╂斁鍣�
+ has_scalers = ('scaler_X' in model_info and model_info['scaler_X'] is not None and
+ 'scaler_y' in model_info and model_info['scaler_y'] is not None)
+ if has_scalers:
+ scaler_X = model_info['scaler_X']
+ scaler_y = model_info['scaler_y']
+
+ features = model_info['features']
+
+ # 澶氱洰鏍囦紭鍖栫畻娉� - 绮掑瓙缇や紭鍖�
+ def predict_weight(screw_speed, process_speed):
+ """浣跨敤妯″瀷棰勬祴绫抽噸"""
+ # 鍑嗗杈撳叆鏁版嵁
+ input_data = {
+ '铻烘潌杞��': screw_speed,
+ '鏈哄ご鍘嬪姏': current_head_pressure,
+ '娴佺▼涓婚��': process_speed,
+ '铻烘潌娓╁害': current_screw_temperature,
+ '鍚庢満绛掓俯搴�': current_rear_barrel_temperature,
+ '鍓嶆満绛掓俯搴�': current_front_barrel_temperature,
+ '鏈哄ご娓╁害': current_head_temperature
+ }
+
+ # 鏍规嵁妯″瀷鐗瑰緛鍒涘缓杈撳叆DataFrame
+ input_df = pd.DataFrame([input_data])[features]
+
+ if model_info['model_type'] in ['LSTM', 'GRU', 'BiLSTM']:
+ # 娣卞害瀛︿範妯″瀷澶勭悊閫昏緫
+ import torch
+
+ # 妫�鏌ユ槸鍚︽湁缂╂斁鍣�
+ if has_scalers:
+ scaled_input = scaler_X.transform(input_df)
+ else:
+ scaled_input = input_df.values
+
+ # 鑾峰彇搴忓垪闀垮害
+ sequence_length = model_info.get('sequence_length', 10)
+
+ # 鍒涘缓搴忓垪鏁版嵁
+ input_seq = np.tile(scaled_input, (sequence_length, 1)).reshape(1, sequence_length, -1)
+
+ # 杞崲涓篜yTorch寮犻噺
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
+ input_tensor = torch.tensor(input_seq, dtype=torch.float32).to(device)
+
+ # 棰勬祴
+ model.eval()
+ with torch.no_grad():
+ y_pred_scaled_tensor = model(input_tensor)
+ y_pred_scaled = y_pred_scaled_tensor.cpu().numpy().ravel()[0]
+
+ if has_scalers:
+ # 鍙嶇缉鏀鹃娴嬬粨鏋�
+ predicted_weight = scaler_y.inverse_transform(np.array([[y_pred_scaled]]))[0][0]
+ else:
+ predicted_weight = y_pred_scaled
+
+ elif has_scalers:
+ # 鐗瑰緛缂╂斁
+ scaled_input = scaler_X.transform(input_df)
+
+ # 妯″瀷棰勬祴
+ scaled_prediction = model.predict(scaled_input)[0]
+
+ # 鍙嶇缉鏀鹃娴嬬粨鏋�
+ predicted_weight = scaler_y.inverse_transform(np.array([[scaled_prediction]]))[0][0]
+
+ else:
+ # 鐩存帴棰勬祴锛屼笉浣跨敤缂╂斁鍣�
+ predicted_weight = model.predict(input_df)[0]
+
+ return predicted_weight
+
+ def objective_function(params):
+ """澶氱洰鏍囩洰鏍囧嚱鏁�"""
+ screw_speed_val, process_speed_val = params
+
+ # 棰勬祴绫抽噸
+ predicted_weight_val = predict_weight(screw_speed_val, process_speed_val)
+
+ # 璁$畻鐩爣1锛氱背閲嶅亸宸�
+ deviation_val = abs(predicted_weight_val - standard_weight)
+ deviation_percent_val = abs((predicted_weight_val - standard_weight) / standard_weight * 100)
+
+ # 璁$畻鐩爣2锛氳皟鏁村箙搴�
+ screw_speed_adjustment_val = abs(screw_speed_val - current_screw_speed)
+ process_speed_adjustment_val = abs(process_speed_val - current_process_speed)
+
+ screw_speed_adjustment_percent_val = abs((screw_speed_val - current_screw_speed) / current_screw_speed * 100)
+ process_speed_adjustment_percent_val = abs((process_speed_val - current_process_speed) / current_process_speed * 100)
+
+ # 鍔犳潈鐩爣鍑芥暟
+ objective_val = (weight_deviation * deviation_percent_val +
+ weight_adjustment * (screw_speed_adjustment_percent_val + process_speed_adjustment_percent_val) / 2)
+
+ return objective_val, predicted_weight_val, deviation_percent_val, \
+ screw_speed_adjustment_percent_val, process_speed_adjustment_percent_val
+
+ # 鍙傛暟绾︽潫
+ def is_within_constraints(params):
+ """妫�鏌ュ弬鏁版槸鍚﹀湪绾︽潫鑼冨洿鍐�"""
+ screw_speed, process_speed = params
+
+ # 铻烘潌杞�熺害鏉�
+ if not (30 <= screw_speed <= 500):
+ return False
+
+ # 娴佺▼涓婚�熺害鏉�
+ if not (0 <= process_speed <= 200):
+ return False
+
+ # 鍗曟璋冩暣骞呭害绾︽潫
+ screw_speed_adjustment_percent = abs((screw_speed - current_screw_speed) / current_screw_speed * 100)
+ if screw_speed_adjustment_percent > max_screw_speed_adjust:
+ return False
+
+ process_speed_adjustment_percent = abs((process_speed - current_process_speed) / current_process_speed * 100)
+ if process_speed_adjustment_percent > max_process_speed_adjust:
+ return False
+
+ return True
+
+ # 绮掑瓙缇や紭鍖栫畻娉�
+ def particle_swarm_optimization(objective, constraints, bounds, n_particles=30, n_iterations=50):
+ """绮掑瓙缇や紭鍖栫畻娉�"""
+ # 鍒濆鍖栫矑瀛�
+ particles = []
+ velocities = []
+ best_positions = []
+ best_scores = []
+
+ # 杈圭晫
+ (screw_speed_min, screw_speed_max), (process_speed_min, process_speed_max) = bounds
+
+ for _ in range(n_particles):
+ # 闅忔満鍒濆鍖栦綅缃�
+ while True:
+ screw_speed = np.random.uniform(screw_speed_min, screw_speed_max)
+ process_speed = np.random.uniform(process_speed_min, process_speed_max)
+ pos = [screw_speed, process_speed]
+ if constraints(pos):
+ break
+
+ particles.append(pos)
+ velocities.append([0.0, 0.0])
+ best_positions.append(pos.copy())
+
+ # 璁$畻鍒濆寰楀垎
+ score, _, _, _, _ = objective(pos)
+ best_scores.append(score)
+
+ # 鍏ㄥ眬鏈�浼�
+ global_best_idx = np.argmin(best_scores)
+ global_best_position = best_positions[global_best_idx].copy()
+ global_best_score = best_scores[global_best_idx]
+
+ # PSO鍙傛暟
+ w = 0.5 # 鎯�ф潈閲�
+ c1 = 1.5 # 璁ょ煡绯绘暟
+ c2 = 1.5 # 绀句細绯绘暟
+
+ # 杩唬浼樺寲
+ for _ in range(n_iterations):
+ for i in range(n_particles):
+ # 鏇存柊閫熷害
+ r1, r2 = np.random.rand(), np.random.rand()
+ velocities[i][0] = (w * velocities[i][0] +
+ c1 * r1 * (best_positions[i][0] - particles[i][0]) +
+ c2 * r2 * (global_best_position[0] - particles[i][0]))
+ velocities[i][1] = (w * velocities[i][1] +
+ c1 * r1 * (best_positions[i][1] - particles[i][1]) +
+ c2 * r2 * (global_best_position[1] - particles[i][1]))
+
+ # 鏇存柊浣嶇疆
+ new_pos = [
+ particles[i][0] + velocities[i][0],
+ particles[i][1] + velocities[i][1]
+ ]
+
+ # 妫�鏌ョ害鏉�
+ if constraints(new_pos):
+ particles[i] = new_pos
+
+ # 鏇存柊涓綋鏈�浼�
+ current_score, _, _, _, _ = objective(new_pos)
+ if current_score < best_scores[i]:
+ best_scores[i] = current_score
+ best_positions[i] = new_pos.copy()
+
+ # 鏇存柊鍏ㄥ眬鏈�浼�
+ if current_score < global_best_score:
+ global_best_score = current_score
+ global_best_position = new_pos.copy()
+
+ return global_best_position, global_best_score
+
+ # 璁剧疆鍙傛暟杈圭晫
+ screw_speed_bounds = [
+ current_screw_speed * (1 - max_screw_speed_adjust / 100),
+ current_screw_speed * (1 + max_screw_speed_adjust / 100)
+ ]
+
+ process_speed_bounds = [
+ current_process_speed * (1 - max_process_speed_adjust / 100),
+ current_process_speed * (1 + max_process_speed_adjust / 100)
+ ]
+
+ # 鎵ц浼樺寲
+ best_params, best_score = particle_swarm_optimization(
+ objective_function,
+ is_within_constraints,
+ [(screw_speed_bounds[0], screw_speed_bounds[1]),
+ (process_speed_bounds[0], process_speed_bounds[1])]
+ )
+
+ # 鑾峰彇鏈�浼樺弬鏁扮殑璇︾粏淇℃伅
+ best_screw_speed, best_process_speed = best_params
+ best_objective, best_predicted_weight, best_deviation_percent, \
+ best_screw_adjust_percent, best_process_adjust_percent = objective_function(best_params)
+
+ # 璁$畻褰撳墠鍙傛暟鐨勯娴嬬粨鏋�
+ current_predicted_weight = predict_weight(current_screw_speed, current_process_speed)
+ current_deviation_percent = abs((current_predicted_weight - standard_weight) / standard_weight * 100)
+
+ # 鐢熸垚璋冩暣寤鸿鏂囨湰
+ def generate_recommendation():
+ """鐢熸垚璋冩暣寤鸿鏂囨湰"""
+ screw_speed_change = "鎻愰珮" if best_screw_speed > current_screw_speed else "闄嶄綆"
+ process_speed_change = "鎻愰珮" if best_process_speed > current_process_speed else "闄嶄綆"
+
+ recommendation = f"绫抽噸鍋忓樊 {current_deviation_percent:.2f}%锛屽缓璁皟鏁达細\n"
+ recommendation += f"1. 灏嗚灪鏉嗚浆閫熶粠 {current_screw_speed:.1f} rpm {screw_speed_change} 鑷� {best_screw_speed:.1f} rpm "
+ recommendation += f"( {screw_speed_change} {abs(best_screw_adjust_percent):.2f}% )\n"
+ recommendation += f"2. 灏嗘祦绋嬩富閫熶粠 {current_process_speed:.1f} m/min {process_speed_change} 鑷� {best_process_speed:.1f} m/min "
+ recommendation += f"( {process_speed_change} {abs(best_process_adjust_percent):.2f}% )\n"
+ recommendation += f"\n棰勬湡鏁堟灉锛氱背閲嶅亸宸皢闄嶈嚦 {best_deviation_percent:.2f}%"
+
+ return recommendation
+
+ recommendation = generate_recommendation()
+
+ # 鏋勫缓璋冩暣缁撴灉
+ adjustment_result = {
+ 'status': '姝e父鑼冨洿' if best_predicted_weight >= lower_limit and best_predicted_weight <= upper_limit else \
+ '瓒呬笂闄�' if best_predicted_weight > upper_limit else '瓒呬笅闄�',
+ 'real_time_weight': actual_weight,
+ 'standard_weight': standard_weight,
+ 'upper_limit': upper_limit,
+ 'lower_limit': lower_limit,
+ 'current_screw_speed': current_screw_speed,
+ 'current_process_speed': current_process_speed,
+ 'new_screw_speed': best_screw_speed,
+ 'new_process_speed': best_process_speed,
+ 'predicted_weight': best_predicted_weight,
+ 'current_predicted_weight': current_predicted_weight,
+ 'deviation_percentage': (actual_weight - standard_weight) / standard_weight * 100,
+ 'current_predicted_deviation_percent': current_deviation_percent,
+ 'predicted_deviation_percent': best_deviation_percent,
+ 'screw_speed_adjustment': best_screw_speed - current_screw_speed,
+ 'process_speed_adjustment': best_process_speed - current_process_speed,
+ 'screw_speed_adjust_percent': best_screw_adjust_percent,
+ 'process_speed_adjust_percent': best_process_adjust_percent,
+ 'recommendation': recommendation,
+ 'weight_deviation': weight_deviation,
+ 'weight_adjustment': weight_adjustment,
+ 'best_objective_score': best_score
+ }
+
+ # 淇濆瓨鍒板巻鍙茶褰�
+ history_record = {
+ 'timestamp': datetime.now(),
+ 'model_file': st.session_state.get('selected_model_file', '鏈煡妯″瀷'),
+ 'standard_weight': standard_weight,
+ 'upper_limit': upper_limit,
+ 'lower_limit': lower_limit,
+ 'actual_weight': actual_weight,
+ 'current_screw_speed': current_screw_speed,
+ 'current_process_speed': current_process_speed,
+ 'adjustment_result': adjustment_result
+ }
+
+ # 娣诲姞鍒颁細璇濈姸鎬佺殑鍘嗗彶璁板綍
+ st.session_state['optimized_adjustment_history'].append(history_record)
+
+ # 闄愬埗鍘嗗彶璁板綍鏁伴噺
+ if len(st.session_state['optimized_adjustment_history']) > 100:
+ st.session_state['optimized_adjustment_history'] = st.session_state['optimized_adjustment_history'][-100:]
+
+ # 5. 缁撴灉灞曠ず
+ st.success("浼樺寲璋冭妭寤鸿璁$畻瀹屾垚锛�")
+
+ st.subheader("馃搵 浼樺寲璋冭妭寤鸿缁撴灉")
+
+ # 5.1 绫抽噸鐘舵��
+ if adjustment_result['status'] == "姝e父鑼冨洿":
+ st.success(f"绫抽噸鐘舵��: {adjustment_result['status']}")
+ else:
+ st.warning(f"绫抽噸鐘舵��: {adjustment_result['status']}")
+
+ # 5.2 鍋忓樊淇℃伅
+ st.markdown("### 馃搳 鍋忓樊淇℃伅")
+ info_cols = st.columns(3)
+ info_cols[0].metric("瀹炴椂绫抽噸", f"{adjustment_result['real_time_weight']:.4f} Kg/m")
+ info_cols[1].metric("鏍囧噯绫抽噸", f"{adjustment_result['standard_weight']:.4f} Kg/m")
+ info_cols[2].metric("鍋忓樊鐧惧垎姣�", f"{adjustment_result['deviation_percentage']:.2f}%")
+
+ # 5.3 棰勬祴缁撴灉瀵规瘮
+ st.markdown("### 馃搱 棰勬祴缁撴灉瀵规瘮")
+ pred_cols = st.columns(3)
+ pred_cols[0].metric("褰撳墠鍙傛暟棰勬祴绫抽噸", f"{adjustment_result['current_predicted_weight']:.4f} Kg/m")
+ pred_cols[1].metric("浼樺寲鍚庨娴嬬背閲�", f"{adjustment_result['predicted_weight']:.4f} Kg/m")
+ pred_cols[2].metric("棰勬祴鍋忓樊鏀瑰杽", f"{adjustment_result['current_predicted_deviation_percent'] - adjustment_result['predicted_deviation_percent']:.2f}%")
+
+ # 5.4 鍏抽敭璋冩暣寤鸿
+ st.markdown("### 馃攽 鍏抽敭璋冩暣寤鸿")
+ st.info(adjustment_result['recommendation'])
+
+ # 5.5 鍙傛暟璋冩暣瀵规瘮
+ st.markdown("### 馃搳 鍙傛暟璋冩暣瀵规瘮")
+
+ param_compare_df = pd.DataFrame({
+ '鍙傛暟鍚嶇О': ['铻烘潌杞��', '娴佺▼涓婚��'],
+ '褰撳墠鍊�': [adjustment_result['current_screw_speed'], adjustment_result['current_process_speed']],
+ '浼樺寲寤鸿鍊�': [adjustment_result['new_screw_speed'], adjustment_result['new_process_speed']],
+ '璋冩暣骞呭害': [f"{adjustment_result['screw_speed_adjust_percent']:.2f}%",
+ f"{adjustment_result['process_speed_adjust_percent']:.2f}%"]
+ })
+
+ # 楂樹寒鏄剧ず璋冩暣骞呭害
+ def highlight_adjustment(val):
+ if isinstance(val, str) and '%' in val:
+ try:
+ percent = float(val.strip('%'))
+ if percent > 0:
+ return 'background-color: #90EE90' # 缁胯壊琛ㄧず澧炲姞
+ elif percent < 0:
+ return 'background-color: #FFB6C1' # 绾㈣壊琛ㄧず鍑忓皯
+ except:
+ pass
+ return ''
+
+ styled_df = param_compare_df.style.applymap(highlight_adjustment, subset=['璋冩暣骞呭害'])
+ st.dataframe(styled_df, use_container_width=True, hide_index=True)
+
+ # 5.6 鍙鍖栧姣�
+ fig = go.Figure()
+ fig.add_trace(go.Bar(
+ x=param_compare_df['鍙傛暟鍚嶇О'],
+ y=param_compare_df['褰撳墠鍊�'],
+ name='褰撳墠鍊�',
+ marker_color='blue'
+ ))
+ fig.add_trace(go.Bar(
+ x=param_compare_df['鍙傛暟鍚嶇О'],
+ y=param_compare_df['浼樺寲寤鸿鍊�'],
+ name='浼樺寲寤鸿鍊�',
+ marker_color='green'
+ ))
+
+ fig.update_layout(
+ barmode='group',
+ title='鍙傛暟璋冩暣瀵规瘮',
+ yaxis_title='鏁板��',
+ height=400
+ )
+
+ st.plotly_chart(fig, use_container_width=True)
+
+ # 5.7 浼樺寲鏁堟灉鍙鍖�
+ st.markdown("### 馃搲 浼樺寲鏁堟灉")
+
+ # 鐩爣鍑芥暟鍊煎姣�
+ fig_objective = go.Figure()
+ fig_objective.add_trace(go.Bar(
+ x=['褰撳墠鍙傛暟', '浼樺寲鍚庡弬鏁�'],
+ y=[
+ weight_deviation * current_deviation_percent + weight_adjustment * 0,
+ weight_deviation * best_deviation_percent + weight_adjustment * \
+ (abs(best_screw_adjust_percent) + abs(best_process_adjust_percent)) / 2
+ ],
+ marker_color=['red', 'green']
+ ))
+ fig_objective.update_layout(
+ title='澶氱洰鏍囦紭鍖栧嚱鏁板�煎姣�',
+ yaxis_title='鐩爣鍑芥暟鍊硷紙瓒婂皬瓒婂ソ锛�',
+ height=300
+ )
+ st.plotly_chart(fig_objective, use_container_width=True)
+
+ # 6. 鍘嗗彶璁板綍灞曠ず
+ st.subheader("馃摎 鍘嗗彶璋冭妭璁板綍")
+
+ if 'optimized_adjustment_history' in st.session_state and st.session_state['optimized_adjustment_history']:
+ # 鏄剧ず鍘嗗彶璁板綍鏁伴噺
+ st.write(f"鍏� {len(st.session_state['optimized_adjustment_history'])} 鏉″巻鍙茶褰�")
+
+ # 鍒嗛〉鏄剧ず
+ page_size = 10
+ total_pages = (len(st.session_state['optimized_adjustment_history']) + page_size - 1) // page_size
+
+ page = st.selectbox(
+ "閫夋嫨椤电爜",
+ options=range(1, total_pages + 1),
+ key="history_page"
+ )
+
+ start_idx = (page - 1) * page_size
+ end_idx = start_idx + page_size
+ paginated_history = st.session_state['optimized_adjustment_history'][start_idx:end_idx]
+
+ # 鍙嶅悜鏄剧ず锛屾渶鏂拌褰曞湪鍓嶉潰
+ for record in reversed(paginated_history):
+ with st.expander(f"璁板綍鏃堕棿: {record['timestamp'].strftime('%Y-%m-%d %H:%M:%S')} | 妯″瀷: {record['model_file']}"):
+ history_cols = st.columns(3)
+
+ with history_cols[0]:
+ st.write("**绫抽噸鍙傛暟**")
+ st.write(f"- 鏍囧噯绫抽噸: {record['standard_weight']:.4f} Kg/m")
+ st.write(f"- 绫抽噸涓婇檺: {record['upper_limit']:.4f} Kg/m")
+ st.write(f"- 绫抽噸涓嬮檺: {record['lower_limit']:.4f} Kg/m")
+ st.write(f"- 瀹為檯绫抽噸: {record['actual_weight']:.4f} Kg/m")
+
+ with history_cols[1]:
+ st.write("**閫熷害鍙傛暟**")
+ st.write(f"- 褰撳墠铻烘潌杞��: {record['current_screw_speed']:.1f} rpm")
+ st.write(f"- 褰撳墠娴佺▼涓婚��: {record['current_process_speed']:.1f} m/min")
+ st.write(f"- 寤鸿铻烘潌杞��: {record['adjustment_result']['new_screw_speed']:.1f} rpm")
+ st.write(f"- 寤鸿娴佺▼涓婚��: {record['adjustment_result']['new_process_speed']:.1f} m/min")
+
+ with history_cols[2]:
+ st.write("**棰勬祴缁撴灉**")
+ st.write(f"- 褰撳墠棰勬祴绫抽噸: {record['adjustment_result']['current_predicted_weight']:.4f} Kg/m")
+ st.write(f"- 浼樺寲鍚庨娴嬬背閲�: {record['adjustment_result']['predicted_weight']:.4f} Kg/m")
+ st.write(f"- 褰撳墠棰勬祴鍋忓樊: {record['adjustment_result']['current_predicted_deviation_percent']:.2f}%")
+ st.write(f"- 浼樺寲鍚庨娴嬪亸宸�: {record['adjustment_result']['predicted_deviation_percent']:.2f}%")
+
+ st.write("**璋冩暣寤鸿**")
+ st.write(record['adjustment_result']['recommendation'])
+ else:
+ st.info("鏆傛棤鍘嗗彶璋冭妭璁板綍")
+
+ # 7. 甯姪璇存槑
+ with st.expander("鉂� 甯姪璇存槑"):
+ st.markdown("""
+ ### 鍔熻兘璇存槑
+ 鏈姛鑳芥ā鍧楀熀浜庡鐩爣浼樺寲绠楁硶锛屾牴鎹綋鍓嶇背閲嶆祴閲忓�煎拰鎸ゅ嚭鏈哄弬鏁帮紝涓虹敤鎴锋彁渚涚瀛﹀悎鐞嗙殑鍙傛暟璋冩暣寤鸿銆�
+
+ ### 浼樺寲绠楁硶
+ - **绠楁硶绫诲瀷**: 绮掑瓙缇や紭鍖栫畻娉曪紙PSO锛�
+ - **浼樺寲鐩爣**:
+ 1. 鏈�灏忓寲绫抽噸鍋忓樊
+ 2. 鏈�灏忓寲鍙傛暟璋冩暣骞呭害
+ - **绾︽潫鏉′欢**:
+ - 铻烘潌杞�熷拰娴佺▼涓婚�熶笂涓嬮檺
+ - 鍗曟鏈�澶ц皟鏁村箙搴�
+
+ ### 缁撴灉瑙h
+ - **绫抽噸鐘舵��**: 鏄剧ず浼樺寲鍚庨娴嬬背閲嶆槸鍚﹀湪鍏佽鑼冨洿鍐�
+ - **鍋忓樊淇℃伅**: 褰撳墠绫抽噸涓庢爣鍑嗙背閲嶇殑鍋忓樊
+ - **棰勬祴缁撴灉瀵规瘮**: 褰撳墠鍙傛暟鍜屼紭鍖栧悗鍙傛暟鐨勯娴嬬背閲嶅姣�
+ - **璋冩暣寤鸿**: 璇︾粏鐨勫弬鏁拌皟鏁村缓璁�
+ - **鍙傛暟瀵规瘮**: 鐩磋灞曠ず鍙傛暟璋冩暣骞呭害
+ - **浼樺寲鏁堟灉**: 澶氱洰鏍囦紭鍖栧嚱鏁板�煎姣�
+
+ ### 娉ㄦ剰浜嬮」
+ 1. 璇风‘淇濊緭鍏ョ殑鍙傛暟鍊煎噯纭弽鏄犺澶囧綋鍓嶇姸鎬�
+ 2. 浼樺寲寤鸿浠呬緵鍙傝�冿紝瀹為檯鎿嶄綔鏃惰缁撳悎鐜板満缁忛獙
+ 3. 寤鸿鍦ㄨ皟鏁村弬鏁板悗瀵嗗垏瑙傚療绫抽噸鍙樺寲
+ 4. 瀹氭湡鏇存柊妯″瀷浠ユ彁楂樺缓璁殑鍑嗙‘鎬�
+ """)
+
+# 椤甸潰鍏ュ彛
+if __name__ == "__main__":
+ show_optimized_parameter_adjustment()
\ No newline at end of file
diff --git a/dashboard.py b/dashboard.py
index 77f0e99..d602522 100644
--- a/dashboard.py
+++ b/dashboard.py
@@ -12,6 +12,7 @@
from app.pages.metered_weight_prediction import show_metered_weight_prediction
from app.pages.metered_weight_forecast import show_metered_weight_forecast
from app.pages.extruder_parameter_adjustment import show_extruder_parameter_adjustment
+from app.pages.optimized_parameter_adjustment import show_optimized_parameter_adjustment
# 璁剧疆椤甸潰閰嶇疆
st.set_page_config(
@@ -112,6 +113,13 @@
url_path="extruder_parameter_adjustment"
)
+optimized_parameter_adjustment_page = st.Page(
+ show_optimized_parameter_adjustment,
+ title="浼樺寲鐗堟尋鍑烘満鍙傛暟璋冭妭",
+ icon="馃殌",
+ url_path="optimized_parameter_adjustment"
+)
+
# 渚ц竟鏍忛〉鑴氫俊鎭�
def show_footer():
st.sidebar.markdown("---")
@@ -119,7 +127,7 @@
# 瀵艰埅閰嶇疆
pg = st.navigation({
- "缁煎悎鍒嗘瀽": [comprehensive_page, metered_weight_page, metered_weight_correlation_page, metered_weight_regression_page, metered_weight_advanced_page, metered_weight_deep_learning_page, metered_weight_steady_state_page, metered_weight_prediction_page, metered_weight_forecast_page, extruder_parameter_adjustment_page],
+ "缁煎悎鍒嗘瀽": [comprehensive_page, metered_weight_page, metered_weight_correlation_page, metered_weight_regression_page, metered_weight_advanced_page, metered_weight_deep_learning_page, metered_weight_steady_state_page, metered_weight_prediction_page, metered_weight_forecast_page, extruder_parameter_adjustment_page, optimized_parameter_adjustment_page],
"鍒嗛」鍒嗘瀽": [sorting_page, extruder_page, main_process_page]
})
--
Gitblit v1.9.3