Posts Issued in January, 2025

EGASアーキテクチャ

posted by sakurai on January 21, 2025 #933

EGASアーキテクチャについて、ChatGPTに聞いてみました。

機能安全、特にISO 26262において、EGASアーキテクチャとは何ですか?

ChatGPT:
機能安全(特にISO 26262)でよく言及される「EGASアーキテクチャ」とは、一般的に “Electronic Gas (またはGaspedal) System” の略称であり、いわゆるドライブ・バイ・ワイヤ(Drive-by-Wire)方式の電子スロットル制御システムを指します。従来のアクセルペダルとスロットルバルブをワイヤやリンケージで機械的につないでいた構造に代わって、ペダル位置センサ・電子制御ユニット(ECU)・スロットルアクチュエータといった電子的構成要素でアクセル開度を制御する仕組みです。

EGASアーキテクチャでは、以下のような機能安全上の特徴・考慮事項が存在します。

  1. ペダル位置センサの冗長化
    アクセルペダルの踏み込み量を計測するペダル位置センサを二重化や多重化し、それぞれのセンサ信号を相互に監視することで故障検知を行います。ISO 26262では、ASIL(Automotive Safety Integrity Level)の要求に応じて十分な冗長度や故障診断機構を設計し、安全目標を満たす必要があります。

  2. ECU内の監視機能(トルクモニタリング等)
    エンジントルクを演算するメインのマイクロコントローラに加え、モニタ用のサブマイクロコントローラやウォッチドッグなどを配置することで、メイン系の異常動作を検出します。必要に応じてフェイルセーフ(エンジンを強制的にアイドルにするといった制御)を実行し、車両の安全を確保します。

  3. スロットルアクチュエータの安全機構
    スロットルバルブを動かすアクチュエータにも故障診断やフェイルセーフ動作を盛り込むことが求められます。例えば、スロットルバルブのポジションセンサを二重化して、開度に矛盾がないかをチェックする仕組みを設計します。

  4. ASIL割り当てと安全コンセプト
    EGASのように車両の加速・減速に直接関わる機能は、ISO 26262におけるASIL評価で高いレベル(例:ASIL CやD)が割り当てられることが多く、それに応じて高度な故障診断、冗長化、監視機能が求められます。

要するに、EGASアーキテクチャは機械的リンケージを排して電子的にアクセル開度(スロットル開度)を制御するシステムの総称であり、ISO 26262の枠組みにおいては、故障時の安全性(フェイルセーフ)や冗長性を確保するためのさまざまな仕組みを持つことが重要とされています。これにより、アクセル制御の異常が起きても車両挙動が過度に危険にならないようにすることが、機能安全上の大きな目的となります。

図%%.1
図933.1 EGASアーキテクチャ図

左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (21)

posted by sakurai on January 20, 2025 #932

次に、IFやSMを単一エレメントではなく複数エレメントのグループとします。これは実際には基本形のFTに対してIFやSMの部分はBEではなくサブツリーが配置されるため、その処理を行わせるためのAIに対する学習となります。

図%%.1
図932.1 RBD

図932.1を読み取ったChatGPTの生成したMARDファイルを以下に示します。

TEST.BED

*Saphire 8.2.9
TEST =
* Name , Descriptions , Project
A , A fault (20FIT) , TEST
B , B fault (40FIT) , TEST
D , D fault (5FIT) , TEST
E , E fault (10FIT) , TEST
SM_IF_COVREM , SM_IF coverage leftover (1-DC=40%) , TEST
SM_IF_COV , SM_IF coverage (DC=60%) , TEST

TEST.BEI

*Saphire 8.2.9
TEST =
* Name ,FdT,UdC,UdT,UdValue, Prob, Lambda, Tau, Mission, Init,PF,UdValue2,Calc. Prob,Freq,Analysis Type,Phase Type,Project
A ,3, , , , ,2.0E-008, ,1.0E+005, , , ,2.0E-003, ,RANDOM,CD,TEST
B ,3, , , , ,4.0E-008, ,1.0E+005, , , ,4.0E-003, ,RANDOM,CD,TEST
D ,3, , , , ,5.0E-009, ,1.0E+005, , , ,5.0E-004, ,RANDOM,CD,TEST
E ,3, , , , ,1.0E-008, ,1.0E+005, , , ,1.0E-003, ,RANDOM,CD,TEST
SM_IF_COVREM ,1, , , ,4.0E-001, , , , , , ,4.0E-001, ,RANDOM,CD,TEST
SM_IF_COV ,1, , , ,6.0E-001, , , , , , ,6.0E-001, ,RANDOM,CD,TEST

TEST.FTD

TEST =
* Name , Description, SubTree, Alternate, Project
TOP , TEST , , , TEST

TEST.FTL

TEST, TOP =
TOP AND IF SM_IF
IF OR A B
SM_IF OR SM_IF_COVREM DPF
DPF AND SM_IF_COV SM_IF_GROUP
SM_IF_GROUP OR D E

TEST.GTD

TEST=
* Name , Description, Project
TOP , TEST , ,TEST
IF , IF Subtree , ,TEST
SM_IF , SM_IF , ,TEST
DPF , DPF , ,TEST
SM_IF_GROUP , SM_IF Subtree , ,TEST

図932.2にこれらのMARDをSpahireにロードし生成したFTを示します。

