制御システム理論では、このタイプのシステムはフィードバックを持つ制御ループです。システムの入力は出力に依存するため、従来の分析には抵抗します。出力は連続関数である可能性があります。
Observables (本質的に値の離散ストリーム) で同じことを行うことができます。つまり、制御システムを宣言的に表現できます。ただし、C# のセマンティクスにより、実装はあまり洗練されていません。(F# には再帰バインディングのオプションがあります)。
まず、フィードバック ループを記述するためのクロージャを定義する必要があります。
public delegate IObservable<T> Feedback<T>(IObservable<T> feedback, out IObservable<T> output);
public static IObservable<T> FeedbackSystem<T>(Feedback<T> closure)
{
IObservable<T> source = Observable.Empty<T>(), output;
source = closure(Observable.Defer(() => source), out output);
return output;
}
上記を使用して、ランダムエラーが速度に導入された場合でも、100 まで加速し、それ以下の速度を維持する速度ガバナーの実装例を次に示します。
var system =
FeedbackSystem((IObservable<double> acceleration, out IObservable<double> velocity) =>
{
//Time axis: moves forward every 0.1s
double t = 0.1; var timeaxis = Observable.Interval(TimeSpan.FromSeconds(t));
velocity = acceleration.Sample(timeaxis) //move in time
.Scan((u, a) => u + a * t) //u' = u + at
.Select(u => u + new Random().Next(10)) //some variations in speed
.Publish().RefCount(); //avoid recalculation
//negative feedback
var feedback = velocity.Select(u => 0.5 * (100 - u));
return feedback.Select(a => Math.Min(a, 15.0)) //new limited acceleration
.StartWith(0); //initial value
});
system.Subscribe(Console.WriteLine);
ステートマシンのケースは、同じ方法で入力を出力に依存させることで可能になります。