JavaScriptオンオフコントローラーシミュレーターの作成

自動制御の理論の本質は、特定のオブジェクトの特定のパラメータを特定の状態(たとえば、炉内の温度やタンク内の水位)に維持するシステムの構築を意味します。プロセスをよりよく理解するために、特定の制御モデル、たとえばタンク内の水位を制御することをすぐに検討すると便利です。ちなみに、TAUの教科書や記事では、このプロセスは歴史への言及として頻繁に言及されています。なぜなら、遠い1763年にロシアの発明者I.I.彼の蒸気エンジン用の水位制御システムを開発しました。ちなみに、この写真のように本質的に2ポジションのレギュレーターである一種の古典的なレギュレーター(水はありません-バルブを開き、水がバルブを閉じます)。







英語の文献のオンオフでは、オープン(オン)とクローズ(オフ)の2つの位置があるため、2つの位置になります。また、3つ以上の位置調整器があります。つまり、給水バルブが主な位置に対して開いているか閉じているか、「わずかに開いている」位置が追加されます。トイレの水を抜いた後、フロートが下がり、バルブが完全に開き、水は全圧でタンクに入りますが、設定レベルに近づくとフロートが上がり、バルブが閉じて水の流れが減少します。そして、現在の水位(英語のPV-プロセス値-現在の値)がセット(英語のSP-セットポイント-セットポイント)に上昇するとすぐに)、バルブが閉じ、水位の上昇が止まります。説明したケースでは、コントローラーは比例コントローラーにさらに似ています。制御アクションは、不一致(エラー)、つまり設定レベルと現在のレベルの差が減少するにつれて減少します。



下のパイプを少し開いて水を抜くことで、バルブが全開で水位が下がらない(つまり、水の流入が水源と等しくなる)状態になり、システムが平衡状態になります。しかし、問題は、この状態が非常に不安定であるということです-外乱があればこの平衡を破ることができます-たとえば、タンクから水をすくい上げることができ、その後、すべての水がタンクから流出する可能性があります(圧力変化のため)、または詰め替えパイプが詰まって流量が減少したり、フロートが壊れて水が溢れたりします。これは、制御システムの構築の複雑さです。実際のシステムは非常に複雑であり、考慮する必要のある多くの特性があります。システムの慣性などの特性があります。加熱プレートをオフにすると、かなり長い間高温のままになります。そのため、温度を制御するために、より複雑なレギュレーターが使用されます。PID-比例積分微分。各コンポーネントには独自の特性があります。これらはすべて、さまざまな条件下で異なる動作をしますが、一緒に使用すると、かなり明確な規制を実現できます。これらのシステムはすべて式に従って計算されますが、この場合、PIDコントローラーの係数が変化したときにシステムがどのように動作するかを理解することが重要です。比例リンクが増えると、初期の影響が大きくなり、システムは必要なパラメーターをすばやく達成できるようになります。しかし、それをやりすぎると、オーバーシュートが発生する可能性があり、システムの低速よりもさらに悪化する可能性があります。



TAUの存在中に、多くのプロセスの数学的記述が見つかりました。これで、特定の状況下でシステムがどのように動作するかを予測できます。システムのパラメーターを設定し、レギュレーターのパラメーターを設定し、それがどうなるかを大まかに確認できるシミュレーションプログラムはたくさんあります。インターネットを歩いていると、エンジニア向けのExcelサイトに出くわしました。レギュレーターのシミュレーターがいくつかあり、制御要素を変更する際のプロセスの変化を確認できます。もちろん、繰り返すのが最も簡単なのはON-OFFコントロールでした。つまり、ロシア語では2ポジションのレギュレーターです。動作原理を思い出させてください。現在のプロセス値(プロセス値= PV)が温度である場合、たとえば、設定値(SP)を下回る場合、レギュレーターがオン(OP)になり、加熱要素が全容量で開始されます。温度が設定値に達するとすぐに、レギュレーターは加熱要素への電圧供給をオフにします。



JavaScriptシミュレーターの作成



チャートを作成するには、ZingChartライブラリを使用します。これは非常にシンプルで使いやすいことがわかりました。ドキュメントには、何でも作成できる例がたくさんあります。プロットの原理は非常に単純です-グラフに自動的に順番に配置される値の配列があるため、連続プロセスグラフが数百のポイントから表示されます。ちなみに、Excelのオリジナルでは、すべてが同じ方法で行われます-300の値が生成され、グラフが作成されます。