$$\img[-1.35em]{/images/withinseminar.png}$$

図932.3にSaphireで取得したMCSを示します。

図%%.3
図932.3 生成されたFTのMCS

Saphireで生成したcut setの表に対してPMHFの欄を追加し、かつ故障率の項を黄色で塗っています。これによりSPF/RFかDPFかが容易に理解されます。

なお、本稿はRAMS 2028に投稿予定のため一部を秘匿していますが、論文公開後の2028年2月頃に開示予定です。


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (20)

posted by sakurai on January 17, 2025 #931

前稿のExcelの整形マクロはChatGPTにより作成して貰ったものですが、備忘のため貼り付けておきます。

Option Explicit

Sub SampleMacro_Final()

    Dim ws As Worksheet
    Set ws = ActiveSheet  ' カレントシート

    '----------------------------------------------------------------------
    ' (A) まず、B列削除「前」のシートで C列(5行目以降)の最終行を求める
    '     ここをレコードの最終行とする。
    '----------------------------------------------------------------------
    Dim lastRow As Long
    With ws
        ' C列の最下行から上に向かい、最初に値(数値)がある行
        lastRow = .Cells(.Rows.Count, "C").End(xlUp).Row
    End With

    If lastRow < 5 Then
        MsgBox "C列の5行目以降にデータがありません。処理を中断します。"
        Exit Sub
    End If

    '----------------------------------------------------------------------
    ' (1) A6:A(lastRow) を数値化
    '----------------------------------------------------------------------
    With ws.Range("A6:A" & lastRow)
        .NumberFormat = "General"
        .Value = .Value
    End With

    '----------------------------------------------------------------------
    ' (2) B列を削除
    '----------------------------------------------------------------------
    ws.Columns("B").Delete

    '----------------------------------------------------------------------
    ' (3) B5:B(lastRow) → 旧C列 の内容を数値化
    '----------------------------------------------------------------------
    With ws.Range("B5:B" & lastRow)
        .NumberFormat = "General"
        .Value = .Value
    End With

    '----------------------------------------------------------------------
    ' (4) C5:C(lastRow) → 旧D列 の内容を数値化
    '----------------------------------------------------------------------
    With ws.Range("C5:C" & lastRow)
        .NumberFormat = "General"
        .Value = .Value
    End With

    '----------------------------------------------------------------------
    ' (5) グリッド線のチェックを外す
    '----------------------------------------------------------------------
    ActiveWindow.DisplayGridlines = False

    '----------------------------------------------------------------------
    ' (6) A4:F4 に罫線 & グレー15% & 中央揃え、見出し "PMHF[FIT]" を F4 に
    '----------------------------------------------------------------------
    With ws.Range("A4:F4")
        .Borders.LineStyle = xlContinuous
        .Borders.Weight = xlThin
        .Borders(xlInsideVertical).LineStyle = xlContinuous
        .Borders(xlInsideVertical).Weight = xlThin
        .Borders(xlInsideHorizontal).LineStyle = xlContinuous
        .Borders(xlInsideHorizontal).Weight = xlThin
        .Interior.ColorIndex = 15
        .HorizontalAlignment = xlCenter
    End With
    ws.Range("F4").Value = "PMHF[FIT]"

    '----------------------------------------------------------------------
    ' (7) A5:F5 を罫線(背景は標準)、揃えはあとでまとめる
    '----------------------------------------------------------------------
    With ws.Range("A5:F5")
        .Borders.LineStyle = xlContinuous
        .Borders.Weight = xlThin
        .Borders(xlInsideVertical).LineStyle = xlContinuous
        .Borders(xlInsideVertical).Weight = xlThin
        .Borders(xlInsideHorizontal).LineStyle = xlContinuous
        .Borders(xlInsideHorizontal).Weight = xlThin
    End With

    '----------------------------------------------------------------------
    ' A列が "total" or 数値 → F列に =B列/1E5*1E9 (小数点1桁表示)
    ' 対象は 行5~lastRow
    '----------------------------------------------------------------------
    Dim r As Long
    Dim valA As Variant
    For r = 5 To lastRow
        valA = ws.Range("A" & r).Value
        If LCase(valA) = "total" Or (IsNumeric(valA) And Not IsEmpty(valA)) Then
            ws.Range("F" & r).Formula = "=B" & r & "/1E5*1E9"
            ws.Range("F" & r).NumberFormat = "0.0"
        End If
    Next r

    '----------------------------------------------------------------------
    ' (8)~(10) グループごとに "外枠のみ" 罫線 → 行6~lastRow
    '----------------------------------------------------------------------
    Dim i As Long, j As Long
    Dim dataA As Variant, dataD As Variant
    Dim foundRow As Long

    i = 6
    Do While i <= lastRow
        dataA = ws.Range("A" & i).Value
        dataD = ws.Range("D" & i).Value  ' 旧E列→新D列など列シフトに注意

        ' 終了条件: AもDも空 or i>lastRow
        If (IsEmpty(dataA) Or dataA = "") And (IsEmpty(dataD) Or dataD = "") Then
            Exit Do
        End If

        foundRow = 0
        For j = i + 1 To lastRow + 1
            If j > lastRow Then
                ' 見つからず最後まで到達 → グループをラスト行までで終える
                foundRow = lastRow + 1
                Exit For
            End If

            Dim tmpA As Variant, tmpD As Variant
            tmpA = ws.Range("A" & j).Value
            tmpD = ws.Range("D" & j).Value

            If (IsEmpty(tmpA) Or tmpA = "") And (IsEmpty(tmpD) Or tmpD = "") Then
                foundRow = j
                Exit For
            End If
            If (IsNumeric(tmpA) And Not IsEmpty(tmpA)) Or (IsEmpty(tmpD) Or tmpD = "") Then
                foundRow = j
                Exit For
            End If
        Next j

        If foundRow = 0 Then
            Exit Do
        End If

        ' グループ外枠のみ罫線
        Call SetOuterBorders(ws.Range(ws.Cells(i, "A"), ws.Cells(foundRow - 1, "F")))

        i = foundRow
    Loop

    '----------------------------------------------------------------------
    ' (11)~(15) 相当: A6:F(lastRow) に最終的な罫線(外枠+縦罫線)
    '----------------------------------------------------------------------
    Call SetOuterBorders(ws.Range("A6:F" & lastRow))
    Call SetInsideVerticalBorders(ws.Range("A6:F" & lastRow))

    '----------------------------------------------------------------------
    ' D1結合対策(任意)
    '----------------------------------------------------------------------
    ws.Range("D1").MergeArea.ClearContents
    With ws.Range("A1:E1")
        .Merge
        .HorizontalAlignment = xlLeft
    End With

    '----------------------------------------------------------------------
    ' ★ E列の色付け
    '   A列が "total" or 数値 → 色なし
    '   A列がその他(空含む) → E列末尾が FIT/% なら色なし、その他はオレンジ
    '   E列が空なら色なし
    '----------------------------------------------------------------------
    Dim valE As Variant
    Dim strA As String, strE As String
    
    For r = 5 To lastRow

        valA = ws.Range("A" & r).Value
        ' A列を文字列化&Trim
        strA = Replace(Replace(Replace(CStr(valA), vbCr, ""), vbLf, ""), " ", "")
        strA = Trim(strA)
        
        ' A列が "total" or 数値(1,2,3...) → E列は色なし
        If LCase(strA) = "total" Or (IsNumeric(strA) And strA <> "") Then
            ws.Range("E" & r).Interior.ColorIndex = xlNone
        
        Else
            ' A列が空やその他 → E列の末尾チェック
            valE = ws.Range("E" & r).Value
            strE = Replace(Replace(Replace(CStr(valE), vbCr, ""), vbLf, ""), " ", "")
            strE = Replace(strE, Chr(160), "")  ' ノーブレークスペースも除去
            strE = Trim(strE)
            
            Dim chkE As String
            chkE = LCase(strE)
            
            ' 末尾が ")" なら削除(必要なら)
            If Right(chkE, 1) = ")" Then
                chkE = Left(chkE, Len(chkE) - 1)
            End If
            
            ' E列が空
            If chkE = "" Then
                ws.Range("E" & r).Interior.ColorIndex = xlNone
                
            ' FIT で終わる
            ElseIf Right(chkE, 3) = "fit" Then
                ws.Range("E" & r).Interior.ColorIndex = 6
            
            ' %  で終わる
            ElseIf Right(chkE, 1) = "%" Then
                ws.Range("E" & r).Interior.ColorIndex = xlNone
            
            ' その他 → オレンジ
            Else
                ws.Range("E" & r).Interior.ColorIndex = 45
            End If
            
        End If
    Next r
    
    '----------------------------------------------------------------------
    ' 列オートフィット & 横位置
    '    (A,B,C,F→右揃え / D,E→左揃え) を最終行まで
    '----------------------------------------------------------------------
    ws.Range("A4:F" & lastRow).Columns.AutoFit
    
    With ws.Range("A5:A" & lastRow): .HorizontalAlignment = xlRight: End With
    With ws.Range("B5:B" & lastRow): .HorizontalAlignment = xlRight: End With
    With ws.Range("C5:C" & lastRow): .HorizontalAlignment = xlRight: End With
    With ws.Range("D5:D" & lastRow): .HorizontalAlignment = xlLeft:  End With
    With ws.Range("E5:E" & lastRow): .HorizontalAlignment = xlLeft:  End With
    With ws.Range("F5:F" & lastRow): .HorizontalAlignment = xlRight: End With

    MsgBox "処理が完了しました。最終行は " & lastRow

