python的先进制造技术工业场景模拟第五十五篇:读取机器人焊接工艺数据,训练模型,由焊接电流波形预判焊缝未熔合缺陷。
周二下午,焊接车间机器人工作站。
"这批法兰环缝,焊完探伤发现 6 道未熔合,"焊接工艺员小周指着 X 光底片,"都在起弧后 3-8 秒的位置,你肉眼看焊缝表面好好的,打磨了才看到根部的未熔合。返修一次要切掉重焊,工时翻倍。"
我调出机器人焊接数据库的 CSV 导出文件。
"这表里有什么?"小周问。
"时间戳、焊接电流(A)、焊接电压(V)、送丝速度(m/min)、保护气流量(L/min)、焊枪角度(°)、工件间隙(mm)、层间温度(℃)、焊接模式(短路/脉冲/喷射),以及对应的探伤结果(合格/未熔合/气孔/咬边),"我指着屏幕,"但它就是一张逐点记录的工艺参数表。你能看到未熔合那几道的电流波形在起弧阶段有个 15A 左右的塌陷,持续了 0.4 秒,可你没法逐道人工看波形——一天焊 200 道,谁看得过来?"
"我就想干一件事,"小周说,"给我一个程序:实时读焊接电流波形,在焊完 5 秒内告诉我'这道焊缝有没有未熔合风险'。不用 100% 准确,但能把高风险的那几道挑出来,优先去探伤,低风险的直接放行。这样探伤工作量砍一半,返修也从'事后发现'变成'焊完就知道'。"
"比如起弧阶段电流偏低+工件间隙偏大+层间温度偏低,这三个凑一起就容易未熔合,"我接话,"用 pandas 做波形分段特征提取(起弧段/稳态段/收弧段),scipy 做电流波形的统计特征(均值/方差/峭度/下降斜率)+ 短时能量 + 过零率,scikit-learn 训练随机森林分类器预判缺陷,matplotlib 画电流波形叠加缺陷标记+特征分布+ROC曲线+混淆矩阵+特征重要性+决策边界,networkx 建工艺参数→缺陷模式的因果链路。"
"对,"小周点头,"别给我黑盒,要能说清楚'为什么这道被判高风险'。我看得懂,能拿去跟焊工说'起弧电流设到 180A 以上,间隙超过 1.2mm 就先补丝再焊,层温低于 80℃ 就预热'。"
"用 scipy 提取波形时域特征,pandas 做特征汇总,scikit-learn 随机森林+交叉验证,matplotlib 出 6 图+报告,存 results/,"我开工程,"数据自包含,合成一批含 200 道焊缝、未熔合率 15% 的电流波形数据,下载就能跑。"
敲了行原型:
# 未熔合 = 热输入不足 → 电流偏低/电压偏低/速度过快
# 波形特征 = 起弧段能量够不够、稳态段稳不稳
# 分类器 = 学会"什么样的波形形状对应未熔合"
# 时域特征 = 不用频域,电流波形本身就是慢变的
"完整版 OOP 封好,"我说,"数据加载器、波形特征提取器、缺陷分类器、因果网络、可视化器,输出缺陷概率+关键特征解释+6图+报告。"
小周凑近看:"那以后看报告:随机森林分类 F1=0.89,特征重要性排第一的是'起弧段平均电流'(31%),第二是'起弧段电流下降斜率'(22%),第三是'工件间隙'(18%)。决策边界:起弧段平均电流 <165A + 间隙 >1.0mm → 未熔合概率 78%。结论:工艺卡加一条'起弧电流下限 170A,间隙超 1.0mm 必须预填丝'。高风险焊缝焊完自动标记,优先拍片。"
"对,"我接话,"焊接不是'焊上就行',是'每一道的热输入都要够'。数字孪生里挂焊接质量节点,这套就是焊工的'未熔合预警器'。"
一、实际应用场景(真实痛点)
场景设定:机器人 MIG/MAG 焊接工作站,批量焊接法兰、管道环缝、箱体结构件。焊接过程中电流、电压逐毫秒记录,但缺陷检测依赖焊后 X 光/超声波探伤——发现未熔合时工件已焊完,返修成本高(切掉重焊)。
现场原话(叙事化):
"不是我们焊不好,"小周说,"是未熔合这东西太隐蔽。表面成型漂亮得很,纹路均匀、余高合适,你看着就是一道好焊缝。结果探伤一照,根部没熔进去——热输入不够,母材和焊丝没真正融合。返修要碳弧气刨切掉,重新坡口、预热、再焊,一道缝返修费是正常焊接的 4 倍。"
"最坑的是起弧位置,"小周补充,"机器人起弧有个建立电弧的过程,前 2-3 秒电流不稳定。如果起弧电流设低了,或者工件间隙偏大,这段就是未熔合的高发区。但你在现场听声音、看弧光,根本分辨不出来。只有探伤能确认。"
核心矛盾:"焊后探伤才发现缺陷" 与 "从电流波形实时预判缺陷风险+优先探伤+工艺参数闭环" 之间的断层。
二、痛点分析(映射到滨州职业学院《先进制造技术》课程模型)
《先进制造技术》模块 本篇痛点对应
工业机器人技术基础:焊接机器人工艺 焊接参数优化+缺陷预防
先进制造技术基础:焊接方法与质量检测 未熔合机理+探伤
智能制造与数字孪生:在线质量监控 焊接过程信号→缺陷预测
柔性制造系统FMS:过程质量控制 实时分选+优先探伤
一句话总结:我们需要一个"机器人焊接电流波形→时域特征提取+随机森林分类+缺陷预判+因果网络程序",用
"pandas" 做波形分段和特征汇总,
"numpy" 做时域计算,
"scipy" 做统计特征(峭度/偏度/短时能量),
"matplotlib" 画波形叠加标记+ROC+混淆矩阵+特征重要性+决策边界+因果网络,
"scikit-learn" 随机森林分类,
"networkx" 建因果链路,实现从"焊后探伤"到"波形预判+优先探伤+工艺闭环"。
三、核心逻辑讲解(大白话)
3.1 问题本质:把未熔合想成"煮粥没煮熟"
把焊接未熔合想成煮粥没煮熟:
* 未熔合 = 米还是硬的,水没烧开就关火了
* 焊接电流 = 火力大小
* 起弧段 = 刚开火那会儿,火还没上来
* 稳态段 = 火稳定了,咕嘟咕嘟
* 工件间隙 = 锅里的米铺得多厚(厚了火要更大)
* 分类器 = 看了 200 锅粥的"火候曲线",学会了"什么样的火候曲线煮出来是夹生饭"
3.2 业务逻辑 → 代码映射
读取焊接工艺数据
│
▼ WeldDataLoader (pandas)
读取表:
时间戳(ms), 电流(A), 电压(V), 送丝速度,
保护气流量, 焊枪角度, 工件间隙, 层间温度,
焊接模式, 探伤结果(合格/未熔合/气孔/咬边)
│
▼ WaveformFeatureExtractor (scipy + numpy)
波形分段:
起弧段(0-3000ms) → 统计特征
稳态段(3000ms-结束前2000ms) → 统计特征
收弧段(最后2000ms) → 统计特征
特征: 均值/方差/最小值/峭度/下降斜率/短时能量
│
▼ DefectClassifier (scikit-learn)
缺陷分类:
随机森林(主模型) + 逻辑回归(基线)
5折交叉验证
输出: 缺陷概率 + 类别标签
│
▼ DefectCausalNetwork (networkx)
因果链路:
节点: 工艺参数 → 波形特征 → 缺陷类型
边: 影响方向 + 重要性权重
│
▼ WeldVisualizer (matplotlib)
可视化:
1. 电流波形叠加缺陷标记(合格=绿, 未熔合=红)
2. 特征分布箱线图(合格 vs 未熔合)
3. ROC曲线
4. 混淆矩阵
5. 特征重要性柱状图
6. 因果网络图
│
▼ SyntheticWeldData (numpy)
合成数据:
200道焊缝, 未熔合率15%
起弧电流偏低+间隙偏大 → 未熔合
可复现
3.3 为什么不能只看"平均电流"
视角 问题
平均电流正常就放行 起弧段塌陷被平均掩盖
焊后全检探伤 成本高、周期长
波形分段特征 抓住起弧段这个关键窗口
分类器 学会"波形形状→缺陷"映射
优先探伤 高风险才拍片,降本增效
3.4 分析前后对比
维度 传统方式 本程序
缺陷发现 焊后探伤 焊完 5 秒预判
探伤策略 100% 全检 高风险优先,降本 50%
根因分析 "可能电流低了" 起弧段电流<165A + 间隙>1.0mm
工艺闭环 无 预判→调参数→再焊
输出 返修单 6图+报告+缺陷概率
四、OOP 代码实现
4.1 项目结构
weld_defect_predictor/
├── weld_defect_predictor/
│ ├── __init__.py
│ ├── weld_data_loader.py # 数据加载
│ ├── waveform_feature_extractor.py # 波形特征提取
│ ├── defect_classifier.py # 缺陷分类
│ ├── defect_causal_network.py # 因果网络
│ ├── visualizer.py # 可视化
│ └── synthetic_weld_data.py # 合成数据
├── tests/
│ ├── __init__.py
│ └── test_weld.py
├── results/
│ ├── waveform_overlay.png
│ ├── feature_boxplot.png
│ ├── roc_curve.png
│ ├── confusion_matrix.png
│ ├── feature_importance.png
│ ├── causal_network.png
│ ├── defect_detail.csv
│ └── defect_report.txt
└── run_weld.py
4.2 核心源码
<details>
<summary></summary>
"""机器人焊接数据加载器"""
import pandas as pd
from pathlib import Path
from typing import Optional
class WeldDataLoader:
"""读取焊接工艺数据"""
def __init__(self, filepath: str = "weld_log.csv",
encoding: str = "utf-8"):
self.filepath = Path(filepath)
self.encoding = encoding
def load(self) -> pd.DataFrame:
if not self.filepath.exists():
raise FileNotFoundError(self.filepath)
df = pd.read_csv(self.filepath, encoding=self.encoding)
req = ["weld_id", "timestamp_ms", "current_a", "voltage_v",
"wire_feed_m_min", "gas_flow_lpm", "torch_angle_deg",
"gap_mm", "interpass_temp_c", "weld_mode",
"defect_type"]
miss = [c for c in req if c not in df.columns]
if miss:
raise ValueError(f"缺列: {miss}")
num_cols = ["timestamp_ms", "current_a", "voltage_v",
"wire_feed_m_min", "gas_flow_lpm", "torch_angle_deg",
"gap_mm", "interpass_temp_c"]
for c in num_cols:
df[c] = pd.to_numeric(df[c], errors="coerce")
df = df.dropna(subset=["current_a", "defect_type"]).reset_index(drop=True)
# 二值化: 未熔合 vs 其他(合格+其他缺陷)
df["is_lack_of_fusion"] = (
df["defect_type"] == "未熔合"
).astype(int)
return df
def summary(self, df: pd.DataFrame) -> str:
s = f"总道数: {df['weld_id'].nunique()}\n"
s += f"总采样点: {len(df)}\n"
s += f"未熔合率: {df['is_lack_of_fusion'].mean()*100:.1f}%\n"
s += f"焊接模式: {df['weld_mode'].unique().tolist()}"
return s
</details>
<details>
<summary></summary>
"""焊接电流波形特征提取 (scipy + numpy)"""
import numpy as np
import pandas as pd
from scipy import stats
from typing import Dict, List
import warnings
warnings.filterwarnings("ignore")
class WaveformFeatureExtractor:
"""分段提取电流波形时域特征"""
def __init__(self, arc_start_ms: float = 3000.0,
arc_end_ms: float = 2000.0):
self.arc_start_ms = arc_start_ms
self.arc_end_ms = arc_end_ms
def extract_features(self, df: pd.DataFrame) -> pd.DataFrame:
"""按 weld_id 分组提取特征"""
feature_rows = []
for weld_id, group in df.groupby("weld_id"):
group = group.sort_values("timestamp_ms").reset_index(drop=True)
max_t = group["timestamp_ms"].max()
# 分段
start_mask = group["timestamp_ms"] <= self.arc_start_ms
end_mask = group["timestamp_ms"] >= (max_t - self.arc_end_ms)
steady_mask = (~start_mask) & (~end_mask)
feat = {"weld_id": weld_id}
# 全局特征
feat.update(self._time_domain_features(
group["current_a"].values, prefix="global"))
# 起弧段
if start_mask.sum() > 5:
feat.update(self._time_domain_features(
group.loc[start_mask, "current_a"].values,
prefix="start"))
# 起弧段电流下降斜率(前500ms vs 后500ms)
start_data = group.loc[start_mask, "current_a"].values
if len(start_data) >= 10:
first_half = start_data[:len(start_data)//2]
second_half = start_data[len(start_data)//2:]
feat["start_current_drop"] = float(
np.mean(first_half) - np.mean(second_half))
else:
feat["start_current_drop"] = 0.0
else:
feat.update({f"start_{k}": 0.0 for k in
["mean","std","min","kurtosis","energy"]})
feat["start_current_drop"] = 0.0
# 稳态段
if steady_mask.sum() > 10:
feat.update(self._time_domain_features(
group.loc[steady_mask, "current_a"].values,
prefix="steady"))
else:
feat.update({f"steady_{k}": 0.0 for k in
["mean","std","min","kurtosis","energy"]})
# 收弧段
if end_mask.sum() > 5:
feat.update(self._time_domain_features(
group.loc[end_mask, "current_a"].values,
prefix="end"))
else:
feat.update({f"end_{k}": 0.0 for k in
["mean","std","min","kurtosis","energy"]})
# 工艺参数(取均值)
feat["gap_mm"] = group["gap_mm"].mean()
feat["interpass_temp_c"] = group["interpass_temp_c"].mean()
feat["wire_feed_m_min"] = group["wire_feed_m_min"].mean()
feat["gas_flow_lpm"] = group["gas_flow_lpm"].mean()
# 标签
feat["is_lack_of_fusion"] = group["is_lack_of_fusion"].iloc[0]
feature_rows.append(feat)
return pd.DataFrame(feature_rows)
def _time_domain_features(self, signal: np.ndarray,
prefix: str) -> Dict:
"""时域统计特征"""
if len(signal) < 3:
return {f"{prefix}_{k}": 0.0 for k in
["mean","std","min","kurtosis","energy"]}
return {
f"{prefix}_mean": round(float(np.mean(signal)), 2),
f"{prefix}_std": round(float(np.std(signal)), 2),
f"{prefix}_min": round(float(np.min(signal)), 2),
f"{prefix}_kurtosis": round(float(stats.kurtosis(signal)), 2),
f"{prefix}_energy": round(float(np.sum(signal**2)), 2),
}
</details>
<details>
<summary></summary>
"""缺陷分类器 (scikit-learn)"""
import numpy as np
import pandas as pd
from typing import Dict, List
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import cross_val_score, StratifiedKFold
from sklearn.metrics import (roc_auc_score, roc_curve, confusion_matrix,
classification_report, accuracy_score)
class DefectClassifier:
"""随机森林分类未熔合缺陷"""
def __init__(self, random_state: int = 42):
self.random_state = random_state
self.rf = RandomForestClassifier(
n_estimators=150, max_depth=8,
class_weight="balanced",
random_state=random_state)
self.lr = LogisticRegression(class_weight="balanced",
random_state=random_state)
self.feature_names_ = None
self.selected_features_ = None
def prepare_features(self, df: pd.DataFrame) -> np.ndarray:
"""选择特征列"""
exclude = ["weld_id", "is_lack_of_fusion"]
feature_cols = [c for c in df.columns if c not in exclude]
self.feature_names_ = feature_cols
return df[feature_cols].values
def fit(self, X: np.ndarray, y: np.ndarray):
self.rf.fit(X, y)
self.lr.fit(X, y)
def predict_proba_fusion(self, X: np.ndarray) -> np.ndarray:
"""未熔合概率"""
return self.rf.predict_proba(X)[:, 1]
def evaluate(self, X: np.ndarray, y: np.ndarray) -> Dict:
"""交叉验证评估"""
skf = StratifiedKFold(n_splits=5, shuffle=True,
random_state=self.random_state)
cv_auc = cross_val_score(self.rf, X, y, cv=skf, scoring="roc_auc")
cv_f1 = cross_val_score(self.rf, X, y, cv=skf,
scoring="f1")
y_pred = self.rf.predict(X)
y_prob = self.predict_proba_fusion(X)
fpr, tpr, _ = roc_curve(y, y_prob)
return {
"cv_auc_mean": round(cv_auc.mean(), 3),
"cv_auc_std": round(cv_auc.std(), 3),
"cv_f1_mean": round(cv_f1.mean(), 3),
"train_accuracy": round(accuracy_score(y, y_pred), 3),
"fpr": fpr,
"tpr": tpr,
"y_pred": y_pred,
"y_prob": y_prob,
}
def feature_importance(self, top_n: int = 10) -> Dict:
importances = self.rf.feature_importances_
return dict(sorted(
zip(self.feature_names_, importances),
key=lambda x: x[1], reverse=True)[:top_n])
</details>
<details>
<summary></summary>
"""缺陷因果网络 (networkx)"""
import networkx as nx
import numpy as np
from typing import Dict
class DefectCausalNetwork:
"""构建工艺参数→波形特征→缺陷因果网络"""
def __init__(self):
self.G = nx.DiGraph()
def build(self, feature_importance: Dict,
defect_rate: float) -> nx.DiGraph:
self.G.clear()
# 缺陷节点
self.G.add_node("未熔合", ntype="defect", weight=2.0)
# 波形特征节点
for feat, imp in list(feature_importance.items())[:6]:
self.G.add_node(feat, ntype="wave_feature", weight=imp)
self.G.add_edge(feat, "未熔合", weight=imp)
# 工艺参数节点(连接波形特征)
params = ["gap_mm", "interpass_temp_c", "wire_feed_m_min"]
param_weights = {"gap_mm": 0.18, "interpass_temp_c": 0.10,
"wire_feed_m_min": 0.08}
for p in params:
self.G.add_node(p, ntype="process_param",
weight=param_weights.get(p, 0.05))
# 连接到最相关的波形特征
if "start_mean" in feature_importance:
self.G.add_edge(p, "start_mean",
weight=param_weights.get(p, 0.05)*0.5)
return self.G
</details>
<details>
<summary></summary>
"""可视化 (matplotlib + networkx)"""
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from pathlib import Path
import networkx as nx
plt.rcParams["font.sans-serif"] = ["SimHei", "DejaVu Sans"]
plt.rcParams["axes.unicode_minus"] = False
class WeldVisualizer:
def __init__(self, results_dir: str = "results"):
self.results_dir = Path(results_dir)
self.results_dir.mkdir(exist_ok=True)
def waveform_overlay(self, df: pd.DataFrame,
sample_welds: List[str] = None):
"""电流波形叠加缺陷标记"""
if sample_welds is None:
# 选2道合格+2道未熔合
ok_ids = df[df["is_lack_of_fusion"]==0]["weld_id"].unique()[:2]
bad_ids = df[df["is_lack_of_fusion"]==1]["weld_id"].unique()[:2]
sample_welds = list(ok_ids) + list(bad_ids)
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
axes = axes.flatten()
for i, wid in enumerate(sample_welds[:4]):
if i >= 4:
break
ax = axes[i]
wdf = df[df["weld_id"]==wid].sort_values("timestamp_ms")
is_bad = wdf["is_lack_of_fusion"].iloc[0]
color = "#E74C3C" if is_bad else "#27AE60"
ax.plot(wdf["timestamp_ms"]/1000, wdf["current_a"],
color=color, linewidth=1.2, alpha=0.8)
ax.axvline(x=3.0, color="orange", linestyle="--", linewidth=1,
label="起弧段结束" if i==0 else "")
ax.set_xlabel("时间 (s)")
ax.set_ylabel("电流 (A)")
ax.set_title(f"焊缝 {wid} ({'未熔合' if is_bad else '合格'})",
color=color, fontsize=11)
ax.grid(alpha=0.3)
if i == 0:
ax.legend(fontsize=8)
plt.suptitle("焊接电流波形(合格 vs 未熔合)", fontsize=14, fontweight="bold")
plt.tight_layout()
plt.savefig(self.results_dir/"waveform_overlay.png", dpi=150, bbox_inches="tight")
plt.close()
def feature_boxplot(self, feat_df: pd.DataFrame):
"""特征分布箱线图"""
fig, axes = plt.subplots(2, 3, figsize=(15, 10))
axes = axes.flatten()
features = ["start_mean", "start_current_drop", "gap_mm",
"steady_mean", "start_min", "interpass_temp_c"]
for i, feat in enumerate(features):
if i >= 6 or feat not in feat_df.columns:
break
ax = axes[i]
ok_data = feat_df[feat_df["is_lack_of_fusion"]==0][feat].dropna()
bad_data = feat_df[feat_df["is_lack_of_fusion"]==1][feat].dropna()
bp = ax.boxplot([ok_data, bad_data], labels=["合格", "未熔合"],
patch_artist=True)
bp["boxes"][0].set_facecolor("#27AE60")
bp["boxes"][1].set_facecolor("#E74C3C")
bp["boxes"][0].set_alpha(0.7)
bp["boxes"][1].set_alpha(0.7)
ax.set_title(feat, fontsize=10)
ax.grid(axis="y", alpha=0.3)
plt.suptitle("关键特征分布(合格 vs 未熔合)", fontsize=13, fontweight="bold")
plt.tight_layout()
plt.savefig(self.results_dir/"feature_boxplot.png", dpi=150, bbox_inches="tight")
plt.close()
def roc_curve(self, fpr, tpr, auc_score: float):
"""ROC曲线"""
fig, ax = plt.subplots(figsize=(8, 8))
ax.plot(fpr, tpr, "b-", linewidth=2.5, label=f"ROC (AUC={auc_score:.3f})")
ax.plot([0,1], [0,1], "k--", linewidth=1.5)
ax.set_xlabel("假阳性率 (FPR)")
ax.set_ylabel("真阳性率 (TPR)")
ax.set_title("ROC 曲线 - 未熔合缺陷预判", fontsize=13, fontweight="bold")
ax.legend(loc="lower right")
ax.grid(alpha=0.3)
plt.tight_layout()
plt.savefig(self.results_dir/"roc_curve.png", dpi=150, bbox_inches="tight")
plt.close()
def confusion_matrix(self, cm: np.ndarray):
"""混淆矩阵"""
fig, ax = plt.subplots(figsize=(7, 7))
im = ax.imshow(cm, cmap="Blues", aspect="auto")
ax.set_xticks([0, 1])
ax.set_yticks([0, 1])
ax.set_xticklabels(["合格", "未熔合"])
ax.set_yticklabels(["合格", "未熔合"])
ax.set_xlabel("预测")
ax.set_ylabel("实际")
for i in range(2):
for j in range(2):
ax.text(j, i, str(cm[i, j]), ha="center", va="center",
fontsize=16, fontweight="bold",
color="white" if cm[i, j] > cm.max()/2 else "black")
plt.colorbar(im, ax=ax)
ax.set_title("混淆矩阵", fontsize=13, fontweight="bold")
plt.tight_layout()
plt.savefig(self.results_dir/"confusion_matrix.png", dpi=150, bbox_inches="tight")
plt.close()
def feature_importance(self, importance: Dict):
"""特征重要性"""
fig, ax = plt.subplots(figsize=(10, 6))
names = list(importance.keys())
vals = list(importance.values())
colors = plt.cm.Reds(np.array(vals) / max(vals))
ax.barh(range(len(names)), vals[::-1], color=colors[::-1],
edgecolor="black", height=0.6)
ax.set_yticks(range(len(names)))
ax.set_yticklabels(names[::-1], fontsize=10)
ax.set_xlabel("特征重要性")
ax.set_title("未熔合缺陷关键特征排序", fontsize=13, fontweight="bold")
ax.grid(axis="x", alpha=0.3)
plt.tight_layout()
plt.savefig(self.results_dir/"feature_importance.png", dpi=150, bbox_inches="tight")
plt.close()
def causal_network(self, G: nx.DiGraph):
"""因果网络图"""
fig, ax = plt.subplots(figsize=(14, 10))
pos = nx.spring_layout(G, seed=42, k=0.8)
node_colors = []
node_sizes = []
for n in G.nodes():
nt = G.nodes[n].get("ntype", "")
if nt == "defect":
node_colors.append("#E74C3C"); node_sizes.append(2500)
elif nt == "wave_feature":
node_colors.append("#3498DB"); node_sizes.append(1200)
else:
node_colors.append("#F39C12"); node_sizes.append(1000)
nx.draw_networkx_nodes(G, pos, node_color=node_colors,
node_size=node_sizes, alpha=0.85, ax=ax)
nx.draw_networkx_edges(G, pos, arrows=True, arrowsize=15,
edge_color="gray", alpha=0.5, ax=ax)
nx.draw_networkx_labels(G, pos, font_size=8, ax=ax)
ax.set_title("工艺参数→波形特征→未熔合 因果网络",
fontsize=14, fontweight="bold")
ax.axis("off")
plt.tight_layout()
plt.savefig(self.results_dir/"causal_network.png", dpi=150, bbox_inches="tight")
plt.close()
</details>
<details>
<summary></summary>
"""合成焊接数据"""
import numpy as np
import pandas as pd
from
利用AI解决实际问题,如果你觉得这个工具好用,欢迎关注长安牧笛!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐

所有评论(0)