なが月・32日目

32日目

午前

Simulink講習会に参加してきた。位置yを時間tで微分したy'は速度になり、y''は加速度になる。これはSimulinkブロック線図上では

―y''→[積分器]―y'→[積分器]―y→

と表現される。そして自由落下の場合加速度はg = -9.81で与えられ、初期位置 x_{0}を100として最後の積分器に初期値として与え、位置をScopeで観測するのは以下のようになる。

[定数 = -9.81]―y''→[積分器]―y'→[積分器]―y→[スコープ(観測器)]
                   ↑x0
                 [定数 = 100]

定数だけでなく変数も使うことができ、これはMatlabワークスペースと共有されているのでMatlabコマンドウィンドウやスクリプトから設定する。逆に出力ログをSimulinkで保存する設定にすると、Matlab側のワークスペースでログを参照して表示させることができる。

1自由度振動系(ばねとダンパーで壁につながれた台車を引っ張る)の実装では、やはり位置x―速度x'―加速度x''の積分関係を先に構成したうえで、ある時点での入力であるx''をその前の時点での位置xから求めるため式を整理して、 F=mx''+cx'+kx x''=\frac{1}{m}(F-cx'-kx)として、前回のループでのx, x'を再利用してx''とすることになる。フックの法則で反力=ばね定数k×伸びxが外力Fに逆らっているというわけで、中学物理を思い出して懐かしくなった。ダンパーは減衰力を発生させ、減衰力は速度x'と減衰係数cに比例するのでこれはcx'と表されるということだ。

力の入力をステップ信号として与えてやると、これはある瞬間に台車を紐でぐいと引っ張り、その時の力を維持することに等しい。すると力が加わっていないときの位置から勢いよく動いていき、やがて戻ろうとし、その振動がダンパーで減衰してやがて初期位置よりも遠い場所で静止状態に近づいていくことがよく分かった。

午後

引き続きSimulink講習会である。サンプルはドローンに内蔵されたカメラの画素を取得し、青色が優勢な画素が一定数以上あった時に移動を停止するというモデルであることが分かった。カメラからの入力がRGBではなくYUVであり、これは輝度, 青色差、赤色差でデータを保持することで色情報を削減できるようにする仕組みだということを知った。輝度は(R, G, B)=(y, y, y)で表されるグレースケールの色で、実際の色は(y+v, y, y+u)であるということだろう。人間には青、緑、黄に相当する波長の光をそれぞれピークとしたスペクトルを有する3種類の錐体があり、それぞれがどれほど刺激を受けたかによって色を認識するため、どの錐体の反応ピークからも外れていて知覚されにくい赤・濃い青の微妙な違いを省略してu, vを4bit(16階調)などに削減することで、情報量を減らす工夫がされるそうだ。

AEチュートリアルは昨日のものから始めた。シェイプレイヤーを作り、ペンツールで字をなぞって覆い隠すようにパスを作成し、「パスをトリム」を追加し、終了点を0%→100%になるようにキーフレームを打つ。文字ロゴレイヤーのトラックマットをシェイプレイヤーに設定すれば、パスの動き通りダイナミックに文字が現れるようになる。

https://helpx.adobe.com/after-effects/how-to/handwritten-title-effects.htmlではさらにペンツールでベジエ曲線を描き、エフェクトの「線(Stroke)」を追加する。ブラシサイズを太くして元の線にほぼ一致するようにしたうえでペイントスタイルを透明に設定する。そしてエフェクトの終了を変化させキーフレームを打つ。これで先のものとは異なり繊細にカーブして文字が描かれるようになる。まさに描かれている先端部分を別の色にしたければ、二つのレイヤーを複製してテキストレイヤーの色を変え、エフェクトの開始点も同様に変化させてキーフレームを打つことで色の変化する部分が一定の範囲に保たれる。字をトレースする段階ではマスク用レイヤーの不透明度を下げるが、最終的にマスクとして扱うときはくっきりとマスクが扱われるように不透明度を100%に戻すことを忘れてはならない。

明日はhttps://helpx.adobe.com/after-effects/how-to/animated-infographic.htmlhttps://helpx.adobe.com/after-effects/how-to/create-data-driven-animations.htmlに取り組みたい。JSONによるデータを利用した自動アニメーションはとても有用そうだ。AfterEffectsのチュートリアルはこの休み期間で終わりにし、Adobe XDチュートリアルに移る。Unityの直感的ではないGUI配置を通じてレイアウトを考えるより、XDでレイアウトを確定させてからUnityに反映するほうがよいだろうと思ったのが理由だ。

ABC139Eの解きなおし。参考にするのはおなじみikatakosさんのPython3答案である。この方は余分なモジュールや自作便利関数を含んだテンプレートを答案に使われていないだけでなく、簡明な処理の書き方をされるので尊敬している。

その答案を見るに解説で言及されていた有向グラフは概念的な話で、グラフを実装する必要はないようだ。

理解のステップとして処理を追いながら変数名を意味のあるものに置き換えていく。その結果が以下である(daysPassedWhenPlayedMostRecentMatchは長すぎるが、省略しようがない)。

各々の選手の最終試合日から遡っていく。(遡りの)当初は全選手が試合可能である。各選手は(正しい時間軸で)最後に試合をしたいと思っている選手の方を見て、

A) 相手が自分との試合を待っているならば試合を行い、(遡りにおける)その開催日は(正しい時間軸で)最後に試合した日を1日目とした時、max(自分の最終試合日+1, 相手の最終試合日+1)となる。両選手は試合を消化したので(遡りにおける)次の日に試合参加可能な選手として再登録される。

B) 相手が別の選手との試合を待っているなら試合はできない。自分も相手との対戦待ち状態に入る。

もし成立不能な組み合わせであれば、Bになった後も相手との対戦が成らず、もはや試合が可能な選手として次の相手を選ぶことは永久にできなくなる。その結果ループ終了時においても試合したい相手がまだ残っていることになり、-1が出力される。

成立する場合は、Bになった後相手の選手が何らかの形で他の選手との待望のマッチを実現し、相手の選手のほうからこちらに対戦申し込みが来る。そして試合を行い試合可能状態に復帰し、対戦相手を消化するまでループが回り続けるということだ。

これは時間遡行によってひどく難解になってしまったが、popが末尾からしかとれない仕様によるものだろう。正しい時間軸でも同じことは言えるはずである。

振り返ってみれば発想の転換があるわけでもない素直な実装であった。