End Sub


'------------------------------------------------------------------------------
' 外枠だけ罫線を付ける
'------------------------------------------------------------------------------
Private Sub SetOuterBorders(rng As Range)
    With rng
        With .Borders(xlEdgeLeft)
            .LineStyle = xlContinuous
            .Weight = xlThin
        End With
        With .Borders(xlEdgeTop)
            .LineStyle = xlContinuous
            .Weight = xlThin
        End With
        With .Borders(xlEdgeRight)
            .LineStyle = xlContinuous
            .Weight = xlThin
        End With
        With .Borders(xlEdgeBottom)
            .LineStyle = xlContinuous
            .Weight = xlThin
        End With
    End With
End Sub

'------------------------------------------------------------------------------
' 縦の内側線だけ
'------------------------------------------------------------------------------
Private Sub SetInsideVerticalBorders(rng As Range)
    With rng.Borders(xlInsideVertical)
        .LineStyle = xlContinuous
        .Weight = xlThin
    End With
End Sub

ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。

なお、本稿はRAMS 2028に投稿予定のため一部を秘匿していますが、論文公開後の2028年2月頃に開示予定です。


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (19)

posted by sakurai on January 16, 2025 #930

ChatGPTにRBDを示してFTを生成させます。まず基本形のRBDを図930.1に示します。

