Posts Issued in July, 2025

posted by sakurai on July 31, 2025 #1002

まず、ChatGPTに、BSVの2線ハンドシェイクアルゴリズムを尋ねてみます。

bluespecのモジュールでは自動的に2線方式のハンドシェークが行われるが、そのアルゴリズムを解説してください。


以下、Blu­e­s­pec がモジュール間/ルール間で自動的に挿入する「2線ハンドシェーク」の 正確なアルゴリズム をまとめ直します。

1. ハンドシェークの基本モデル

各メソッド呼び出し(あるいはルール起動)には、必ず以下の2本の信号が対応します。

信号 BSV上の名前 役割
Ready can_fire() Callee(呼ばれる側)が 実行可能 かを示す純組合せフラグ (ready)
Enable will_fire Caller(呼ぶ側)が 実際に起動 する1サイクルパルス (enable)
  • Ready (can_fire) は、FIFO なら !full、Register なら常に True、独自モジュールなら内部状態から算出される組合せ信号です。
  • Enable (will_fire) は後述のルール・スケジューラによって自動合成される一周期パルス信号で、これが Callee の *_enポートに接続されます。

2. ルール/メソッド呼び出し単位での合成フロー

2.1 各メソッドのcan_fire 取得

ルールの本文中で呼ぶメソッドが複数ある場合、まずそれぞれの Ready 信号を取り出します。

rule foo when (guard);
   let v  <- A.method1.can_fire;   // ①
       w  <- B.method2.can_fire;   // ②
   …
endrule

(実際は can_fire()はメソッド呼出子の後ろに自動で付く組合せロジックです)

2.2 ルール単位の can_fire_rule (= 全 Ready の AND)

ルールは「自分のガードが真 & すべての callee が Ready」で発火可能です。

wire can_fire_rule = guard && A_ready && B_ready;

2.3 スケジューラ仲裁 (scheduler_grant)

同じリソース(レジスタやポート)に対して競合する他ルールとの静的解析結果に基づき、 can_fire_rule 同士の優先度/排他を決める組合せロジックが入ります。

// 競合ルール同士なら priority_bits で排他
wire grant_rule = can_fire_rule & scheduler_logic(…);

2.4 will_fire(= 発火パルス)

上記 grant_ruleが 1 サイクルだけ 真になる「発火許可パルス」となり、 これが Enable 信号として扱われます。

wire will_fire = grant_rule;  // 1-cycle pulse

2.5 Callee への配線 (扇形ファンアウト)

得られた will_fire を、ルール本文で呼び出したすべてのメソッドの*_en(Enable)端子に繋ぎます。

assign A_en = will_fire;
assign B_en = will_fire;

2.6 レジスタ更新の en 端子

同じ will_fire をそのルール内のレジスタ書き込み *_en にも使うので、 レジスタ更新 も同一パルスでまとめて走ります。

3. 複数ルール/複数メソッドの競合回避

  • 同一リソースを書き換える複数ルール は、静的優先度ツリー(priority tree)で排他し、あるルールが will_fire すると他は偽になります。
  • 同一ルール内の複数メソッド呼び出し は、ひとつの will_fireで 同時に 起動。
  • 非競合ルール どうしは並列に will_fire可能。

合成後、以下のような MUX/OR ネットワークが作られます:

// レジスタ更新データの MUX(優先度付き)
assign reg_din =
      (rule2_will_fire) ? data2 :
      (rule1_will_fire) ? data1 :
                          reg_q;

// write-enable の OR
assign reg_en = rule1_will_fire | rule2_will_fire | … ;

4. まとめ:2線ハンドシェークの要点

  1. Ready (can_fire)

    • Callee が 組合せで「今受け入れられるか」を出力。
  2. Enable (will_fire)

    • ルール単位で「ガード & 全 Ready & スケジューラ許可」を合成し、
    • 1 サイクルだけ真になるパルスを自動生成。
  3. ファンアウト
    • そのパルスを該当するすべてのメソッド/レジスタの *_en に扇形配線。
  4. 競合解消
    • 複数ルール間の静的優先度/排他はコンパイラが生成。
  5. ユーザ記述不要
    • can_fire()以外はすべて BSC が自動で合成し、
    • 人手で AND/OR や MUX を書く必要はありません。

これが Bluespec SystemVerilog が内部的に繰り返す 「2 線方式ハンドシェーク」 の実装アルゴリズムです。


caller/calleeが分かりにくかったですが、callerは最上位、calleeがモジュールで、この場合は両FSMとなります。


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

posted by sakurai on July 30, 2025 #1001

