""" 冷却/浇注系统自动设计模块 功能: 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))