図%%.1
図930.1 RBD

ここでは2nd SMは省略しています。その理由はワーストケース評価を行いたいためです。冗長系ではRFがほとんど存在しないため、2nd SMの効果が大きく見えてきますが、このような非冗長系においては1st SMの効果であるRFが支配的であり、経験からはRFは95%以上となる場合が多いと考えます。

図930.1を読み取ったChatGPTの生成したMARDファイルを以下に示します。

TEST.BED

*Saphire 8.2.9
TEST =
* Name , Descriptions , Project
IF_FAULT , IF fault(10FIT) , TEST
SM_FAULT , SM_IF fault(20FIT) , TEST
SM_IF_COVREM , SM_IF coverage leftover(1-DC=10%) , TEST
SM_IF_COV , SM_IF coverage(DC=90%) , TEST

TEST.BEI

*Saphire 8.2.9
TEST =
* Name ,FdT,UdC,UdT,UdValue, Prob, Lambda, Tau, Mission, Init,PF,UdValue2,Calc. Prob,Freq,Analysis Type,Phase Type,Project
IF_FAULT ,3, , , , ,1.0E-008, ,1.0E+005, , , ,1.0E-003, ,RANDOM,CD,TEST
SM_FAULT ,3, , , , ,2.0E-008, ,1.0E+005, , , ,2.0E-003, ,RANDOM,CD,TEST
SM_IF_COVREM ,1, , , ,1.0E-001, , , , , , ,1.0E-001, ,RANDOM,CD,TEST
SM_IF_COV ,1, , , ,9.0E-001, , , , , , ,9.0E-001, ,RANDOM,CD,TEST

TEST.FTD

TEST =
* Name , Description, SubTree, Alternate, Project
TOP , TEST , , , TEST

TEST.FTL

TEST, TOP =
TOP AND IF_FAULT SM_IF
SM_IF OR SM_IF_COVREM DPF
DPF AND SM_IF_COV SM_FAULT

TEST.GTD

TEST=
* Name , Description, Project
TOP , TEST , ,TEST
SM_IF , SM_IF gate , ,TEST
DPF , coverage partial path , ,TEST

図930.2にこれらのMARDをSpahireにロードし生成したFTを示します。

$$\img[-1.35em]{/images/withinseminar.png}$$

比較のために前記事に掲載した基本形のFT図$\dagger$を示します。

図%%.3
図929.1 生成されたFT

図930.3にSaphireで取得したMCSを示します。予想どおりRFが98%以上であり、DPFは2%未満となりました。

図%%.3
図930.3 生成されたFTのMCS

Saphireで生成したcut setの表に対してPMHFの欄を追加し、かつ故障率の項を黄色で塗っています。これによりSPF/RFかDPFかが容易に理解されます。

なお、本稿はRAMS 2028に投稿予定のため一部を秘匿していますが、論文公開後の2028年2月頃に開示予定です。


$\dagger$ S. Atsushi, "A Framework for Performing Quantitative Fault Tree Analyses for Subsystems with Periodic Repairs," 2021 Annual Reliability and Maintainability Symposium (RAMS), Orlando, FL, USA, 2021, pp. 1-6.


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (18)

posted by sakurai on January 15, 2025 #929

Fault Treeの構成

PMHF式に準拠してFault Tree (FT)を構成します。まず基礎となるFTは図929.1のとおりです。このFT構成法は弊社の$\dagger$過去論文に依るものです。これは後で示すPMHF式を再現するように構成しています。

図%%.1
図929.1 FTの構成

次に対応するPMHF式を示します。前記FTの構成法にはMethod 1, 2, 3と3種あり、それぞれ以下のような特徴があります。

  • Method 1: 2nd SMが無いものとする。もっとも単純なツリーであり、真値よりもPMHFは大となるため、初期にワーストケースを見るのに都合が良い。 $$ M_\text{PMHF}=(1-K_\text{IF,RF})\lambda_\text{IF}+K_\text{IF,RF}\lambda_\text{IF}\lambda_\text{SM} $$
  • Method 2: 2nd SMのカバレージ$K_\text{SM,MPF}$の効果を加えたもの。ただし、真値よりも次のMethod 3で加わる効果が入っていない分だけPMHFが小さく算出されることが問題。ただしこの誤差は$K_\text{SM,MPF}$が小さい時または$\tau$が小さい時は無視できる。 $$ M_\text{PMHF}=(1-K_\text{IF,RF})\lambda_\text{IF}+K_\text{IF,RF}\lambda_\text{IF}\lambda_\text{SM}\color{red}{\left((1-K_\text{SM,MPF})T_\text{lifetime}\right)} $$
  • Method 3: Method 2の効果に加えて、2nd SMの定期検査周期間$\tau$内の不検出効果を加える。PMHFとしては真値であるが、加えた不検出効果は、$K_\text{SM,MPF}$が小さい時または$\tau$が小さい時は無視できる。 $$ M_\text{PMHF}=(1-K_\text{IF,RF})\lambda_\text{IF}+K_\text{IF,RF}\lambda_\text{IF}\lambda_\text{SM}\left((1-K_\text{SM,MPF})T_\text{lifetime}\color{red}{+K_\text{SM,MPF}\tau}\right) $$