実際、最も難しいのは値の生成です。つまり、制御アクションに正しく反応するプロセスを正しく説明することの難しさ-加熱要素をオンにする-温度が上昇する、オフにする-低下することに加えて、システムの慣性をここに置く必要がありますさらに、加熱環境が異なる可能性があり、一部のメディアはより速く加熱および冷却し、一部はその逆になります。レベルを調整すると、上から同じ流れで、底部の面積が小さいタンクでレベルが高くなります。このすべては、プロセスが伝送(ゲイン)にも依存するという事実につながります。オリジナルでは、遅延パラメータもプロセスに導入されました(システムが制御信号にすぐに応答しないように)が、私はそれを放棄することにしました-2つで十分です。しかし、彼は設定に変更を加えました、実際には、設定値が0から100に変化する可能性があることが判明しましたが、100を超えると、プロセスの動作が異なり始めます。その理由は、プロセス式が普遍的であり、特定のケースを記述していないためです。一般的に、始めましょう:



パラメータを入力するための5つのフィールドを作成し、これらすべてをテーブルに配置します。これをcssで上に素敵な色でペイントし、中央に配置します。



<table align="center" oninput="setvalues ();">
	<tr>
	<td>
Process parameters <br>
Gain: <input id="gain" type="number" value ="1" ><br>
Time Constant: <input id="time" type="number" value ="100" ><br>
	</td>
	<td>
Control parameters <br>
SetPoint(0-100): <input id="sp" type="number" value ="50"><br>
Hysteresis: <input id="hyst" type="number" value ="1">%<br>
	</td>
	<td>
Plot parameters <br>	
Points: <input id="points" type="number" value ="200"><br>
	</td>
	</tr>
</table>


ご覧のとおり、テーブル内のフィールドの値が変更されるたびに、setvalues()関数が呼び出されます。その中で、各フィールドからのデータを特別な変数に読み込みます。



	let gain = document.getElementById('gain').value;
	let time = document.getElementById('time').value;
	let sp = document.getElementById('sp').value;
	let points = document.getElementById('points').value;
	let hyst = document.getElementById('hyst').value;


すでに述べたように、グラフを作成するには、グラフの作成の基礎となるデータを含む配列が必要なので、一連の配列を作成します。



let pv = []; //    
let pv100 = []; //   *100
let op = []; //   1 , 0 
let pvp = 0; //  
let low = sp-sp*hyst/100;//  
let high = +sp+(sp*hyst/100); //   
let st=true; //  


ヒステリシスについて少し説明させてください。状況は次のとおりです。温度が設定値に達すると、加熱要素がオフになり、すぐに(実際には、慣性があるため、すぐにではなく)冷却プロセスが開始されます。そして、1度または数分の1度まで冷却されたため、システムは、タスクの範囲をすでに超えていることを認識し、加熱要素を再度オンにする必要があります。このモードでは、加熱要素は非常に頻繁にオン/オフになりますが、おそらく1分間に数回-このようなモードの機器ではあまり良くないため、このような変動を排除するために、いわゆるヒステリシスが導入されます-デッドバンド-デッドバンド-たとえば1度高く、設定値を下回ると反応しなくなり、切り替え回数を大幅に減らすことができます。したがって、変数lowは設定値の下限であり、変数highは上限です。st変数は、トップレベルへの到達を追跡し、プロセスを最下位に落とすことができます。プロセス全体のロジックはループ内にあります。



	for (var i=0;i<points;i++) {
		if (pvp<=(low/100)) {
			st=true;
			op[i]=1;
			}//
		else if (pvp<=(high/100)&& st) op[i] = 1;
		else { st=false; op[i]=0;}
		
		let a = Math.pow(2.71828182845904, -1/time);
		let b = gain*(1 -a);
		pv[i] = op[i]*b+pvp*a;
		pv100[i] = pv[i]*100;
		pvp = pv[i];
	}


その結果、指定された数のポイントを持つ配列を取得し、それをグラフ作成スクリプトに送信します。



scaleX: {
 	zooming: true
  },
      series: [
		{ values: op , text: 'OP' },
        { values: pv100 , text: 'PV'}
      ]
    };


スポイラーの下の完全なコード
<!DOCTYPE html>
<html>
 
<head>
  <meta charset="utf-8">
  <title></title>
 
  <script src="https://cdn.zingchart.com/zingchart.min.js"></script>
  <style>
    html,
    body,
    #myChart {
      width: 100%;
      height: 100%;
    }
	input {
	width: 25%;
	text-align:center;
	}
	td {
	
	background-color: peachpuff;
	text-align: center;
	}	
  </style>
</head>
<body>
<table align="center" oninput="setvalues ();">
	<tr>
	<td>
Process parameters <br>
Gain: <input id="gain" type="number" value ="1" ><br>
Time Constant: <input id="time" type="number" value ="100" ><br>
	</td>
	<td>
Control parameters <br>
SetPoint(0-100): <input id="sp" type="number" value ="50"><br>
Hysteresis: <input id="hyst" type="number" value ="2">%<br>
	</td>
	<td>
Plot parameters <br>	
Points: <input id="points" type="number" value ="250"><br>
Animation: <input type="checkbox" id="animation">
	</td>
	</tr>
</table>

<script>

