🧂

リングバッファの実装例 Sysmac StudioとSTによる

2024/11/29に公開

はじめに

本記事は、主にPLC(Programmable Logic Controller)向けのソフトウェア開発に従事、または関心のある方で、Structured Text(ST)による開発に興味がある方向けです。

リングバッファの実装については、インターネット上に十分な情報があるため、ここでは少し変則的な見方を用います。任意長配列と互いに無関係に走査する2つの位置指示子を、要素数という制約によってリングバッファとして振る舞わせるという見方で組み立てます。リングバッファは、位置指示子のみの実装もありますが、分かりやすさとリソース共有のしやすさで要素数を用いた実装の方が有利です。

説明

リングバッファは、データ入力位置とデータ出力位置を指す2つの位置指示子と任意長配列のバッファから成ります。データ入力を行えば、データ入力位置指示子(Head)を増分し、データ出力を行えば、データ出力位置指示子(Tail)を増分します。どちらの位置指示子もバッファの配列長(Capacity)に到達したら、ゼロに戻ります。位置指示子の制約は、位置指示子を動かすとき、どちらの位置指示子であるかに関係無く、移動によってもう一つの位置指示子を追い越さないことです。リングバッファが保持する要素数は、データ出力位置指示子から増分方向にデータ入力位置指示子までの距離です。

リングバッファの素朴なイメージは、カーレースです。追い越すだけの幅が無い1つのコース上を2台のレースカーがレースをしています。もし、コースが2つあればレースカーは、互いに無関係に自由にコースを回り続けることになります。これが、互いに無関係に走査する二つの位置指示子です。記述すると次のようになります。

データ入力位置指示子

Buffer[Head] := Value;
Head := (Head + 1) MOD Capacity;

データ出力位置指示子

Value := Buffer[Tail];
Tail := (Tail + 1) MOD Capacity;

それぞれ、副作用として値の読み書きを行います。バッファとして有益な機能は提供しませんが、配列上を一方向に延々と巡る動作は行います。ここに明示的な要素数(Size)を導入し、次のような制約を追加します。

制約
0 <= Size <= Capacity

何をしているのか分からなくなってきたかもしれません。任意長配列とはいっても無限長ではないので、格納できる要素数には限りがあるのですから当然です。当然なそれもソフトウェアにおいては記述しない限り当然ではないのですから、記述することになります。

この制約は常に満たす必要があります。素朴にコードを記述するのであれば、処理前に制約を満たしていることを確認し、満たしていなければ処理を行わず、処理後にも制約を満たしていることを確認し、満たしていなければその処理結果を破棄するということになります。実装する場合はできる限り簡単で無駄のない実装にします。

データ入力位置指示子

IF Capacity <= Size THEN RETURN; END_IF;
Buffer[Head] := Value;
Head := (Head + 1) MOD Capacity;
Size := Size + 1;

データ出力位置指示子

IF Size < 1 THEN RETURN; END_IF;
Value := Buffer[Tail];
Tail := (Tail + 1) MOD Capacity;
Size := Size - 1;

これだけでリングバッファとして振る舞うようになります。単純な動作を行う2つの位置指示子に、要素数と単純な制約を与えるだけで、リングバッファという有用な振る舞いが現れたことになります。複雑なシミュレーションや、創発的な何かを期待するエージェントシステムでも無いので感動が無いのは仕方がありません。答えを知っていたのですから。

リングバッファは、何らかの最適化を施したものでなければ丸呑みできる単純な構造です。その構造を利用することが目的であれば、それで十分です。今回の見方は、リングバッファを構成する要素を分解して振る舞いを観察し、要素を単純化した後、リングバッファとして振る舞わせるのに必要な、できる限り単純な要素は何かという方針で組み立てたものです。

これに対して適切なテストを実施して妥当であれば、問題なく使用できると考えてよいのですが、そもそもリングバッファ自体がよく分からないと困惑している場合、以下を参照してみてください。Sysmac Studioを使用して私よりも具体的で丁寧に解説されています。

https://www.osdes.com/oms/sample/ringbuf/ringbuffer.html

私はリングバッファ自体の解説は半ば放棄していますが、以下に実装例を置いておきます。毎度ですが、Sysmac Studioを使用します

https://github.com/kmu2030/RingBufferExample

互いに無関係な位置指示子から始めてバッファ操作のFUN化、構造体の導入による構造の隠蔽まで順に行っています。コードを記述、組織化し、再利用可能なモジュールにする過程もSysmac Studio含めPLC向けソフトウェアでは一般に不足しているトピックなので、どこかで述べる必要があります。

まとめ

リングバッファの解説としては、ズレています。ST向けとしているので、HowではなくWhatに注意を向けるということの結果です。STによるアルゴリズム実装よりもコードの組織化やモジュール化について問われることの方が多いため、どうかとは思いました。しかし、リングバッファは、制約が強い環境でのデータ処理には必須なので、名称だけでも出しておこうと取り上げました。ここからは、実機搭載可能なアプリケーションの構築も交えながら進めていきます。

Discussion