Method 3の係数の効果を3Dグラフに表すと図929.2のような形になります。

$$\img[-1.35em]{/images/withinseminar.png}$$

記事#927で述べたように、$K_\text{MPF}$が小さいか$\tau$が小さい場合にはこの効果は無視できます。

なお、本稿はRAMS 2028に投稿予定のため一部を秘匿していますが、論文公開後の2028年2月頃に開示予定です。


$\dagger$ S. Atsushi, "A Framework for Performing Quantitative Fault Tree Analyses for Subsystems with Periodic Repairs," 2021 Annual Reliability and Maintainability Symposium (RAMS), Orlando, FL, USA, 2021, pp. 1-6.


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (17)

posted by sakurai on January 14, 2025 #928

Method3での新旧係数比較

昔の記事の表217.1にMethod3での手作業の係数がまとめてありますが、これとChatGPTによる係数の割り当てを比較します。

まずChatGPTにカットセットの旧の表(表217.2)と新の表(表925.1)を見せ、old.txtとnew.txtを作成してもらいました。

old.txt

C4,M1,M2
C2,M2,SC1
C2,M1,SC2
C1,SC1,SC2
C1,SA1,SA2
C2,M2,MCU1
C2,M1,MCU2
C1,MCU2,SC1
C1,MCU1,SC2
C5,I2,M1
C5,I1,M2
C1,MCU1,MCU2
C3,I2,SC1
C3,I1,SC2
C7,I1,I2
C3,I2,MCU1
C3,I1,MCU2
C8,I2,P1
C8,I1,P2
C6,M2,P1
C6,M1,P2
C4,P2,SC1
C4,P1,SC2
C9,P1,P2
C4,MCU2,P1
C4,MCU1,P2
C2,D2,M1
C2,D1,M2
C1,D2,SC1
C1,D1,SC2
C1,D2,MCU1
C1,D1,MCU2
C3,D2,I1
C3,D1,I2
C3,CA2,SA1
C3,CA1,SA2
C4,D2,P1
C4,D1,P2
C1,D1,D2
C7,CA1,CA2

new.txt

C12,M1,M2
C17,M2,SC1
C17,M1,SC2
C15,SC1,SC2
C15,SA1,SA2
C17,M2,MCU1
C17,M1,MCU2
C15,MCU2,SC1
C15,MCU1,SC2
C19,I2,M1
C19,I1,M2
C15,MCU1,MCU2
C16,I2,SC1
C16,I1,SC2
C18,I1,I2
C16,I2,MCU1
C16,I1,MCU2
C13,I2,P1
C13,I1,P2
C14,M2,P1
C14,M1,P2
C12,P2,SC1
C12,P1,SC2
C11,P1,P2
C12,MCU2,P1
C12,MCU1,P2
C17,D2,M1
C17,D1,M2
C15,D2,SC1
C15,D1,SC2
C15,D2,MCU1
C15,D1,MCU2
C16,D2,I1
C16,D1,I2
C16,CA2,SA1
C16,CA1,SA2
C12,D2,P1
C12,D1,P2
C15,D1,D2
C18,CA1,CA2

さらにそれを比較するプログラムを作成してもらいました。

#!/usr/bin/env python3
import sys
import csv
from collections import defaultdict

"""
Usage:
  python transform_coverage.py old.txt new.txt

Where:
  old.txt, new.txt each line looks like:
    C4,M1,M2
    C1,SA1,SA2
  etc.

We parse the first token as coverage name (e.g. 'C4'),
the rest as element names (e.g. 'M1','M2').
We store them in a dictionary keyed by the sorted tuple of elements.

Then we produce a transform table:
  old_coverage -> new_coverage
for each matching element-tuple.
If multiple old coverages map to the same new coverage or vice versa,
we show those collisions or many-to-many relationships explicitly.
"""

def parse_cutset_file(filename):
    """
    Parse lines like "C4,M1,M2" into:
      coverage='C4'
      elements=('M1','M2')  # sorted
    We'll store coverage -> set of element_tuples
    We'll also store element_tuple -> coverage
    Returns (coverage2sets, element2cov)
    """
    coverage2sets = defaultdict(set)   # coverage -> { (el1,el2,...) , ... }
    element2cov = {}
    with open(filename, "r", encoding="utf-8") as f:
        for line in f:
            line=line.strip()
            if not line or line.startswith("#"):
                continue
            # split by comma
            parts = [x.strip() for x in line.split(",")]
            coverage = parts[0]
            elements = parts[1:]
            # sort elements so (M1,M2) == (M2,M1)
            sorted_e = tuple(sorted(elements))
            coverage2sets[coverage].add(sorted_e)
            element2cov[sorted_e] = coverage
    return coverage2sets, element2cov