外部投稿記事において、2つのFSM(Finite State Machine)の調停を図るコマンドバッファOneStageを設計しました。このコマンドバッファもFSMであり、GameFSMからくるサウンドコマンドを一時保持し、SoundFSMがそれを引き取り当該サウンドを鳴らすというものです。実際には中間バッファは省略し、制御のみでコマンドバッファ制御を実行しています。

図%%.1
図1001.1 GameFSMとSoundFSMの調停

実はBSVはこのような調停の仕組みを自動で持っていて、bscはそれを自動生成することができます。ChatGPTの助けを借りて、これを実装します。

また、中間バッファとしてFIFOが必要かどうかも助言を受けます。以前の記事中にあるとおり、FIFOは付ければ良いというものではなく、付ければ付けるほど取りこぼしは減るもののレイテンシーが大きくなります。

さらに、取りこぼしを防ぐため、SoundFSMがbusyとなることを避ける目的から、基本的には全てのコマンドをプリエンプティブにしています。これは割り込み可能という意味で、サウンド演奏中にコマンドが入ると演奏を中断し、新たに演奏を開始するものです。


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

posted by sakurai on July 29, 2025 #1000

安全要求、特にTSRについて業界の一部に誤解があるようなので解説します。

誤解:「安全要求(SR)は安全目標違反(VSG)を避ける目的のため、安全機構(SM)のみを仕様化する」
正解:「安全要求(SR)は安全目標違反(VSG)を避ける目的のため、意図機能(IF)及び安全機構(SM)の両方を仕様化する」

SMのみが誤りである理由を3点示します。

  1. そもそも論から言えば、ECU全体への要求であるFSR及びそのECUへの配置であるFSCと、それを分解してエレメントにTSRを配置したTSCは上位と下位で一貫していなければなりません。TSRがSMのみであればIFへの要求が抜けるため、上位と下位で一貫しなくなります。
    ※ただし安全要求が初めからSMのみを記述するものである場合、そうは言えなくなる可能性もあります。

  2. 反対にIFにSRが割り当てていないと次のような問題がおこります。定量評価において、例えばSGがASIL-Cだった場合、ECU全体としてASIL-Cで設計する必要があります。ところが安全分析において、SMのみがASIL-Cで設計されていても、肝心のIFの故障率が大きい場合には全体としてASIL-Cを満足できません
    安全分析のみIFも含めてASIL-Cで抑えると言う方法(脱法)を取る場合、要求されていない安全に関わる仕様をIFのエレメントに要請することになり、それがどこから来たものか、明文化されていないことになります。これはISO 26262の精神である要求の明文化を損なうものと言えます。

  3. 当たり前過ぎて規格から文言を探すのは却って難しいのですが、Part 5の6.4.2 e)において、TSRは意図機能を実装するハードウェアエレメントにも適用されるべきことが記されています。TSRはSMだけでなくIFにも割り当てられる必要があると明示されており、システムの信頼性を確保するためにIFの安全対策が必要であることが補強されます。

以上3点から結論として、IFにもTSRを割り当てなければならないと考えます。


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

posted by sakurai on July 28, 2025 #999

ChatGPTを駆使しドラフトの作成が完了したので、AJEに提出しました。

従来はnative checkとしてAJEが修正した点はほぼ全てそのとおりに反映していましたが、今回は修正の全か所について原文と修正文をChatGPTにより評価してもらいました。その結果、元の英文をChatGPTが作成したせいもあるかもしれませんが、原文の方がおおむね良いという評価になりました。

ChatGPTのほうがISO 26262や信頼性用語に詳しく、例えば原文のtop eventをAJEはhighest eventに修正してきましたが、これはFTA用語でtop eventで修正する必要はありません。

7月末までに論文ドラフト及びプレゼン資料ドラフトを作成し、投稿を完了しました。

表999.1 RAMS 2026へのマイルストーン
期限 マイルストーン 状態
2025/4/30 AJEにアブストラクトを修正依頼
2025/4/30 アブストラクト(氏名、所属無し版)投稿締め切り(システム入力)
2025/6/2
2025/5/27
アブストラクト採択結果 採択
2025/7/31
2025/7/26
初稿論文、プレゼン投稿締め切り(氏名、所属無し版)
2025/9/1 査読コメント
2025/9/30 最終論文、プレゼン投稿締め切り(氏名、所属有り版)
IEEEコピーライトフォーム提出
2025/10/10 RAMSへの登録及びホテルの予約


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

Pongと強化学習 (114)

posted by sakurai on July 16, 2025 #998

このプロトコルを用いてpythonのCustomAtariEnvと統合します。


CustomAtariEnv クラスを Device クラスを用いてシリアル通信の詳細を抽象化し、インタフェースをシンプルにするために再設計します。この方法により、CustomAtariEnv クラスはゲーム環境のロジックに集中し、シリアル通信の詳細は Device クラスが担当します。

