CAN受信処理遅延の比較¶
文書バージョン:1.2.0
対象GitHubバージョン:v1.2.0
文書ID:guide-can-rx-processing-delay
文書状態:公開済み。mainへのpush時に検証後、GitHub Pagesを自動更新
更新履歴¶
| 文書バージョン | 更新日 | 更新内容 |
|---|---|---|
1.2.0 |
2026-10-22 |
v1.2.0の対象タグ・文書版を確定。過去の測定基準と公開済み履歴を保持 |
1.1.1 |
2026-10-11 |
公開文書整合性監査の修正を反映し、文書PATCHを一つ上げ、対象タグをv1.1.4へ統一 |
1.1.0 |
2026-10-06 |
初版:受信処理遅延だけを変える3条件、送信・観測・受信完了の実測、Viewer実画面、終了時未完了とモデルの制約を説明 |
目的:送信成功と受信完了を分けて読む¶
「フレームの送信は終わったのに、cの受信完了が遅い」という場面を再現します。同じ3要求を送る条件で、cのrxProcessingDelayだけを0、200、900µsへ変えます。Busの送信時刻、cの観測時刻、cの受信完了時刻を比べ、どこで時間を使っているかを確かめます。
この実習で変えるのは受信後の処理時間です。受信フィルタは全受入のままです。CAN Controllerの受信バッファ容量や満杯による受信破棄は、このモデルにはありません。遅い受信処理を設定しても、その機能を再現したことにはなりません。
初めてのCAN実行の準備・出力ファイルの説明と、Viewerで結果を読むの時刻移動を先に確認すると進めやすくなります。コードの基準はv1.1.3、今回の実行・ビルド基準はmain c152840df77e5ce29c678ca8165c7c00935756fbです。
構成と責務¶
NED・INI・JSONの3種類を使います。配線と生成入力を固定し、INIにあるcの受信処理時間だけを変えます。
| 入力・部品 | この実習で担当すること | 比較中の扱い |
|---|---|---|
models/demo/Main.ned |
a・b・cのControllerを1つのBusへ接続する | 同じ配線、配線遅延0 |
minimal.json |
a・b・cに1要求ずつ、時刻0で生成する | 同じID・データ・生成回数 |
rx-delay*.ini |
500kbps、実行1ms、cの受信処理時間を指定する | Main.c.rxProcessingDelayだけを変更 |
| Bus | 調停、送信、EOF、Bus解放を決める | 受信側の処理が終わるまでBusを占有しない |
| 受信Controller | フレームを観測し、フィルタ適合後に受信完了を記録する | cだけ処理時間を変え、a・bは0 |
送信要求はa:0、b:0、c:0です。例えばa:0はaが送る1フレームを表し、それに対するbとcの受信は別々の行に記録されます。送信元aへの自己受信はありません。
接続と受信までの流れ¶
- aの要求がBusの送信権を得て、a.txからBusへ送信します。
- EOFでaの送信成功が確定します。Busから送信元以外のb.rxとc.rxへ受信通知が届きます。
- bとcは通知を観測し、各自の受信フィルタを判定します。この実習は両方とも全受入です。
- 各Controllerは観測時刻に
rxProcessingDelayを加えた時刻で受信完了を記録します。 - BusはEOFから3bit間隔を終えると次の送信を始められます。cの受信処理完了を待ちません。
今回の配線遅延は0なので、t_observed = t_EOFです。フィルタに適合した受信については、t_received = t_observed + rxProcessingDelayになります。配線遅延がある構成では観測時刻も遅れるため、EOFと観測を同じものと考えないでください。
RX処理は受信ごとに独立しています。先の受信処理中でも、次の受信や自身の送信と重ねられます。1つのCPUが全受信を順番に処理する待ち行列のモデルではありません。
最小実行手順¶
リポジトリのルートで実行します。実習入力ZIPにも、同じ相対配置で3つのINI、共通JSON、NEDを収録しています。ZIPだけでは実行プログラムは入りません。導入・ビルド手順は入門を参照してください。
cargo build --locked -p dir-simulator
for delay in 0 200 900; do
./target/debug/dir-simulator validate \
--config "examples/guide/can/rx-delay${delay}.ini"
./target/debug/dir-simulator run \
--config "examples/guide/can/rx-delay${delay}.ini" \
--output "results-guide-rx${delay}"
./target/debug/dir-simulator view \
--input "results-guide-rx${delay}/results.json" \
--output "guide-rx${delay}-viewer.html"
done
生成した3つのViewer HTMLをブラウザで開きます。繰り返すときは出力ディレクトリとHTMLを別名にしてください。既存出力の保護で拒否されることを、シミュレーション失敗と取り違えないようにします。掲載コマンドはBash/WSLで検証しています。
1変数だけを変える設定¶
3つのINIの差は次の1行だけです。cのTXキュー容量、Busの速度、workload、実行終了時刻は同じです。共通NEDのrxFilter = "*"も変えません。
# rx-delay200.iniで変えている行
Main.c.rxProcessingDelay = 200us
| INI | cの受信処理時間 | その条件で確かめること |
|---|---|---|
rx-delay0.ini |
0µs | 観測と受信完了が一致する基準 |
rx-delay200.ini |
200µs | 観測は同じで、受信完了だけが遅れる |
rx-delay900.ini |
900µs | 観測済みでも1ms終了までに受信完了しない |
実測:Busの送信は3条件とも同じ¶
| 要求 | SOF(µs) | EOF(µs) | Bus解放(µs) |
|---|---|---|---|
| a:0 | 0 | 238 | 244 |
| b:0 | 244 | 400 | 406 |
| c:0 | 406 | 530 | 536 |
3条件とも送信成功3件、送信破棄0件です。cのRX処理時間を増やしても、CAN IDやフレーム長、送信順、Bus解放時刻は変わりません。c自身の要求も406µsで送信を開始します。
実測:cの受信完了だけが変わる¶
以下はc宛ての受信だけを比べた表です。時刻値はすべてµs、右の3列は各処理時間条件での受信完了時刻です。「—」は1ms終了までに完了していないことを示します。
| 要求 | 観測 | 0µs | 200µs | 900µs |
|---|---|---|---|---|
| a:0 | 238 | 238 | 438 | — |
| b:0 | 400 | 400 | 600 | — |
bがaを受ける238µs、aがbを受ける400µs、aとbがcを受ける530µsは3条件とも変わりません。全受信6行のうち、c宛ての2行だけが変わります。
200µs条件では、cはaの受信を238〜438µs、bの受信を400〜600µsに処理します。400〜438µsは2つのRX処理が重なり、cの送信も406µsから始まります。この重なりは、独立した固定遅延のモデルが実装している動作です。
| 実行1ms時点の記録 | 0µs | 200µs | 900µs |
|---|---|---|---|
| 送信成功 | 3 | 3 | 3 |
| 受信完了(全受信者) | 6 | 6 | 4 |
| 受信未完了(pending) | 0 | 0 | 2 |
| フィルタ拒否 | 0 | 0 | 0 |
| termination | events_exhausted | events_exhausted | time_limit |
0/200µs条件は予定したイベントが尽き、900µs条件は処理完了イベントを残して実行時間上限に達します。3条件ともend_ps = 1000000000、partial = falseです。このpartial=falseだけから「すべての受信が完了した」と判断できません。受信行の状態と完了時刻を確認します。
実Viewerで観測と完了を見分ける¶
200µs条件のViewerで単位をµsにし、時刻400へ移動してa:0を選択します。送信は成功済みですが、cの受信はまだ「受信待機」です。cの観測は238µsで、受信完了は438µsです。