def main(oldfile, newfile):
    old_cov2sets, old_elem2cov = parse_cutset_file(oldfile)
    new_cov2sets, new_elem2cov = parse_cutset_file(newfile)

    # We'll create a transform table: oldCov -> newCov
    # by checking each element tuple in old
    # and see what coverage is assigned in new.
    transform_map = defaultdict(set)  
    # key=oldCoverageName, value=set of newCoverageNames
    # Because it's possible multiple new coverages appear.

    # Also track if some old coverage references multiple distinct new coverage
    # or vice versa.

    # all element tuples from old
    for etuple, oldcov in old_elem2cov.items():
        if etuple in new_elem2cov:
            newcov = new_elem2cov[etuple]
            transform_map[oldcov].add(newcov)
        else:
            # no match in new => discrepancy
            transform_map[oldcov].add("NO_MATCH_IN_NEW")

    # Now produce a nice table
    print("=== Coverage transform table ===")
    for oldcov in sorted(transform_map.keys()):
        newcovs = transform_map[oldcov]
        if len(newcovs)==1:
            single = list(newcovs)[0]
            if single=="NO_MATCH_IN_NEW":
                print(f"{oldcov} => [NO MATCH in NEW file!]")
            else:
                print(f"{oldcov} => {single}")
        else:
            # multiple new coverages
            nclist = ",".join(sorted(newcovs))
            print(f"{oldcov} => {{{nclist}}}  # multiple new coverage found for same old coverage")

    print()
    print("=== Reverse check: new coverage => old coverage ===")
    # We'll do similarly in reverse
    # create new_elem2cov from parse => done
    # but we want coverage -> set of element tuples
    rev_map = defaultdict(set)  # new-> old coverage
    for etuple, newcov in new_elem2cov.items():
        if etuple in old_elem2cov:
            oldcov = old_elem2cov[etuple]
            rev_map[newcov].add(oldcov)
        else:
            rev_map[newcov].add("NO_MATCH_IN_OLD")

    for newcov in sorted(rev_map.keys()):
        oldcovs = rev_map[newcov]
        if len(oldcovs)==1:
            single = list(oldcovs)[0]
            if single=="NO_MATCH_IN_OLD":
                print(f"{newcov} => [NO MATCH in OLD file!]")
            else:
                print(f"{newcov} => {single}")
        else:
            # multiple old coverage
            oclist = ",".join(sorted(oldcovs))
            print(f"{newcov} => {{{oclist}}}  # multiple old coverage found for same new coverage")

    print()
    print("=== Detailed mismatch check (cutset by cutset) ===")
    # We'll unify the union of all element tuples
    all_etups = set(list(old_elem2cov.keys())+ list(new_elem2cov.keys()))
    for et in sorted(all_etups):
        ocov = old_elem2cov.get(et,"-")
        ncov = new_elem2cov.get(et,"-")
        elements_str = ",".join(et)
        print(f"Cutset({elements_str}): old={ocov} , new={ncov}")

if __name__=="__main__":
    if len(sys.argv)<3:
        print("Usage: python transform_coverage.py old.txt new.txt")
        sys.exit(0)
    oldfile=sys.argv[1]
    newfile=sys.argv[2]
    main(oldfile,newfile)

ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。

次に以下のコマンドにより、新旧の対応を表示します。

\$ python transform_cov.py old.txt new.txt | head -10 | tail -9

この出力は

C1 => C15
C2 => C17
C3 => C16
C4 => C12
C5 => C19
C6 => C14
C7 => C18
C8 => C13
C9 => C11

となるので、これを表にまとめます。新係数C??の値は直接MARD中のBEIファイルから拾いました。

表928.1
定数記号 定数値 定数記号 定数値
C1 0.2280772 C15 0.2280772
C2 0.2287720 C17 0.2287720
C3 0.2310880 C16 0.2310880
C4 0.2357200 C12 0.2357200
C5 0.2588800 C19 0.2588800
C6 0.3052000 C14 0.3052000
C7 0.3515200 C18 0.3515200
C8 0.5368000 C13 0.5368000
C9 1.0000000 C11 1.0000000

係数名の振り方は異なるものの、係数値とそのエレメントペアへの割り当ては完全に一致していることが確認できました。数値自体も旧のC1~9は表217.1を用いています。

割り当て係数が全く同じであるにも関わらず昔の記事今の記事の頂上侵害確率が、旧$8.32\color{red}{1}\cdot 10^{-4}\Rightarrow$新$8.32\color{red}{4}\cdot 10^{-4}$、及びPMHFにおいて、旧$55.4\color{red}{7}\Rightarrow$新$55.4\color{red}{9}$が若干異なるのは、Saphireの版数の違いと考えられます。旧は2020年版、新は2024年版です。

なお、本稿はRAMS 2026に投稿予定のため一部を秘匿していますが、論文公開後の2026年2月頃に開示予定です。


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (16)

posted by sakurai on January 13, 2025 #927

3手法と正解値との比較表

3つの手法1, 2, 3について微妙に異なる結果が出たので、表にまとめます。まずExcelによる正解値を算出するのに不信頼度$F(t)$を $$F(t)\approxλt$$ と近似する場合。次に同じく不信頼度$F(t)$を $$F(t)=1-e^{-λt}$$ で表す場合。最後にSaphire 8.2.9 (2024年版)でカットセット分析を実施した値の順に示します。

