2015年8月16日日曜日

数式お絵描き

前回のブログでこうもりの描き方がすっかり分ったかといえば, まだすっきりしない部分がある. 下の線を描くプログラムの11から15行目が思いのほか複雑なのだ.

この式の構造はこうなっている. 11行目の(1/2)*に掛けられる因子は4つの項で出来ている.
3*Sqrt[1-(x/7)^2]            (楕円)
+Sqrt[1-(Abs[Abs[x]-2]-1)^2] (4つの小楕円)
+Abs[x/2]                    (折線)
-((3*Sqrt[33]-7)/112)*x^2    (放物線)
-3
最初はお馴染の楕円で高さは3にしてある. 次が4個の楕円で高さはどれも1だ. その次が(0,0)で折り返す直線で, 最後がx2の抛物線である.



4個の楕円はx=-4,-2,0,2,4の5個所でy=0である. このうち中央のx=0では, 他の項の楕円の3を足し, 最後の3を引き, 折線と放物線はx=0で0だから, 0のままである.

x=4では楕円は3√33/7, 折線は2, 放物線は16*(3√33-7)/112, それから3を引くが, これは計算すると結局0になる.

x=2のところは面倒になったので, Schemeで計算した.
(define (a x)
 (define (sq x) (* x x))
 (+ (* 3 (sqrt (- 1 (sq (/ x 7)))))
    (abs (/ x 2))
    (- (* (/ (- (* 3 (sqrt 33)) 7) 112) (sq x)))
    (- 3)))

(a 2) => .5094556875135123
(a 3) => .3881737849967646
(a 1) => .3778577420858067
という次第で, 0,±4では0, ±2では0.5くらいになる. 1と3では1.37程度になろうか.



この図を見ると高さの値は微妙に違うようだが, まぁいいか. この図では±4の外側では定義されていないということで, 青線がないが, 前回のフィルタを掛けた下の図では

のように外側の方もよくみるとx軸上に青の線が見える. 高さも2倍になっているのが分かる. これから楕円の下半分を引くと, 思ったとおりの下の曲線が出来る.

ところでこの下の図は, 前回のこうもりの絵とはすこし違っている. 最後のAspectRatio->Automaticをつけなかったのである.



AspectRatioの詳細はまだわからないが, Plot関数では, AspectRatio->Automatic がないと縦横比が黄金比のφになるらしい.

ディスプレイ上で測ってみると, 左右は56ミリ, 上下は33ミリであった.
(/ 56. 33) => 1.696969696969697
確かに黄金比に近いといえなくはない. x軸の0から2と, y軸の0から2の長さは明らかに違う. Automaticを指定した前回のこうもりの絵では, 横:縦は正しく7:3になっている.

黄金比にするような見栄えを工夫するのがAutomaticの機能のように思うのだが, Mathematicaの文化はこういうものか. 前回のSinの図でも, Automaticがないので, 横/縦は1.7くらい. Automaticを追加すると, 縦と横の長さは1:1になり, もっと平べったい, 正確になった. (世の中のSinカーブでは, 前回の図も含めてx=0での勾配が1になっていない図がかなり多い.)

2015年8月5日水曜日

数式お絵描き

Raspberry PiでMathematicaが使えるのはうれしい.

そのアナウンスにこうもりのような絵があった. もちろんMathematicaのPlot関数で描いたものだ.



その描画プログラムも添えてあったので, Mathematica屋の絵を描く方法が分るのではないかと期待してプログラムを解読した. とりあえずは目がくらくらするが,

である.

そもそもMathematicaで標準関数の絵を描くのは簡単だ. "Plot["と書き, 描くべき式を書き, ","で区切り, "{x,-Pi,Pi}"のように変数の範囲を書き, "]"で閉じる.
Plot[Sin[x],{x,-Pi,Pi}]


こうもりの絵のようなのは, 上の線と下の線を{,}で囲み区切ればよい.

Plot[{Sin[x],Cos[x]},{x,-Pi,Pi}]


こうもりプログラムでは, 1行目の"With"から10行目の"]]"までが上の曲線, 11行目から15行目の"2]"までが下の曲線である.

上の曲線のプログラムは"With[{"から w(3行目), l(2,3行目), h(4,5,6行目), r(7,8行目)を局所定義し(8行目の"},"で終る), それらを使い9,10行目の本体で描画する.

w(3*Sqrt[1-(x/7)^2])はこういう曲線だ.

これは要するに長軸(半径)7, 短軸1のx2/49+y2=1なる楕円の, 平方根は正をとるからその上半分を描いたわけである. あとから縦軸を3倍した.

次はl.(6/7)*Sqrt[10]+(3+x)/2-(3/7)*Sqrt[10]*Sqrt[4-(x+1)^2] のような形だ. 下に左右反対のrがある. xで変る項は(3+x)2とSqrt[4-(x+1)^2]で, 前者は斜線, 後者は例によって楕円である.

大きさを合せて合成するとこうなる. 上の図の斜線はxの範囲-7から7まであるが, 下の図では引くべき楕円が定義されている範囲が-3から1までなので, その外の 線は消えている.



4行目のhはこうもりの耳のところで, ( (1/2)*(3*(Abs[x-1/2]+Abs[x+1/2]+6)-11*(Abs[x-3/4]+Abs[x+3/4])))といろいろの斜線を組合せているに過ぎない.

ここまで準備したところで, 上の曲線は-7から-3,-3から-1,-1から1,1から3,3から7の区間をUnitStepで接続する. UnitStep[x]はx<0では0, 0≤xでは1になる関数で, UnitStep[x+3]とすると, -3から右が1になる.

w+(l-w)*UnitStep[x+3]+(h-l)*UnitStep[x+1]+(r-h)*UnitStep[x-1]+ (w-r)*UnitStep[x-3]]

x=-7では4個のどのUnitStepも0だから最初の項wで描きだす. x=-3になるとUnitStep[x+3]が1になり, それに(l-w)が掛るから, wが消えlの曲線を描き始める. x=-1 でlが終りhが始まる. x=1でrに, x=3で(w-r)があるので, rも終り, wが復活して最後を描く.


下の線もなかなか凝っているが, 全体的には上と同じ楕円に, 4個の楕円が組み合わさっている構造だ.
ここで一番主要な線はSqrt[1-(Abs[Abs[x]-2]-1)^2]だ.



すぐ上の図は左からAbs[x], Abs[x]-2, Abs[Abs[x]-2], Abs[Abs[x]-2]-1で, ここでそれぞれの斜線部分に対応して例の楕円が4個できる仕掛けである.



UnitStepの代わりにこちらではバンド幅フィルタのような関数でこの4個の楕円を取り出している. それが((x+4)/Abs[x+4]-(x-4)/Abs[x-4])で, 左がx<-4で-1, -4<xで1, 右がx<4で-1, 4<xで1だから, 結局x<-4で0, -4<x<4で2, 4<xで0という形が得られる.



これで4個の楕円を切り出しておき, それから最初と同じ楕円を引いて下の線が描ける.



勿論面倒なのでは区間の切れ目で位置を合わせることで, Sqrt[33]などはそういう計算の結果であろうが, プログラムの骨組みの説明では無視させて貰った. 面白かった.