Device クラスの設計

Device クラスはシリアル通信を担当し、コマンドの送受信を簡単に行えるように設計します。

    import serial
    
    class Device:
        def __init__(self, port):
            self.serial = serial.Serial(port, baudrate=115200, timeout=1)
        
        def send(self, command, payload=None):
            message = bytearray([SOH])
            message.append(ord(command))
            if payload is not None:
                message.extend(payload)
            message.append(EOT)
            self.serial.write(message)
        
        def receive(self):
            response = bytearray()
            while True:
                byte = self.serial.read(1)
                if byte:
                    response.append(byte[0])
                    if byte[0] == EOT:
                        break
            return response
        
        def close(self):
            self.serial.close()

CustomAtariEnv クラスの再設計

CustomAtariEnv クラスは Device クラスを使用して通信を行います。これにより、CustomAtariEnv はシリアル通信の詳細から切り離されます。

    import gym
    from gym import spaces
    
    class CustomAtariEnv(gym.Env):
        def __init__(self, device):
            super(CustomAtariEnv, self).__init__()
            self.device = device
            self.action_space = spaces.Discrete(4)  # 仮に4つのアクション
            self.observation_space = spaces.Box(low=0, high=255, shape=(256, 160, 3), dtype=np.uint8)  # 仮の解像度
    
        def reset(self):
            self.device.send(CMD_RESET)
            return self.device.receive()
    
        def step(self, action):
            action_command = self.get_action_command(action)
            self.device.send(CMD_ACTION, [action_command])
            return self.device.receive()
    
        def get_action_command(self, action):
            # Map the action to the actual command
            if action == 0:
                return ACTION_MOVE_LEFT
            elif action == 1:
                return ACTION_MOVE_RIGHT
            elif action == 2:
                return ACTION_FIRE
            else:
                raise ValueError("Invalid action")
        
        def close(self):
            self.device.close()

使用例

    device = Device('/dev/ttyUSB0')
    env = CustomAtariEnv(device)
    
    initial_state = env.reset()
    action = 1  # 仮に右移動
    new_state = env.step(action)
    
    env.close()

この再設計により、CustomAtariEnv クラスはシリアル通信の詳細から独立し、デバイスとの通信は Device クラスを通じて抽象化されます。これにより、ゲームロジックと通信ロジックが分離され、コードの可読性と保守性が向上します。


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

Pongと強化学習 (113)

posted by sakurai on July 15, 2025 #997

FPGAとdqn_atari.pyとのインタフェースプロトコルをChatGPTと相談した結果、以下のプロトコルにまとまりました。ChatGPTは最初はjsonフォーマットを提案してきましたが、FPGAでデコードする都合上シンプルなフォーマットとしました。


通信プロトコル

PythonからFPGAへのコマンド

  • SOH = 0x01
  • EOT = 0x04
  • ACK = 0x06
  • NAK = 0x15
  • CMD_RESET = 'R' = 0x52
  • CMD_ACTION = 'A' = 0x41
  1. リセットコマンド:

    • 目的: ゲームを初期状態にリセットし、新しいエピソードを開始する。
    • フォーマット: [SOH, CMD_RESET, データ長(0), EOT]
    • データ長はこのコマンドにおいてペイロードがないため0。
      図%%.1
      図997.1 リセットコマンド
  2. ステップコマンド:

    • 目的: 特定のアクションを実行し、その結果としての新しいゲーム状態を取得する。
    • フォーマット: [SOH, CMD_ACTION, データ長(1), アクションコード, EOT]
    • データ長アクションコード1バイト。
      図%%.2
      図997.2 ステップコマンド

FPGAからPythonへの応答

  1. リセット応答:

    • 目的: リセットが完了したことを確認し、新しいゲームフレームを提供する。
    • フォーマット: [SOH, ACK/NAK, データ長, フレームデータ, EOT]
    • コマンドフォーマットが正常ならACK、異常ならNAKを返す。
    • データ長フレームデータのバイト数。
      図%%.3
      図997.3 リセット応答
  2. ステップ応答:

    • 目的: アクションの結果としての新しいゲーム状態、報酬、およびゲームの継続状態を提供する。
    • フォーマット: [SOH, ACK/NAK, データ長, フレームデータ, 報酬, ゲーム終了フラグ, EOT]
    • コマンドフォーマットが正常ならACK、異常ならNAKを返す。
    • データ長は(フレームデータのバイト数 + 報酬1バイト + ゲーム終了フラグ1バイト)のバイト数。
      図%%.4
      図997.4 ステップ応答

このプロトコルでは、ペイロードの長さを明確にすることで、EOTがペイロード内に現れる問題を解消しています。また、データの一貫性と通信の信頼性を高めるためにペイロードの長さを先頭に加えています。


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

