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()
|