589 lines
21 KiB
Python
589 lines
21 KiB
Python
"""
|
|
冷却/浇注系统自动设计模块
|
|
|
|
功能:
|
|
1. 冷却系统设计 - 水路布局、直径、间距
|
|
2. 浇注系统设计 - 主流道、分流道、浇口
|
|
3. 热力学估算 - 冷却时间、温度分布
|
|
4. 排气系统设计 - 排气槽、排气针位置
|
|
|
|
设计依据:
|
|
- 模具尺寸和产品几何
|
|
- 材料热物性参数
|
|
- 生产节拍要求
|
|
- 行业标准规范
|
|
"""
|
|
|
|
from typing import Dict, List, Any, Optional
|
|
import math
|
|
from shared.utils.logger import get_logger
|
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
class MaterialThermalDB:
|
|
"""材料热物性数据库"""
|
|
|
|
PLASTICS = {
|
|
"ABS": {"density": 1.05, "specific_heat": 1.47, "thermal_cond": 0.17,
|
|
"melt_temp": 230, "mold_temp": 60, "eject_temp": 85},
|
|
"PP": {"density": 0.90, "specific_heat": 1.90, "thermal_cond": 0.15,
|
|
"melt_temp": 220, "mold_temp": 40, "eject_temp": 80},
|
|
"PC": {"density": 1.20, "specific_heat": 1.25, "thermal_cond": 0.20,
|
|
"melt_temp": 300, "mold_temp": 80, "eject_temp": 120},
|
|
"PE": {"density": 0.95, "specific_heat": 2.30, "thermal_cond": 0.50,
|
|
"melt_temp": 200, "mold_temp": 30, "eject_temp": 70},
|
|
"PS": {"density": 1.05, "specific_heat": 1.34, "thermal_cond": 0.12,
|
|
"melt_temp": 220, "mold_temp": 50, "eject_temp": 80},
|
|
"PA": {"density": 1.14, "specific_heat": 1.70, "thermal_cond": 0.25,
|
|
"melt_temp": 260, "mold_temp": 70, "eject_temp": 100},
|
|
"POM": {"density": 1.42, "specific_heat": 1.47, "thermal_cond": 0.31,
|
|
"melt_temp": 200, "mold_temp": 70, "eject_temp": 100},
|
|
"PMMA": {"density": 1.18, "specific_heat": 1.47, "thermal_cond": 0.19,
|
|
"melt_temp": 240, "mold_temp": 60, "eject_temp": 90},
|
|
}
|
|
|
|
FOAM = {
|
|
"AlSi10Mg": {"density": 0.45, "specific_heat": 0.90, "thermal_cond": 0.05,
|
|
"melt_temp": 380, "mold_temp": 150, "eject_temp": 200},
|
|
"AlSi12": {"density": 0.50, "specific_heat": 0.88, "thermal_cond": 0.06,
|
|
"melt_temp": 360, "mold_temp": 140, "eject_temp": 190},
|
|
}
|
|
|
|
COOLANT = {
|
|
"water": {"specific_heat": 4.18, "density": 1.0, "thermal_cond": 0.60},
|
|
"oil": {"specific_heat": 2.00, "density": 0.85, "thermal_cond": 0.15},
|
|
}
|
|
|
|
@classmethod
|
|
def get_material(cls, material: str) -> Optional[Dict]:
|
|
if material in cls.PLASTICS:
|
|
return cls.PLASTICS[material]
|
|
if material in cls.FOAM:
|
|
return cls.FOAM[material]
|
|
return None
|
|
|
|
|
|
class CoolingSystemDesigner:
|
|
"""冷却系统设计器"""
|
|
|
|
def design_cooling_system(self, mold_size: Dict, product_bbox: Dict,
|
|
material: str = "ABS",
|
|
cavity_count: int = 1,
|
|
cycle_time_target: Optional[float] = None) -> Dict[str, Any]:
|
|
"""
|
|
设计冷却系统
|
|
|
|
Args:
|
|
mold_size: {"length": L, "width": W, "height": H}
|
|
product_bbox: {"dimensions": [dx, dy, dz]}
|
|
material: 材料名称
|
|
cavity_count: 型腔数量
|
|
cycle_time_target: 目标成型周期(秒)
|
|
|
|
Returns:
|
|
冷却系统设计方案
|
|
"""
|
|
logger.info(f"开始冷却系统设计: 材料={material}, {cavity_count}穴")
|
|
|
|
mat_props = MaterialThermalDB.get_material(material)
|
|
if mat_props is None:
|
|
mat_props = MaterialThermalDB.PLASTICS["ABS"]
|
|
logger.warning(f"未知材料 {material},使用 ABS 默认参数")
|
|
|
|
dims = product_bbox.get("dimensions", [100, 100, 50])
|
|
max_wall = max(dims) * 0.6
|
|
|
|
cooling_time = self._estimate_cooling_time(
|
|
max_wall, mat_props, mold_size.get("height", 100)
|
|
)
|
|
|
|
layout = self._design_channel_layout(mold_size, dims, cavity_count)
|
|
|
|
channels = self._generate_channel_positions(layout, mold_size, dims)
|
|
|
|
flow_rate = self._calculate_flow_rate(channels, mat_props)
|
|
|
|
thermal_check = self._check_thermal_performance(
|
|
cooling_time, channels, mat_props, mold_size, cycle_time_target
|
|
)
|
|
|
|
return {
|
|
"cooling_time": round(cooling_time, 1),
|
|
"channels": channels,
|
|
"layout": layout,
|
|
"flow_rate": flow_rate,
|
|
"thermal_check": thermal_check,
|
|
"material_properties": mat_props,
|
|
"recommendations": self._generate_cooling_recommendations(
|
|
cooling_time, thermal_check, channels, cycle_time_target
|
|
),
|
|
}
|
|
|
|
def _estimate_cooling_time(self, max_wall_thickness: float,
|
|
mat_props: Dict, mold_height: float) -> float:
|
|
"""估算冷却时间(基于一维热传导简化模型)"""
|
|
k = mat_props["thermal_cond"]
|
|
rho = mat_props["density"] * 1000
|
|
cp = mat_props["specific_heat"] * 1000
|
|
|
|
alpha = k / (rho * cp)
|
|
|
|
t_melt = mat_props["melt_temp"]
|
|
t_mold = mat_props["mold_temp"]
|
|
t_eject = mat_props["eject_temp"]
|
|
|
|
if t_melt <= t_eject:
|
|
return 10.0
|
|
|
|
theta = (t_eject - t_mold) / (t_melt - t_mold) if (t_melt - t_mold) != 0 else 0.5
|
|
theta = max(0.01, min(0.99, abs(theta)))
|
|
|
|
L = max_wall_thickness / 1000.0
|
|
|
|
cooling_time = (L ** 2 / (alpha * math.pi ** 2)) * math.log(4 / (math.pi * theta))
|
|
|
|
return max(5.0, cooling_time)
|
|
|
|
def _design_channel_layout(self, mold_size: Dict, dims: List[float],
|
|
cavity_count: int) -> Dict:
|
|
"""设计水路布局方案"""
|
|
length = mold_size.get("length", 300)
|
|
width = mold_size.get("width", 300)
|
|
|
|
channel_diameter = 8.0
|
|
channel_spacing = 30.0
|
|
wall_distance = 15.0
|
|
|
|
num_channels_length = max(2, int((width - 2 * wall_distance) / channel_spacing))
|
|
num_channels_width = max(2, int((length - 2 * wall_distance) / channel_spacing))
|
|
|
|
if cavity_count <= 4:
|
|
layout_type = "straight"
|
|
num_channels = num_channels_length
|
|
else:
|
|
layout_type = "spiral"
|
|
num_channels = max(num_channels_length, num_channels_width)
|
|
|
|
return {
|
|
"type": layout_type,
|
|
"diameter": channel_diameter,
|
|
"spacing": channel_spacing,
|
|
"wall_distance": wall_distance,
|
|
"num_channels": num_channels,
|
|
"num_channels_length": num_channels_length,
|
|
"num_channels_width": num_channels_width,
|
|
}
|
|
|
|
def _generate_channel_positions(self, layout: Dict, mold_size: Dict,
|
|
dims: List[float]) -> List[Dict]:
|
|
"""生成水路位置"""
|
|
channels = []
|
|
length = mold_size.get("length", 300)
|
|
width = mold_size.get("width", 300)
|
|
wall_dist = layout["wall_distance"]
|
|
diameter = layout["diameter"]
|
|
|
|
if layout["type"] == "straight":
|
|
num = layout["num_channels_length"]
|
|
spacing = (width - 2 * wall_dist) / max(num - 1, 1)
|
|
|
|
for i in range(num):
|
|
y = wall_dist + i * spacing - width / 2
|
|
channels.append({
|
|
"id": i + 1,
|
|
"type": "straight",
|
|
"start": [-length / 2 + wall_dist, y, 0],
|
|
"end": [length / 2 - wall_dist, y, 0],
|
|
"diameter": diameter,
|
|
"side": "A" if i % 2 == 0 else "B",
|
|
})
|
|
else:
|
|
num = layout["num_channels"]
|
|
for i in range(num):
|
|
offset = (i - (num - 1) / 2) * layout["spacing"]
|
|
channels.append({
|
|
"id": i + 1,
|
|
"type": "spiral",
|
|
"center": [0, offset, 0],
|
|
"radius": min(length, width) / 2 - wall_dist,
|
|
"diameter": diameter,
|
|
"side": "A" if i % 2 == 0 else "B",
|
|
})
|
|
|
|
return channels
|
|
|
|
def _calculate_flow_rate(self, channels: List[Dict],
|
|
mat_props: Dict) -> Dict:
|
|
"""计算冷却液流量"""
|
|
total_length = 0
|
|
diameter = 8.0
|
|
|
|
for ch in channels:
|
|
if ch["type"] == "straight":
|
|
start = ch["start"]
|
|
end = ch["end"]
|
|
total_length += math.sqrt(sum((s - e) ** 2 for s, e in zip(start, end)))
|
|
elif ch["type"] == "spiral":
|
|
total_length += 2 * math.pi * ch.get("radius", 100)
|
|
|
|
velocity = 1.5
|
|
area = math.pi * (diameter / 2 / 1000) ** 2
|
|
flow_rate_lpm = velocity * area * 60000
|
|
|
|
reynolds = 1000 * velocity * (diameter / 1000) / 0.001
|
|
|
|
return {
|
|
"velocity_m_s": velocity,
|
|
"flow_rate_lpm": round(flow_rate_lpm, 1),
|
|
"total_channel_length": round(total_length, 1),
|
|
"reynolds_number": round(reynolds, 0),
|
|
"flow_regime": "turbulent" if reynolds > 4000 else "laminar",
|
|
}
|
|
|
|
def _check_thermal_performance(self, cooling_time: float,
|
|
channels: List[Dict],
|
|
mat_props: Dict,
|
|
mold_size: Dict,
|
|
target_cycle: Optional[float]) -> Dict:
|
|
"""检查热力学性能"""
|
|
num_channels = len(channels)
|
|
total_heat = mat_props["specific_heat"] * mat_props["density"] * 100
|
|
|
|
heat_removal_rate = num_channels * 0.5 * 4.18 * 1.5 * 10
|
|
|
|
adequacy = "adequate" if num_channels >= 4 else "insufficient"
|
|
|
|
if target_cycle is not None:
|
|
if cooling_time <= target_cycle * 0.6:
|
|
adequacy = "excellent"
|
|
elif cooling_time <= target_cycle * 0.8:
|
|
adequacy = "adequate"
|
|
else:
|
|
adequacy = "insufficient"
|
|
|
|
return {
|
|
"cooling_time": round(cooling_time, 1),
|
|
"estimated_heat_removal_rate": round(heat_removal_rate, 1),
|
|
"channel_count": num_channels,
|
|
"adequacy": adequacy,
|
|
}
|
|
|
|
def _generate_cooling_recommendations(self, cooling_time: float,
|
|
thermal_check: Dict,
|
|
channels: List[Dict],
|
|
target_cycle: Optional[float]) -> List[str]:
|
|
"""生成冷却系统建议"""
|
|
recs = []
|
|
|
|
if thermal_check["adequacy"] == "insufficient":
|
|
recs.append("冷却能力不足,建议增加水路数量或增大水路直径")
|
|
recs.append("考虑使用铍铜镶件提高局部冷却效率")
|
|
|
|
if cooling_time > 30:
|
|
recs.append("冷却时间较长,建议优化水路布局使水路更靠近型腔")
|
|
|
|
if len(channels) < 4:
|
|
recs.append("水路数量偏少,建议至少4条水路")
|
|
|
|
flow_regime = "turbulent"
|
|
if flow_regime == "laminar":
|
|
recs.append("冷却液流速偏低,建议提高流速以达到湍流状态(Re>4000)")
|
|
|
|
if not recs:
|
|
recs.append("冷却系统设计合理,建议进行热分析验证")
|
|
|
|
return recs
|
|
|
|
|
|
class GatingSystemDesigner:
|
|
"""浇注系统设计器"""
|
|
|
|
def design_gating_system(self, product_bbox: Dict, material: str = "ABS",
|
|
cavity_count: int = 1,
|
|
gate_type: str = "auto",
|
|
layout_positions: Optional[List] = None) -> Dict[str, Any]:
|
|
"""
|
|
设计浇注系统
|
|
|
|
Args:
|
|
product_bbox: {"dimensions": [dx, dy, dz]}
|
|
material: 材料名称
|
|
cavity_count: 型腔数量
|
|
gate_type: 浇口类型 (auto/side/center/submarine/fan)
|
|
layout_positions: 型腔位置列表
|
|
|
|
Returns:
|
|
浇注系统设计方案
|
|
"""
|
|
logger.info(f"开始浇注系统设计: 材料={material}, {cavity_count}穴, 浇口={gate_type}")
|
|
|
|
mat_props = MaterialThermalDB.get_material(material)
|
|
if mat_props is None:
|
|
mat_props = MaterialThermalDB.PLASTICS["ABS"]
|
|
|
|
dims = product_bbox.get("dimensions", [100, 100, 50])
|
|
|
|
if gate_type == "auto":
|
|
gate_type = self._recommend_gate_type(dims, cavity_count)
|
|
|
|
sprue = self._design_sprue(dims, mat_props)
|
|
runner = self._design_runner(dims, cavity_count, layout_positions)
|
|
gate = self._design_gate(dims, gate_type, cavity_count, mat_props)
|
|
|
|
venting = self._design_venting(dims, cavity_count)
|
|
|
|
return {
|
|
"sprue": sprue,
|
|
"runner": runner,
|
|
"gate": gate,
|
|
"gate_type": gate_type,
|
|
"venting": venting,
|
|
"material": material,
|
|
"recommendations": self._generate_gating_recommendations(
|
|
gate_type, cavity_count, dims, mat_props
|
|
),
|
|
}
|
|
|
|
def _recommend_gate_type(self, dims: List[float], cavity_count: int) -> str:
|
|
"""推荐浇口类型"""
|
|
aspect = max(dims[:2]) / min(dims[:2]) if min(dims[:2]) > 0 else 1
|
|
|
|
if cavity_count == 1:
|
|
if aspect > 2:
|
|
return "side"
|
|
return "center"
|
|
else:
|
|
return "side"
|
|
|
|
def _design_sprue(self, dims: List[float], mat_props: Dict) -> Dict:
|
|
"""设计主流道"""
|
|
max_dim = max(dims)
|
|
volume = dims[0] * dims[1] * dims[2]
|
|
|
|
if volume > 500000:
|
|
sprue_d_top = 4.0
|
|
sprue_d_bottom = 8.0
|
|
elif volume > 50000:
|
|
sprue_d_top = 3.0
|
|
sprue_d_bottom = 6.0
|
|
else:
|
|
sprue_d_top = 2.5
|
|
sprue_d_bottom = 5.0
|
|
|
|
sprue_length = max_dim * 0.5 + 20
|
|
|
|
taper_angle = math.degrees(
|
|
math.atan((sprue_d_bottom / 2 - sprue_d_top / 2) / sprue_length)
|
|
)
|
|
|
|
return {
|
|
"diameter_top": sprue_d_top,
|
|
"diameter_bottom": sprue_d_bottom,
|
|
"length": round(sprue_length, 1),
|
|
"taper_angle": round(taper_angle, 2),
|
|
"volume": round(
|
|
math.pi / 3 * sprue_length * (
|
|
(sprue_d_top / 2) ** 2 + (sprue_d_top / 2) * (sprue_d_bottom / 2) + (sprue_d_bottom / 2) ** 2
|
|
), 1
|
|
),
|
|
}
|
|
|
|
def _design_runner(self, dims: List[float], cavity_count: int,
|
|
positions: Optional[List]) -> Dict:
|
|
"""设计分流道"""
|
|
if cavity_count <= 1:
|
|
return {
|
|
"type": "none",
|
|
"diameter": 0,
|
|
"total_length": 0,
|
|
"volume": 0,
|
|
}
|
|
|
|
runner_diameter = max(4.0, min(dims[:2]) * 0.04)
|
|
|
|
if positions and len(positions) > 1:
|
|
total_length = 0
|
|
for pos in positions:
|
|
total_length += 2 * math.sqrt(pos[0] ** 2 + pos[1] ** 2)
|
|
else:
|
|
total_length = cavity_count * max(dims[:2]) * 1.5
|
|
|
|
cross_area = math.pi * (runner_diameter / 2) ** 2
|
|
|
|
return {
|
|
"type": "trapezoid",
|
|
"diameter": round(runner_diameter, 1),
|
|
"total_length": round(total_length, 1),
|
|
"volume": round(cross_area * total_length, 1),
|
|
"cross_section": {
|
|
"top_width": round(runner_diameter * 1.2, 1),
|
|
"bottom_width": round(runner_diameter * 0.8, 1),
|
|
"depth": round(runner_diameter * 0.9, 1),
|
|
},
|
|
}
|
|
|
|
def _design_gate(self, dims: List[float], gate_type: str,
|
|
cavity_count: int, mat_props: Dict) -> Dict:
|
|
"""设计浇口"""
|
|
min_dim = min(dims[:2])
|
|
wall_thickness = dims[2] * 0.6
|
|
|
|
if gate_type == "center":
|
|
gate_diameter = max(1.0, wall_thickness * 0.5)
|
|
return {
|
|
"type": "center",
|
|
"diameter": round(gate_diameter, 1),
|
|
"length": 1.5,
|
|
"position": "top_center",
|
|
}
|
|
elif gate_type == "submarine":
|
|
gate_diameter = max(0.8, wall_thickness * 0.3)
|
|
return {
|
|
"type": "submarine",
|
|
"diameter": round(gate_diameter, 1),
|
|
"length": 2.0,
|
|
"angle": 45,
|
|
"position": "bottom_side",
|
|
}
|
|
elif gate_type == "fan":
|
|
return {
|
|
"type": "fan",
|
|
"width": round(min_dim * 0.3, 1),
|
|
"depth": round(wall_thickness * 0.5, 1),
|
|
"length": 1.5,
|
|
"position": "side",
|
|
}
|
|
else:
|
|
gate_diameter = max(1.0, wall_thickness * 0.4)
|
|
return {
|
|
"type": "side",
|
|
"diameter": round(gate_diameter, 1),
|
|
"length": 2.0,
|
|
"position": "side_center",
|
|
}
|
|
|
|
def _design_venting(self, dims: List[float], cavity_count: int) -> Dict:
|
|
"""设计排气系统"""
|
|
volume = dims[0] * dims[1] * dims[2]
|
|
|
|
if volume > 500000:
|
|
vent_count = max(4, cavity_count * 2)
|
|
vent_depth = 0.03
|
|
vent_width = 8.0
|
|
elif volume > 50000:
|
|
vent_count = max(2, cavity_count)
|
|
vent_depth = 0.02
|
|
vent_width = 5.0
|
|
else:
|
|
vent_count = cavity_count
|
|
vent_depth = 0.015
|
|
vent_width = 3.0
|
|
|
|
return {
|
|
"type": "vent_slot",
|
|
"count": vent_count,
|
|
"depth_mm": vent_depth,
|
|
"width_mm": vent_width,
|
|
"length_mm": 10.0,
|
|
"positions": "parting_line",
|
|
}
|
|
|
|
def _generate_gating_recommendations(self, gate_type: str, cavity_count: int,
|
|
dims: List[float], mat_props: Dict) -> List[str]:
|
|
"""生成浇注系统建议"""
|
|
recs = []
|
|
|
|
if cavity_count > 1:
|
|
recs.append("多型腔模具建议使用平衡式流道布局")
|
|
|
|
if mat_props.get("melt_temp", 0) > 260:
|
|
recs.append("高熔点材料,建议使用热流道系统减少废料")
|
|
|
|
if gate_type == "center":
|
|
recs.append("中心浇口适用于单型腔,注意浇口痕处理")
|
|
elif gate_type == "side":
|
|
recs.append("侧浇口适用于多型腔,需注意流动平衡")
|
|
|
|
aspect = max(dims[:2]) / min(dims[:2]) if min(dims[:2]) > 0 else 1
|
|
if aspect > 3:
|
|
recs.append("产品长宽比大,建议使用多点进浇或扇形浇口")
|
|
|
|
if not recs:
|
|
recs.append("浇注系统设计合理,建议进行模流分析验证")
|
|
|
|
return recs
|
|
|
|
|
|
class MoldSystemDesigner:
|
|
"""模具系统综合设计器(冷却+浇注)"""
|
|
|
|
def __init__(self):
|
|
self.cooling_designer = CoolingSystemDesigner()
|
|
self.gating_designer = GatingSystemDesigner()
|
|
|
|
def design_complete_system(self, mold_size: Dict, product_bbox: Dict,
|
|
material: str = "ABS",
|
|
cavity_count: int = 1,
|
|
gate_type: str = "auto",
|
|
cycle_time_target: Optional[float] = None,
|
|
layout_positions: Optional[List] = None) -> Dict[str, Any]:
|
|
"""
|
|
综合设计冷却和浇注系统
|
|
|
|
Returns:
|
|
{
|
|
"cooling": Dict,
|
|
"gating": Dict,
|
|
"overall_assessment": Dict,
|
|
"recommendations": List[str]
|
|
}
|
|
"""
|
|
cooling = self.cooling_designer.design_cooling_system(
|
|
mold_size, product_bbox, material, cavity_count, cycle_time_target
|
|
)
|
|
|
|
gating = self.gating_designer.design_gating_system(
|
|
product_bbox, material, cavity_count, gate_type, layout_positions
|
|
)
|
|
|
|
cooling_time = cooling["cooling_time"]
|
|
gating_fill_time = self._estimate_fill_time(product_bbox, material)
|
|
|
|
total_cycle = cooling_time + gating_fill_time + 5.0
|
|
|
|
assessment = {
|
|
"estimated_cycle_time": round(total_cycle, 1),
|
|
"cooling_time": cooling_time,
|
|
"fill_time": round(gating_fill_time, 1),
|
|
"ejection_time": 3.0,
|
|
"buffer_time": 2.0,
|
|
"meets_target": True if cycle_time_target is None else total_cycle <= cycle_time_target,
|
|
}
|
|
|
|
all_recs = cooling.get("recommendations", []) + gating.get("recommendations", [])
|
|
if assessment["meets_target"] is False:
|
|
all_recs.insert(0, f"成型周期({total_cycle:.0f}s)超出目标({cycle_time_target}s),需优化冷却系统")
|
|
|
|
return {
|
|
"cooling": cooling,
|
|
"gating": gating,
|
|
"overall_assessment": assessment,
|
|
"recommendations": all_recs,
|
|
}
|
|
|
|
def _estimate_fill_time(self, product_bbox: Dict, material: str) -> float:
|
|
"""估算填充时间"""
|
|
dims = product_bbox.get("dimensions", [100, 100, 50])
|
|
volume = dims[0] * dims[1] * dims[2]
|
|
|
|
mat_props = MaterialThermalDB.get_material(material)
|
|
if mat_props is None:
|
|
mat_props = MaterialThermalDB.PLASTICS["ABS"]
|
|
|
|
fill_rate = 50.0
|
|
|
|
fill_time = volume / fill_rate
|
|
|
|
return max(0.5, min(fill_time, 10.0))
|