Pongと強化学習 (112)

posted by sakurai on July 14, 2025 #996

ゲームの見栄えが良いので、Space Invadersで強化学習を実装しようと思っていましたが、考えを変えてPongで実装することにしました。その理由はpythonにより記述されたatari-dqnの学習の効果があまり現れなかったためです。

Pongのほうが学習の結果がずっと良かったのですがその学習効果を図996.1に示します。

図%%.1
図996.1 エピソード8と5000の学習効果の比較

画面中左のオレンジパドルが単純コンピュータ制御で、右側のグリーンパドルが強化学習により学習したエージェントです。左画面がエピソード8の段階で0対20で一点も取れないのに対し、右画面のエピソード5000の段階では20対14と単純AIに勝ち越しています。約1日程度でこのくらいの学習効果があります。

なお単純コンピュータ制御は、単純にパドルのY座標をボールと一致させているだけです。ただし完全に一致すると絶対に負けることがなく強化学習ができなくなるため、一度に一ドットしか移動できない制約をいれているようです。従ってかなり強いですが、急激な変化には弱い性質があります。

DQN学習中はロス等のパラメータをサーバーに送信しており、以下のような学習効果に関するチャートを取得することが可能です。

図%%.2
図996.2 各種パラメータのチャート

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

6月の検索結果

posted by sakurai on July 10, 2025 #995

弊社コンテンツの6月の検索結果です。

表995.1 上昇率上位のページ(前月との比較)
タイトル クリック数
SPFM, LFM, PMHFの計算法の例 +28
レイテントフォールトのご質問 +16
故障率 +12

表995.2 パフォーマンス上位のページ
タイトル クリック数
機能安全用語集 122
ISO 26262での独立の考え方 61
ASILデコンポジション 60

表995.3 上昇率上位のクエリ
クエリ クリック数
従属故障 +6
MPFDI +4
IEC TR 62380 +3

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


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

Pongと強化学習 (111)

posted by sakurai on July 8, 2025 #994

コードの先頭の部分の説明です。


プログラムの冒頭にあるインポートリストは、Deep Q-Network (DQN) の実装において使用されるさまざまなライブラリやモジュールを取り込むためのものです。それぞれのインポートがプログラム内でどのような役割を担っているか、詳しく解説します。

基本ライブラリのインポート

  1. argparse: コマンドライン引数を処理するためのモジュール。このモジュールを使ってプログラム実行時に外部から設定値を受け取ることができます。
  2. os: オペレーティングシステムとのインタラクションを行うためのモジュール。ファイルパスの操作や、環境変数へのアクセスなどに使用します。
  3. random: 乱数を生成するためのモジュール。DQNでの探索処理やランダムサンプリングに使用されます。
  4. time: 時間に関連する関数を提供するモジュール。プログラムのパフォーマンス測定や待機処理などに使われることがあります。
  5. strtobool(from distutils.util): 文字列形式の真偽値をPythonのブール型に変換する関数。設定ファイルやコマンドライン引数からの入力を扱う際に便利です。

機械学習・強化学習ライブラリのインポート

  1. gymnasium as gym: OpenAI Gym(現在はGymnasiumとして知られています)の環境を扱うためのライブラリ。強化学習アルゴリズムのトレーニングに必要な標準的なインターフェイスを提供します。
  2. numpy as np: 数値計算を効率的に行うためのライブラリ。配列操作や数学的計算に広く用いられます。
  3. torch: PyTorchライブラリで、ディープラーニングモデルの構築とトレーニングに使用されます。
    • torch.nn: ニューラルネットワークの構築に使用されるクラスや関数を含むモジュール。
    • torch.nn.functional as F: 損失関数や活性化関数など、ニューラルネットワークで頻繁に使用される関数を提供します。
    • torch.optim as optim: 最適化アルゴリズムを提供するモジュール。SGDやAdamなど、ニューラルネットワークの訓練に必要です。
  4. stable_baselines3.common.atari_wrappers: Atariゲーム環境のためのラッパー関数群。ゲームの観測や報酬の前処理を行います(例:ClipRewardEnv, EpisodicLifeEnvなど)。
  5. stable_baselines3.common.buffers: 経験再生バッファ(ReplayBuffer)など、強化学習においてデータを効率的に保存・利用するためのデータ構造を提供します。
  6. torch.utils.tensorboard: TensorBoardで訓練プロセスを可視化するためのユーティリティ。訓練中の損失や精度などのメトリクスをログに記録します。

このインポートリストは、DQNプログラムが多様な機能とモジュールを必要としていることを示しており、強化学習タスクを効果的に実行するための準備が整っています。


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