setTimeout('setvalues ()', 0);

function setvalues (){

	let gain = document.getElementById('gain').value;
	let time = document.getElementById('time').value;
	let sp = document.getElementById('sp').value;
	let points = document.getElementById('points').value;
	let hyst = document.getElementById('hyst').value;
	let anim = document.getElementById('animation').checked ? +1 : 0;
	let pv = []; //    
	let pv100 = []; //   *100
	let op = []; //   1 , 0 
	let pvp = 0; //  
	let low = sp-sp*hyst/100; //  
	let high = +sp+(sp*hyst/100); //  
	let st=true; //  
	for (var i=0;i<points;i++) {
		if (pvp<=(low/100)) {
			st=true;
			op[i]=1;
			}
		else if (pvp<=(high/100)&& st) op[i] = 1;
		else { st=false; op[i]=0;}
		
		let a = Math.pow(2.71828182845904, -1/time);
		let b = gain*(1 -a);
		pv[i] = op[i]*b+pvp*a;
		pv100[i] = pv[i]*100;
		pvp = pv[i];
	}
	
	ZC.LICENSE = ["569d52cefae586f634c54f86dc99e6a9", "b55b025e438fa8a98e32482b5f768ff5"];
    var myConfig = {
    type: "line",
    "plot": {
		"animation": {
          "effect": anim,
          "sequence": 2,
          "speed": 200,
        }
		},
	legend: {
    layout: "1x2", //row x column
    x: "20%",
    y: "5%",
	},
 	crosshairX:{
 	  plotLabel:{
 	    text: "%v"
 	  }
 	},
      "scale-y": {
    item: {
      fontColor: "#7CA82B"
    },
    markers: [
	 {
        type: "area",
        range: [low, high],
        backgroundColor: "#d89108",
        alpha: 0.7
      },
	{
        type: "line",
        range: [sp],
        lineColor: "#7CA82B",
        lineWidth: 2,
		  label: { //define label within marker
          text: "SP = "+sp,
          backgroundColor: "white",
          alpha: 0.7,
          textAlpha: 1,
          offsetX: 60,
          offsetY: -5
        }
      }]
	},	
	scaleX: {
		zooming: true
	},
	  'scale-y-2': {
	  values: "0:1"
	},
      series: [
		{ scales: "scale-x,scale-y-2", values: op , 'legend-text': 'OP' },
        { values: pv100 , text: 'PV'}
      ]
    };
 
    zingchart.render({
      id: 'myChart',
      data: myConfig,
      height: "90%",
      width: "100%"
    });
}


</script>
  <div id='myChart'></div>
</body> 
</html>




さて、シミュレーターの準備ができたので、それがどのように機能するかをチェックする時が来ました。ここで同じコードをテストできますが、githubでテストでき ます:オンオフ制御シミュレーター



標準設定:リンク1の増幅、時定数100秒、ヒステリシス2%







ここで、92などのより大きな設定を設定すると、設定は50ですが、突然プロセスが大幅に遅くなります。同じ71秒で増加しますが、その後、曲線は指数関数的にゆっくりとタスクに近づき始め、わずか278秒で設定値に到達します。そのため、プロット範囲を300ポイントに拡大する必要がありました。







この例は非常にわかりやすく、状況を温度のあるモデルに転送します。ヒーターの電力が十分ではないと結論付けることができます。ヒーターには100%の負荷がかかっていますが、温度は一定の時間後に上昇を停止します。いくつかの解決策があります:同じものの2番目の加熱要素を置くか、それに2倍の電圧を印加する(ただし、これは加熱要素を損傷する可能性があります)、2倍の電力のヒーターを置く、または加熱に関してはより多くの熱伝導性液体をシステムに注ぎます液体。温度を95〜100度の範囲に維持する必要がある場合は、レギュレーターを配置する必要がないことは非常に興味深いことです-そのような低電力ヒーターを配置し、それを最大限にオンにします-300秒(条件付き300秒)後に目的の100度を得ることができます。このようなシステムの問題は、冬にマイナス40でウィンドウを開くと、温度がすぐに大幅に低下し、このようなシステムのパフォーマンスが非常に低くなることです。



ゲインセクションを2倍に増やしましょう。これは、同じタイプの2番目の加熱要素を取り付けるか、別のパイプを追加してタンクを補充するようなものです。







グラフも非常にわかりやすいことがわかりました。51度に達した温度は実際には2倍速くなりましたが、92度に達すると4倍速くなりました。そのようなシミュレーターが実際のプロセスにどれだけ近いかはわかりませんが、そこに指定された依存関係は指数関数的であるため、これはシステムの完全に予想される動作ですが、2番目のパイプを追加して充填率を4倍にするという観点から説明することさえ想像できません。線形関数の応答は、係数の増加に対してより予測可能ですが、実際のシステムが線形になることはめったにありません。



All Articles