-Method 1Method 2Method 3
Excel$F(t)\approx\lambda T$頂上事象侵害確率3.428e-37.903e-58.425e-4
PMHF [FIT]228.55.26956.17
$F(t)=1-e^{-\lambda T}$頂上事象侵害確率3.385e-37.840e-58.324e-4
PMHF [FIT]225.75.22755.49
Saphire頂上事象侵害確率3.381e-37.841e-58.324e-4
PMHF [FIT]225.45.22755.49

SaphireとExcelによる$F(t)=1-e^{-\lambda T}$の結果がほぼ一致したことから(これは次稿で解説予定)、Saphireは不信頼度を近似式ではなく正確に求めていることがわかります。ただし、最初の$\lambda T$はPMHF計算の近似により算出された項であることからこれはこれで正しいと考えられるので、$1-e^{\lambda T}$やSaphireの計算のほうが正確であるとも言えません。

PMHFにおける$\tau$の効果

次にMethod 3における$\tau$の値の効き方を調べます。論文においては$\tau=1 [H]$であるようでした。一方ブログでは$\tau=3,420 [H]$として計算しています。

現状では$\tau=3,420 [H]$の時にPMHFは55.49[FIT]ですが、ASIL-Dターゲットの10[FIT]になるには、$\tau$をどの程度まで小さくする必要があるかをExcelのゴールシークで調べたところ、 $$\img[-1.35em]{/images/withinseminar.png}$$ という結論になりました。これは車両寿命の2.17%となり、この例の冗長系がASIL-Dを満足するためには、定期点検修理間隔は車両寿命の2.17%未満である必要があります。

なお、本稿はRAMS 2026に投稿予定のため一部を秘匿していますが、論文公開後の2026年2月頃に開示予定です。


左矢前のブログ 次のブログ右矢

Fault treeの自動生成 (15)

posted by sakurai on January 10, 2025 #926

Method 3に向けてChatGPT-o1 proに作成させたpythonプログラムを示します。これは各エレメントの故障率及び2nd SMによるカバレージに基づき、FTを構成するファイル群MARDを生成するプログラムです。

#!/usr/bin/env python3
import math

# 1) 各要素のFIT(λ)およびカバレッジDC
FIT_map = {
    "P":   2.33e-7,
    "MCU": 8.18e-7,
    "D":   1.09e-7,
    "I":   5.99e-7,
    "M":   1.00e-6,
    "SC":  1.00e-6,
    "CA":  5.10e-8,
    "SA":  1.00e-6,
}
DC_map = {
    "P":   0.00,
    "MCU": 0.99,
    "D":   0.99,
    "I":   0.60,
    "M":   0.90,
    "SC":  0.99,
    "CA":  0.60,
    "SA":  0.99,
}

# 上流G11,G21 => 36ペア, 下流G12,G22 => 4ペア 合計40
G11 = ["P1","MCU1","D1","I1","M1","SC1"]
G21 = ["P2","MCU2","D2","I2","M2","SC2"]
G12 = ["CA1","SA1"]
G22 = ["CA2","SA2"]

T_mission = 1.5e4         # 15000h
tau_over_TL = 3420.0/15000.0  # 0.228

def lam(e):
    """ Return FIT value (lambda) for e (e.g. 'M1' -> base 'M'). """
    return FIT_map[e[:-1]]

def DC(e):
    """ Return DC coverage for e. """
    return DC_map[e[:-1]]

def factor_method3(e1,e2):
    """ Compute factor(4桁丸め前) for handout(手法3):
        base = (1-DC(e1))*(1-DC(e2))
        factor = base + (1-base)*tau_over_TL
    """
    base = (1 - DC(e1)) * (1 - DC(e2))
    return base + (1.0 - base)*tau_over_TL

def all_pairs():
    """ 全40ペア: 上流36 + 下流4 """
    idx=0
    for x in G11:
        for y in G21:
            idx+=1
            yield idx,x,y
    for x in G12:
        for y in G22:
            idx+=1
            yield idx,x,y

# 2) 40ペアの計算
pairs = []
for (i,e1,e2) in all_pairs():
    pairs.append((i,e1,e2))
pairs.sort(key=lambda x:x[0])

# coverage factorを 4桁丸めでユニーク管理し、C11 から順番付与
coverage_map = {}  # dict: factor_4 -> coverage_name
coverage_list = [] # list to store (coverage_name, factor_4)

def coverage_name_for(f4):
    """ 4桁丸めした factor f4 に対応する coverage 名を割当。 
        最初に出たfactorにはC11、その次C12… 
    """
    if f4 in coverage_map:
        return coverage_map[f4]
    # 次のインデックス
    idx = len(coverage_map)  # 0-based
    cname = f"C{idx+11}"     # e.g. if idx=0 => 'C11', idx=1 => 'C12', ...
    coverage_map[f4] = cname
    coverage_list.append( (cname, f4) )
    return cname

results = []
for (i,e1,e2) in pairs:
    raw_factor = factor_method3(e1,e2)   # not rounded yet
    f4 = round(raw_factor,4)            # 4桁丸め
    c_name = coverage_name_for(f4)
    results.append( (i,e1,e2,raw_factor,f4,c_name) )

results.sort(key=lambda x:x[0])

# 各BasicEvent
basic_events = [
  "P1","MCU1","D1","I1","M1","SC1","CA1","SA1",
  "P2","MCU2","D2","I2","M2","SC2","CA2","SA2"
]