撮影条件:200µs条件、選択時刻400µs、要求a:0、幅1,440px。受信者詳細の時刻欄はps整数なので、238000000 ps = 238µs、438000000 ps = 438µsです。詳細の時刻欄は実行全体で保存された時刻、状態バッジは選択した400µs時点の状態です。先の438µsが表示されていても、400µsで完了済みという意味ではありません。
438µsへ進めるとa:0 → cが完了し、600µsではb:0 → cも完了します。a:0のEOF238µsやBus解放244µsを、cの受信完了438µsへ置き換えて読まないようにします。
次に900µs条件のViewerで1,000µsへ移動し、同じa:0を選択します。送信成功3件・受信完了4件ですが、cの観測時刻はあり、受信完了は「未確定」です。

撮影条件:900µs条件、選択時刻1,000µs、要求a:0、幅1,440px。results.jsonでもc宛て2行はstatus = "pending"、received_ps = nullです。
終了時のpendingを欠落や破棄と混同しない¶
900µsを足した処理完了予定はa:0 → cが1,138µs、b:0 → cが1,300µsです。この2つは式から求めた予定で、今回の結果に保存された受信完了の実績ではありません。実行区間は[0, 1ms)なので、上限以後のイベントは実行されません。Viewerの時刻移動だけで、実行していない受信を完了させることもできません。
これは「受信を観測したが処理が終わる前に観測期間が終了した」結果です。フィルタ拒否、TXキュー満杯、RXバッファ破棄の証拠ではありません。出力の送信成功と、受信行の観測・完了・状態を別々に読みます。
この実習で分かることと制約¶
rxProcessingDelayはフィルタに適合した観測から受信完了までの固定遅延です。フレームのwire転送時間や送信側txProcessingDelayとは別です。- 通常CAN Controllerの
queueCapacityはTX待機容量です。RXバッファ容量、RX満杯の破棄、1つの受信CPUの直列処理、処理負荷による遅延増加はこのモデルにありません。 - GatewayのRX保持容量・routing処理・TX容量待機は別機能です。この例はGatewayを使いません。
- 理想ACKモデルです。受信アプリケーションの処理完了をACKの条件にしません。実CAN機器の割込み・DMA・ドライバ・CPU競合を測った結果ではありません。
- 3要求、固定配線遅延0、全受入フィルタだけの比較です。実機の受信欠落率・バッファ設計・性能受入を保証する実験ではありません。
受信先の選別を調べるフィルタ比較とは目的が異なります。このページは選別条件を固定し、時刻の違いだけを観測します。調停実験では送信権の順序を、設定・用語・FAQではobserved / receivedと時刻単位を復習できます。ガイド内検索では短い語「受信」「遅延」でこのページを探せます。