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 app.services.parameter_adjustment_service import ParameterAdjustmentAdvisor # 页面函数定义 def show_extruder_parameter_adjustment(): # 页面标题 st.title("挤出机参数调节建议") # 添加操作指引 with st.expander("📖 操作指引", expanded=True): st.markdown(""" 欢迎使用挤出机参数调节建议功能!本功能可以根据您输入的米重数据和当前参数,为您提供科学合理的参数调整建议。 **操作步骤:** 1. 选择一个已训练好的模型 2. 输入米重标准值、上下限和当前挤出机参数 3. 输入当前实际米重测量值 4. 点击"计算调节建议"按钮 5. 查看系统生成的参数调整建议 **注意事项:** - 请确保输入的参数值在设备允许的范围内 - 建议根据实际生产情况调整模型参数 - 历史调节记录可在页面底部查看 """) # 初始化会话状态 if 'adjustment_history' not in st.session_state: st.session_state['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, 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("🚀 计算调节建议") # 添加迭代调整选项 use_iterative_adjustment = st.checkbox("🔄 使用迭代调整", value=False, help="启用迭代调整,自动优化参数直到预测米重满足偏差要求") # 迭代调整参数设置 max_iterations = 5 tolerance = 0.5 if use_iterative_adjustment: st.write("### 迭代调整参数设置") iter_cols = st.columns(2) max_iterations = iter_cols[0].number_input("最大迭代次数", min_value=1, max_value=20, value=5, step=1) tolerance = iter_cols[1].number_input("允许偏差百分比(%)", min_value=0.1, max_value=5.0, value=0.5, step=0.1) if st.button("📊 计算调节建议", key="calculate_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("正在计算调节建议..."): # 初始化参数调节建议器 adjustment_advisor = ParameterAdjustmentAdvisor() # 准备初始参数 initial_params = { '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, 'current_screw_temperature': current_screw_temperature, 'current_rear_barrel_temperature': current_rear_barrel_temperature, 'current_front_barrel_temperature': current_front_barrel_temperature, 'current_head_temperature': current_head_temperature, 'current_head_pressure': current_head_pressure } # 根据是否启用迭代调整执行不同逻辑 if use_iterative_adjustment and 'selected_model' in st.session_state: # 使用迭代调整 iterative_result = adjustment_advisor.iterative_adjustment( initial_params=initial_params, model_info=st.session_state['selected_model'], max_iterations=max_iterations, tolerance=tolerance ) # 使用迭代调整的最终结果 adjustment_result = iterative_result['final_result'] iteration_history = iterative_result['iteration_history'] converged = iterative_result['converged'] total_iterations = iterative_result['total_iterations'] else: # 正常计算调整建议 adjustment_result = adjustment_advisor.calculate_adjustment( 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, current_screw_temperature=current_screw_temperature, current_rear_barrel_temperature=current_rear_barrel_temperature, current_front_barrel_temperature=current_front_barrel_temperature, current_head_temperature=current_head_temperature ) # 使用选中的模型预测调整后的米重 predicted_weight = None if 'selected_model' in st.session_state: selected_model_info = st.session_state['selected_model'] predicted_weight = adjustment_advisor.predict_weight( model_info=selected_model_info, screw_speed=adjustment_result['new_screw_speed'], head_pressure=current_head_pressure, process_speed=adjustment_result['new_process_speed'], screw_temperature=current_screw_temperature, rear_barrel_temperature=current_rear_barrel_temperature, front_barrel_temperature=current_front_barrel_temperature, head_temperature=current_head_temperature ) # 将预测结果添加到调整结果中 adjustment_result['predicted_weight'] = predicted_weight # 初始化迭代历史(如果未使用迭代调整) iteration_history = None converged = None total_iterations = None # 保存到历史记录 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, 'current_screw_temperature': current_screw_temperature, 'current_rear_barrel_temperature': current_rear_barrel_temperature, 'current_front_barrel_temperature': current_front_barrel_temperature, 'current_head_temperature': current_head_temperature, 'adjustment_result': adjustment_result, 'use_iterative_adjustment': use_iterative_adjustment, 'iteration_history': iteration_history } # 添加到会话状态的历史记录 if 'adjustment_history' not in st.session_state: st.session_state['adjustment_history'] = [] st.session_state['adjustment_history'].append(history_record) # 限制历史记录数量 if len(st.session_state['adjustment_history']) > 100: st.session_state['adjustment_history'] = st.session_state['adjustment_history'][-100:] # 4. 结果展示 st.success("调节建议计算完成!") st.subheader("📋 调节建议结果") # 4.1 米重状态 if adjustment_result['status'] == "正常": st.success(f"米重状态: {adjustment_result['status']}") else: st.warning(f"米重状态: {adjustment_result['status']}") # 4.2 偏差信息 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}%") # 4.2.1 模型预测结果 if adjustment_result['predicted_weight'] is not None: st.markdown("### 📈 模型预测结果") pred_cols = st.columns(3) pred_cols[0].metric("调整后预测米重", f"{adjustment_result['predicted_weight']:.4f} Kg/m") # 计算预测偏差 predicted_deviation = adjustment_result['predicted_weight'] - adjustment_result['standard_weight'] predicted_deviation_percent = (predicted_deviation / adjustment_result['standard_weight']) * 100 pred_cols[1].metric("预测偏差", f"{predicted_deviation:.4f} Kg/m") pred_cols[2].metric("预测偏差百分比", f"{predicted_deviation_percent:.2f}%") # 显示预测效果 if abs(predicted_deviation_percent) < 0.5: st.success("调整后米重预测值接近标准值,调整效果良好!") elif abs(predicted_deviation_percent) < 1.0: st.info("调整后米重预测值在可接受范围内。") else: st.warning("调整后米重预测值仍有较大偏差,建议进一步微调。") else: st.warning("模型预测失败,请检查模型文件或参数。") # 4.3 关键调整建议 st.markdown("### 🔑 关键调整建议") st.info(adjustment_result['recommendation']) # 4.4 参数调整对比 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) # 4.5 可视化对比 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) # 4.6 迭代调整结果展示 if use_iterative_adjustment and iteration_history: st.markdown("### 🔄 迭代调整历史") # 显示迭代调整状态 if converged: st.success(f"✅ 迭代调整成功收敛!经过 {total_iterations} 次迭代,预测米重偏差达到 {tolerance}% 以内。") else: st.warning(f"⚠️ 迭代调整未收敛!经过 {total_iterations} 次迭代,预测米重偏差仍未达到 {tolerance}% 以内。") # 显示迭代历史表格 iter_history_df = pd.DataFrame(iteration_history) iter_history_df = iter_history_df[[ 'iteration', 'current_screw_speed', 'current_process_speed', 'adjusted_screw_speed', 'adjusted_process_speed', 'predicted_weight', 'predicted_deviation_percent' ]] # 格式化表格 iter_history_df = iter_history_df.rename(columns={ 'iteration': '迭代次数', 'current_screw_speed': '调整前螺杆转速', 'current_process_speed': '调整前流程主速', 'adjusted_screw_speed': '调整后螺杆转速', 'adjusted_process_speed': '调整后流程主速', 'predicted_weight': '预测米重', 'predicted_deviation_percent': '预测偏差百分比(%)' }) st.dataframe(iter_history_df, use_container_width=True) # 迭代调整可视化 st.markdown("### 📉 迭代调整效果") # 偏差变化趋势图 fig_deviation = go.Figure() fig_deviation.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=iter_history_df['预测偏差百分比(%)'], mode='lines+markers', name='预测偏差百分比', line=dict(color='blue', width=2), marker=dict(size=8) )) # 添加偏差阈值线 fig_deviation.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=[tolerance] * len(iter_history_df), mode='lines', name='允许偏差上限', line=dict(color='red', dash='dash', width=1) )) fig_deviation.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=[-tolerance] * len(iter_history_df), mode='lines', name='允许偏差下限', line=dict(color='red', dash='dash', width=1) )) fig_deviation.update_layout( title='迭代调整偏差变化趋势', xaxis_title='迭代次数', yaxis_title='预测偏差百分比(%)', height=400, legend=dict(yanchor="top", y=0.99, xanchor="left", x=0.01) ) st.plotly_chart(fig_deviation, use_container_width=True) # 螺杆转速和流程主速变化趋势 fig_params = go.Figure() fig_params.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=iter_history_df['调整前螺杆转速'], mode='lines+markers', name='调整前螺杆转速', line=dict(color='blue', width=2), marker=dict(size=8) )) fig_params.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=iter_history_df['调整后螺杆转速'], mode='lines+markers', name='调整后螺杆转速', line=dict(color='green', width=2), marker=dict(size=8) )) fig_params.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=iter_history_df['调整前流程主速'], mode='lines+markers', name='调整前流程主速', line=dict(color='orange', width=2), marker=dict(size=8) )) fig_params.add_trace(go.Scatter( x=iter_history_df['迭代次数'], y=iter_history_df['调整后流程主速'], mode='lines+markers', name='调整后流程主速', line=dict(color='purple', width=2), marker=dict(size=8) )) fig_params.update_layout( title='参数调整变化趋势', xaxis_title='迭代次数', yaxis_title='数值', height=400, legend=dict(yanchor="top", y=0.99, xanchor="right", x=0.99) ) st.plotly_chart(fig_params, use_container_width=True) # 5. 历史记录展示 st.subheader("📚 历史调节记录") if 'adjustment_history' in st.session_state and st.session_state['adjustment_history']: # 显示历史记录数量 st.write(f"共 {len(st.session_state['adjustment_history'])} 条历史记录") # 分页显示 page_size = 10 total_pages = (len(st.session_state['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['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") with history_cols[2]: st.write("**温度参数**") st.write(f"- 螺杆温度: {record['current_screw_temperature']:.1f} °C") st.write(f"- 后机筒温度: {record['current_rear_barrel_temperature']:.1f} °C") st.write(f"- 前机筒温度: {record['current_front_barrel_temperature']:.1f} °C") st.write(f"- 机头温度: {record['current_head_temperature']:.1f} °C") st.write("**调整建议**") st.write(record['adjustment_result']['recommendation']) else: st.info("暂无历史调节记录") # 6. 帮助说明 with st.expander("❓ 帮助说明"): st.markdown(""" ### 功能说明 本功能模块用于根据当前米重测量值和挤出机参数,为用户提供科学合理的参数调整建议,以帮助用户将米重控制在标准范围内。 ### 模型选择 - 系统会自动读取项目目录中训练好的模型文件 - 模型文件需符合系统要求的格式,包含模型参数和训练信息 - 建议选择R²得分较高、误差较小的模型 ### 参数输入 - 米重标准值:您期望的目标米重值 - 米重上下限:允许的米重波动范围 - 挤出机当前参数:包括螺杆转速、流程主速、机头压力和挤出机电流 - 当前实际米重:实际测量得到的米重值 ### 结果解读 - 米重状态:显示当前米重是否在允许范围内 - 偏差百分比:当前米重与标准米重的偏差百分比 - 关键调整建议:系统给出的主要调整建议 - 参数调整对比:详细展示每个参数的当前值、建议值和调整幅度 ### 注意事项 1. 请确保输入的参数值准确反映设备当前状态 2. 调整建议仅供参考,实际操作时请结合现场经验 3. 建议在调整参数后密切观察米重变化 4. 定期更新模型以提高建议的准确性 """) # 页面入口 if __name__ == "__main__": show_extruder_parameter_adjustment()