def lam_str(e):
    """ return lam in 3E format """
    l = lam(e)
    return f"{l:.3E}"

def unreli(e):
    """ 1-exp(-lam*T_mission) """
    l= lam(e)
    import math
    return 1.0 - math.exp(-l*T_mission)

# 3) 5ファイルを出力
#   METHOD3.BED, METHOD3.BEI, METHOD3.FTD, METHOD3.FTL, METHOD3.GTD
bed_lines = []
bei_lines = []
ftd_lines = []
ftl_lines = []
gtd_lines = []

# 3.1 BED
bed_lines.append("*Saphire 8.2.9\nTEST =")
bed_lines.append("* Name , Descriptions , Project")
for be in basic_events:
    bed_lines.append(f"{be} , {be}desc , TEST")
for (cn,f4) in coverage_list:
    bed_lines.append(f"{cn} , CoverageFactor_{cn} , TEST")

# 3.2 BEI
bei_lines.append("*Saphire 8.2.9\nTEST =")
bei_lines.append("* Name ,FdT,UdC,UdT,UdValue,Prob,Lambda,Tau,Mission,Init,PF,UdValue2,Calc. Prob,Freq,Analysis Type,Phase Type,Project")
# basic events
for be in basic_events:
    l = lam(be)
    l_str = f"{l:.3E}"
    un = unreli(be)
    un_str = f"{un:.3E}"
    # FdT=3 => exp. dist, prob => un
    line = f"{be} ,3, , ,0.000E+000,0.000E+000,{l_str},0,1.500E+004, , ,0.000E+000,{un_str}, ,RANDOM,CD,TEST"
    bei_lines.append(line)
# coverage
for (cn,f4) in coverage_list:
    f_str = f"{f4:.4E}"
    line = f"{cn} ,1, , ,0.000E+000,{f_str},0.000E+000,0,0.000E+000, , ,0.000E+000,{f_str}, ,RANDOM,CD,TEST"
    bei_lines.append(line)

# 3.3 FTD
ftd_lines.append("TEST =")
ftd_lines.append("* Name , Description, SubTree, Alternate, Project")
ftd_lines.append("METHOD3 ,Method3TopDefinition, , ,TEST")

# 3.4 FTL
ftl_lines.append("*Saphire 8.2.9")
ftl_lines.append("TEST,METHOD3 =")
mcsnames = [f"MCS{i:02d}" for i in range(1,41)]
mcs_line = " ".join(mcsnames)
ftl_lines.append(f"METHOD3 OR {mcs_line}")
for (i,e1,e2,rawf,f4,cname) in results:
    mcs = f"MCS{i:02d}"
    ftl_lines.append(f"{mcs} AND {e1} {e2} {cname}")

# 3.5 GTD
gtd_lines.append("TEST=")
gtd_lines.append("* Name , Description, Project")
gtd_lines.append("METHOD3 ,Method3TopGate, TEST")
for i in range(1,41):
    gtd_lines.append(f"MCS{i:02d} ,Pair{i:02d}, TEST")


# ---- Write out actual files ----
def write_file(fname, lines):
    with open(fname, "w", encoding="utf-8") as f:
        for ln in lines:
            f.write(ln+"\n")

write_file("METHOD3.BED", bed_lines)
write_file("METHOD3.BEI", bei_lines)
write_file("METHOD3.FTD", ftd_lines)
write_file("METHOD3.FTL", ftl_lines)
write_file("METHOD3.GTD", gtd_lines)

print("Created METHOD3.BED, METHOD3.BEI, METHOD3.FTD, METHOD3.FTL, METHOD3.GTD successfully.")

ChatGPT の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。


左矢前のブログ 次のブログ右矢

posted by sakurai on January 9, 2025 #925

SAPHIREで前稿で生成したMARDファイルをロードすると、図925.1のようなFTが生成されます。

図%%.1
図925.1 Method 3のFault Tree

次にSolveで論理圧縮をかけ、View CutSetによりカットセットを表示させます。

表925.1 Method 3のFault Treeのカットセット
図%%.2

表925.1に示すとおり、頂上事象の確率は $\img[-1.35em]{/images/withinseminar.png}$ となります。

2020年にSaphireを使用した同じMethod3の以前の記事では頂上事象の確率は8.321E-04でした。若干異なるのは丸め誤差や内部精度が変わったのかもしれません。

なお、本稿はRAMS 2026に投稿予定のため一部を秘匿していますが、論文公開後の2026年2月頃に開示予定です。


左矢前のブログ 次のブログ右矢

12月の検索結果

posted by sakurai on January 8, 2025 #924

弊社コンテンツの昨年12月の検索結果です。

表924.1 上昇率上位のページ(前月との比較)
タイトル クリック数
PMHFの意味 +57
故障率 +22
レイテントフォールトの奥深さ +18

表924.2 パフォーマンス上位のページ
タイトル クリック数
機能安全用語集 153
1st Editionと2nd Editionとの相違点 (Part 10) 98
ASILデコンポジション 89

表924.3 上昇率上位のクエリ
クエリ クリック数
デコンポジション +7
FTTIとは +4
ASILデコンポジション +2

表924.4 パフォーマンス上位のクエリ
クエリ クリック数
FTTI 53
PMHF 23
レイテントフォールトとは 17


左矢前のブログ 次のブログ右矢


ページ: