熱力學仿真輔助隨機森林:面向船用柴油機燃燒室組件的可解釋性故障診斷

羅聰聰 a , 趙明航 a,* , 付旭雲 a , 鍾詩勝 a , 付松 b , 張楷 c , 余曉霞 d
a 哈爾濱工業大學(威海) 機械工程系,威海 264209,中國
b 哈爾濱工業大學 機電工程學院,哈爾濱 150001,中國
c 西南交通大學 機械工程學院,成都 610031,中國
d 重慶理工大學 機械工程學院,重慶 400054,中國

摘要

傳統船用柴油機智慧故障診斷方法常因故障訓練樣本匱乏導致泛化能力不足,且因未充分融合故障機理領域的先驗知識而造成可解釋性較差。針對上述問題,本文提出了一種 熱力學仿真輔助隨機森林 (TSRF) 方法。

該方法通過熱力學仿真揭示故障演化特徵,並將其作為先驗知識融入智慧故障診斷模型的設計中。首先,通過微調系統基礎參數以類比不同故障的顯著特徵,開發了五個熱力學故障模型。隨後,基於數值模擬結果確定了表徵燃燒室組件退化的潛在熱力學指標。

通過計算 SHapley Additive explanations (SHAP) 值進行特徵篩選,僅保留與故障狀態具有顯著相關性的變數。最後,利用篩選出的參數評估燃燒室健康狀態。實驗結果表明,所提出的 TSRF 方法表現出優異的分類性能,在故障數據集上的平均準確率高達 99.07%。

關鍵詞:
船用柴油機 故障診斷 可解釋性AI SHAP值

研究動機

在海洋工程與預測與健康管理 (PHM) 領域,行業面臨兩大長期瓶頸:

  • 數據稀缺: 船舶柴油機(特別是遠洋船舶主機)是船舶的心臟,一旦在海上發生嚴重故障,可能導致失去動力、擱淺甚至海難。因此,它們在設計時的安全係數極高,本身發生嚴重故障的機率就很低。此外,船舶行業執行嚴格的預防性維護體系(如基於運行小時數的定時檢修)。絕大多數磨損部件在真正損壞引發故障數據之前,就已經被強制更換了。這導致目前擁有大量的健康數據和早期磨損數據,但極其缺乏完全失效或嚴重故障的真實數據。
  • 「黑盒子」問題: 由於深度學習模型通常缺乏透明度,若無法解釋故障的物理成因,工程師很難對其建立信任。在受驗船協會嚴格監管的航運業,這種不透明性尤為關鍵。如果 AI 誤判引發縮缸或曲軸斷裂,而系統無法追溯錯誤是源於數據偏差、演算法缺陷還是感測器漂移,這種不可追溯性在海事事故調查中是不可被接受的。

為應對上述挑戰,我們提出了 TSRF 方法。通過將基於物理的機理模型與先進的可解釋性技術相融合,並利用高保真仿真模型生成解決了數據稀缺問題,並確保診斷決策符合熱力學基本原理。


方法論

本研究的工作流程包含以下四個主要階段(如圖所示):

  1. 熱力學建模: 我們不單純依賴物理試驗台,而是構建了六缸船用柴油機的高保真一維熱力學模型。該模型基於真實運行數據進行了嚴格校準,仿真誤差控制在 5% 以內。
  2. 故障注入: 基於校準後的模型,我們通過微調物理參數模擬了五種特定的燃燒室故障(如氣缸蓋裂紋、活塞燒蝕等),生成涵蓋真實發動機各類不同程度故障的數據集。
  3. 基於 SHAP 的特徵選擇: 我們利用 SHAP 值定量識別關鍵特徵,篩選出主導診斷決策的 14 個關鍵參數。
  4. 分類診斷: 利用這一物理增強的數據集訓練隨機森林 (RF) 分類器,實現了高精度的故障診斷。
Structure of TSRF method combining Thermodynamic Simulation and Random Forest for Explainable AI

圖 1: TSRF 方法架構圖。


熱力學建模細節

為確保高保真度,我們構建了一維柴油機仿真模型。該機理模型在物理精度與數據集生成所需的計算效率之間取得了平衡。

模型拓撲

發動機系統被離散化為流體管路與功能組件網絡:

  • 核心動力單元: 六缸、二衝程直列配置。
  • 氣路系統: 進/排氣歧管 (PL1, PL2) 通過錯綜複雜的管路網絡連接。
  • 增壓系統: 渦輪增壓器 (TC1) 與中冷器 (CO1) 耦合。

校準與驗證

在進行故障注入之前,基線模型已基於實測數據進行了嚴格校準。

  • 數據來源: 通過數據採集模組 (DCM) 獲取的真實船舶運行數據。
  • 驗證: 關鍵參數(如功率、排氣溫度)的偏差嚴格控制在 ±5% 誤差範圍內
1-D thermodynamic simulation model

圖 2: 柴油機一維熱力學模型示意圖。

Model Validation Results

圖 5: 數據採集模組 (DCM)。

故障注入機制

由於一維模型無法直接表徵 3D 結構缺陷,我們採用了現象學映射法,將物理退化機制轉化為等效的熱力學參數偏移。

故障類型 物理機制 建模實現
F1: 氣缸蓋裂紋 熱傳導受阻。 將氣缸蓋表面溫度 ($T_H$) 提升至 346°C。
F2: 活塞燒蝕 材料缺損與密封失效。 提高活塞溫度 ($T_P$) + 輕微吹漏氣 (0.01 kg/s)。
F3: 缸套磨損 磨損導致缸徑增大。 增大缸徑 + 大量吹漏氣 (0.03 kg/s)。
F4: 活塞環磨損 氣體洩漏。 調節吹漏氣質量流量 (0.02 kg/s)。
F5: 活塞環黏著 摩擦力增大與密封失效。 缸徑變化 + 缸套溫度升高 + 吹漏氣。

可解釋性分析

本研究的一大核心創新在於將重心從「故障是什麼?」轉向「為何判定為該故障?」。我們通過活塞環磨損 (F4) 的實例分析展示了這一能力:

  • 局部解釋 (瀑布圖): 瀑布圖解析了具體的預測邏輯。例如,模型預測「活塞環磨損」,是因為吹漏氣熱流 (P06) 和吹漏氣質量流量 (P07) 呈現特定數值,從而提高了該故障的預測機率。這符合物理規律:活塞環磨損破壞了密封性,導致氣體洩漏(吹漏氣)。
  • 全局解釋 (蜂群圖): 全局分析揭示了模型習得的普遍規律。我們發現渦輪前排氣壓力 (P11) 的低值是活塞環磨損的強力指標。從物理角度看這具有一致性:磨損的活塞環導致氣體從氣缸洩漏,從而減少了驅動渦輪的可用能量。
SHAP Analysis,including Waterfall plot, beeswarm plot, interaction plot and dependence plot

圖 11: 基於 SHAP 值的活塞環磨損 (F4) 故障分析:(a) 瀑布圖;(b) 蜂群圖;(c) 交互圖;(d) 依賴圖。

點擊查看 SHAP 可視化代碼 (Python)

若您對上述圖表的實現細節感興趣,以下是用於生成瀑布圖、蜂群圖、交互圖和依賴圖的範例代碼。👇

import shap
import matplotlib.pyplot as plt
import numpy as np

# --- 0. Setup & Global Settings ---
plt.rcParams['font.family'] = 'Arial'
plt.rcParams['font.size'] = '24'
plt.rcParams['axes.unicode_minus'] = False

# Assumption: 'best_model' is your trained XGBoost/RF model
# Assumption: 'X_train' and 'X_test' are pandas DataFrames

# 1. Calculate SHAP values as Numpy Arrays (for Beeswarm, Dependence, Interaction)
explainer_tree = shap.TreeExplainer(best_model)
shap_values_numpy = explainer_tree.shap_values(X_train)

# 2. Calculate SHAP values as Explanation Object (Specifically for Waterfall)
explainer_obj = shap.Explainer(best_model, X_test)
shap_values_obj = explainer_obj(X_test)


##################################################################
#                                                                #
#                      (a) Waterfall Plot                        #
#          Visualizes contribution for a single sample           #
#                                                                #
##################################################################

class_idx = 4  # Target class
sample_idx = 3 # Specific sample to explain

plt.figure()
shap.plots.waterfall(
    shap_values_obj[sample_idx, :, class_idx],
    max_display=9,
    show=False
)

# Customizing style
ax = plt.gca()
ax.set_xlabel(ax.get_xlabel(), fontsize=36)
ax.set_ylabel(ax.get_ylabel(), fontsize=36)
ax.spines['bottom'].set_linewidth(3)
plt.show()


##################################################################
#                                                                #
#                      (b) Beeswarm Plot                         #
#              Global summary of feature importance              #
#                                                                #
##################################################################

class_idx = 5
plt.figure(figsize=(10, 8))

shap.summary_plot(
    shap_values_numpy[..., class_idx],
    X_train,
    feature_names=X_train.columns,
    plot_type="dot",
    show=False,
    cmap='Greys' # or 'plasma'
)

# Customize Color Bar
cbar = plt.gcf().axes[-1]
cbar.set_ylabel('Parameter Value', fontsize=24)
cbar.tick_params(labelsize=20)
plt.show()


##################################################################
#                                                                #
#                     (c) Interaction Plot                       #
#          Visualizes interaction effects between features       #
#                                                                #
##################################################################

# Note: Calculation can be expensive
shap_interaction_values = explainer_tree.shap_interaction_values(X_test)
class_idx = 4

plt.figure()
shap.summary_plot(
    shap_interaction_values[..., class_idx],
    X_test,
    show=False,
    max_display=6,
    cmap='Greys'
)

# Clean up subplots
axes = plt.gcf().axes
for ax in axes:
    ax.spines['bottom'].set_linewidth(2)
    ax.tick_params(axis="x", labelsize=18, width=2)
    ax.set_title(ax.get_title(), fontsize=14)

plt.subplots_adjust(wspace=0.3, hspace=0.4)
plt.show()


##################################################################
#                                                                #
#                     (d) Dependence Plot                        #
#           Feature relationship colored by interaction          #
#                                                                #
##################################################################

Feature_X = 'P06'  # Main feature
Feature_Y = 'P07'  # Interaction feature
class_idx = 4

shap.dependence_plot(
    Feature_X,
    shap_values_numpy[..., class_idx],
    X_train,
    interaction_index=Feature_Y,
    dot_size=100,
    show=False
)

# Customize Axes
ax = plt.gca()
ax.tick_params(axis='both', which='major', labelsize=36, width=2)
ax.set_ylabel(f'SHAP value ({Feature_X})', fontsize=36)
ax.spines['bottom'].set_linewidth(3)
ax.spines['left'].set_linewidth(3)
plt.show()


##################################################################
#                                                                #
#            (e) Advanced Composite Plot (Beeswarm + Bar)        #
#      Combines Beeswarm (Bottom Axis) & Importance (Top Axis)   #
#                                                                #
##################################################################

class_idx = 5
fig, ax1 = plt.subplots(figsize=(10, 8))

# 1. Main Beeswarm Plot (on ax1)
shap.summary_plot(
    shap_values_numpy[..., class_idx],
    X_train,
    feature_names=X_train.columns,
    plot_type="dot",
    show=False,
    color_bar=True,
    cmap='Greys' # or 'plasma'
)

# Customize Color Bar
cbar = plt.gcf().axes[-1]
cbar.set_ylabel('Parameter Value', fontsize=24)
cbar.tick_params(labelsize=20)

# Adjust layout to make room for the top axis
plt.gca().set_position([0.2, 0.2, 0.65, 0.65])

# 2. Feature Importance Bar Plot (on Top Axis ax2)
# Create a twin axis sharing the y-axis
ax2 = ax1.twiny()

shap.summary_plot(
    shap_values_numpy[..., class_idx],
    X_train,
    plot_type="bar",
    show=False
)

# Align position with the main plot
plt.gca().set_position([0.2, 0.2, 0.65, 0.65])

# Style the bars (Transparent & Light Color)
bars = ax2.patches
for bar in bars:
    bar.set_color('#CCE5FB') # Light blue background bars
    bar.set_alpha(0.4)       # Transparency

# Customize Axes Labels
ax1.set_xlabel(f'Shapley Value Contribution (F{class_idx})', fontsize=24, labelpad=5)
ax1.set_ylabel('Parameters', fontsize=24)
ax2.set_xlabel('Mean Shapley Value (Parameter Importance)', fontsize=24, labelpad=10)

# Move ax2 (Bar plot axis) to the top
ax2.xaxis.set_label_position('top')
ax2.xaxis.tick_top()

# Ensure ax1 (dots) is drawn ON TOP OF ax2 (bars)
ax1.set_zorder(ax1.get_zorder() + 1)
ax1.patch.set_visible(False) # Make ax1 background transparent

plt.show()

研究亮點

我們認為本項工作為該領域做出了以下關鍵貢獻:

  • 建立了針對船用柴油機燃燒室組件五種典型故障的參數化模型。
  • 通過與多種特徵選擇方法的對比,驗證了 SHAP 方法的有效性。
  • 通過融合數據驅動方法與熱力學機理模型,為可解釋的故障診斷提供了新視角。

引用

如果您發現這項工作對您的研究有益,請考慮閱讀以下論文 😊

BibTeX

@article{luo2025thermodynamic,
  title     = {Thermodynamic simulation-assisted random forest: Towards explainable fault diagnosis of combustion chamber components of marine diesel engines},
  author    = {Luo, Congcong and Zhao, Minghang and Fu, Xuyun and Zhong, Shisheng and Fu, Song and Zhang, Kai and Yu, Xiaoxia},
  journal   = {Measurement},
  volume    = {251},
  pages     = {117252},
  year      = {2025},
  publisher = {Elsevier},
  doi       = {10.1016/j.measurement.2025.117252},
}

標準格式

C. Luo, M. Zhao, X. Fu, S. Zhong, S. Fu, K. Zhang, X. Yu. Thermodynamic simulation-assisted random forest: Towards explainable fault diagnosis of combustion chamber components of marine diesel engines[J]. Measurement, 2025, 251: 117252.