More than 1 year has passed since last update.

はじめに

単位付きの数値を (物理)量 ((Physical) Quantity)といいます。
私たち技術者は日々、たくさんの量と付き合っていて、量の単位を変換したり、異なる単位で表された量同士を計算したりしています。しかし、算法言語 programming language の「数」は単位を持たない数値のみなので、算譜 program は数同士の計算の記述に留め、単位はコメントやノートに書いておくことが多いのではないでしょうか? 量をそのまま扱う手法があれば、見通しがよくなりなるはずです。

ここでは、Julia言語で、量の算術を支援する Physical パッケージを紹介します。

インストール

Physical.jl パッケージの本家は https://github.com/ggggggggg/Physical.jl です。
Julia言語の公式パッケージではないので、直接 github からインストールします。

Pkg.clone("https://github.com/ggggggggg/Physical.jl.git").

パッケージを使うには using で読み込みます。

julia> using Physical

簡単な例から

本パッケージでも、単位付き数値(量)は、数値と単位を掛け算したものです。接頭辞 (Micro, Milli, Kilo など) をつける場合は、接頭辞と単位を括弧 () で囲みます。

julia> 1.0 * Meter
1.0 m 

julia> 1000.0 * (Milli*Meter)
1000.0 mm 

比較演算子 == や近似比較関数 isapprox を用いて、量同士を比較できます。
単位は異なっても同じ量であれば真と判定されます。次元が異なる量を比較すると例外が発生します。

julia> 1.0 * Meter == 1000.0 * (Milli*Meter)
true

julia> 0.9 * Meter == 1000.0 * (Milli*Meter)
false

julia> (1.0 + 1e-8) * Meter == 1000.0 * (Milli*Meter)
false

julia> isapprox( (1.0 + 1e-8) * Meter , 1000.0 * (Milli*Meter) )
true

julia> 1.0 * Second == 1000.0 * (Milli*Meter)
ERROR: AssertionError:
 in == at C:\Users\ ___ \.julia\v0.4\Physical\src\Quantities.jl:122

量の大きさ(数字)と単位を取り出すには .value.unit をそれぞれ用います。
.unit の結果は、文字列型ではなく PUnits.Unit 型です。

julia> (1.0 * Meter).value
1.0

julia> (1.0 * Meter).unit
m 

julia> typeof(ans)
PUnits.Unit

julia> (1000.0 * (Milli*Meter)).value
1000.0

julia> (1000.0 * (Milli*Meter)).unit
mm 

julia> (1.0 * Meter).unit == (1000.0 * (Milli*Meter)).unit
false

同じ次元の量は加減算できます。次元が異なる量を加減算すると、例外が発生します。

julia> 1000.0*(Milli*Meter) + 0.1*Meter
1100.0 mm 

julia> 1000.0*(Milli*Meter) + 0.1*Gram
ERROR: incompatible base units kg  and m 
 in error at error.jl:21

基本単位として、質量(重さ)、長さ、時間、電流、温度、物質量を知っておけばよいでしょう。単位はフルスペルで書きます。Julia の流儀に従い、定数の頭文字は大文字にします。

julia> Kilogram
1 kg  

julia> Gram
1 g  

julia> Meter
1 m  

julia> Second
1 s  

julia> Ampere
1 A  

julia> Kelvin
1 K  

julia> Mole
1 mol  

組立単位

単位同士を乗除すると組立単位を作れます。

julia> 1.0 * Meter / Second
1.0 s⁻¹m  

量同士は乗除できます。単位も含めて計算できます。結果が無次元になると、数字型 FloatComplex になります。

julia> (1.0*Meter) / (1.0*Second)
1.0 s⁻¹m 


julia> v=(1.0*Meter)^3
1.0 m³

julia> v^(1/3)
1.0 m  

julia> v^(2/3)
1.0 m²

julia> (1.0*Meter)/(1.0*Meter)
1.0

julia> typeof(ans)
Float64

julia> Complex(1.0,1.0)*Meter / (1.0*Meter)
1.0 + 1.0im

julia> typeof(ans)
Complex{Float64}

単位の変換

単位の変換には as を用います。第二引数が変換先の単位です。変換先は組立単位でも構いません。
変換できない単位を指定すると例外が発生します。

julia> as( 1000.0 * (Milli*Meter), Meter)
1.0 m 

julia> as( 1000.0 * (Milli*Meter), Second)
ERROR: incompatible base units m  and s 
 in error at error.jl:21

エネルギーの単位

$\textrm{J}$ (joule, ジュール)はエネルギーの単位です。joule に等価な組立単位が複数あります。

julia> (1.0 * KiloGram)* (1.0*Meter/Second)^2
1000.0 g s⁻²m²

julia> as( ans, Joule )
1.0 J 

julia> (1.0*Volt)*(1.0*Coulomb)
1.0 V C 

julia> as( ans, Joule )
1.0 J 

定義済の単位や型

本パッケージには、多数の単位や定数が定義されています。定義ファイルは、data / default ディレクトリ (github のソースでは https://github.com/ggggggggg/Physical.jl/tree/master/data/default ) にあります。
以下の、4つのファイルがインクルードされているので、中身を見てみるとよいでしょう (なお b_english.jl の定義は、現在 exportされていないので使えません)。

julia> Physical.loaded_files
4-element Array{ByteString,1}:
 "a_prefix.jl"
 "a_si_plus.jl"
 "b_english.jl"
 "c_physics.jl"

エネルギーの単位: 電子ボルト

電磁気学や電気電子工学では、エネルギーを電子ボルト(electron volt) で表示する場合があります。

Julia> 1.0 * ElectronVolt
1.0 eV 

Julia> as( ans, Joule)
1.602176565e-19 J 

新しい派生単位の作成

新しく派生単位を定義するには、DerivedUnit を用います。第一変数は、新しい派生単位の文字列表現です。例で説明しましょう。

日本の長さの単位

日本の尺貫法の長さ・面積の単位を作ってみましょう。

julia> const Shaku = DerivedUnit( "尺", 10 // 33 * Meter)
1 尺

julia> const KenJp = DerivedUnit( "閒", 6. * Shaku)
1 閒

julia> const Tsubo = DerivedUnit( "坪", KenJp ^2 )
1 坪 

julia> as( 30.* Tsubo, Meter^2 )
99.17355371900828 m²

体積の単位 リットル

体積の単位 リットル (liter) を定義しましょう。
1リットルは 一辺 $10~\textrm{cm}$ の立方体(サイコロ)の体積です。 $1~\textrm{dm} = 10^{-1}~\textrm{m} = 10~\textrm{cm}$ 。
$1~\textrm{L} = 1~\textrm{dm}^3 = (1~\textrm{dm})^3$ 。

julia> const Liter = DerivedUnit( "L", (Deci*Meter)^3 )
1 L 

julia> (10.*(Centi*Meter))^3
1000.0 cm³

julia> as( ans, Liter)
1.0 L 

圧力の単位

$\textrm{Pa}$ (pascal, パスカル)は圧力の単位です。
圧力とは、単位面積当たりに加わる力です。$\textrm{Pa}=\frac{\textrm{N}}{\textrm{m}^2}$

1気圧を定義してみましょう。1気圧は 1013.25 hPa (ヘクトパスカル)です。

julia> const Atmosphere = DerivedUnit("atm", 1013.25 (Hecto*Pascal) )

julia> 1.0 * Atomsphere
1.0 atm

julia> as( ans, Pascal)
101325.0 Pa  

julia> as(ans, Mega*Pascal)
0.101325 MPa  

psi という圧力の単位を知っていますか? pound-force per square inch の頭文字を取ったもので、「一辺 1 inch の正方形に 1 pound の荷重が印加された」圧力に対応します。米国はヤードポンド法を使っているので、米国発祥の科学技術分野 (特に航空宇宙分野)に関わると慣れざるをえません。
1 inch = 25.4 mm、1 pound = 453 g (ハンバーガーなどの、クォーターパウンダーは $\frac{1}{4}$ pound = 113 g)。 g_earth_gravityは、地上における重力加速度です ( c_physics.jl に定義されています)。

julia> const Inch = DerivedUnit("in", 254//10000*Meter)
1 in 

julia> const Pound = DerivedUnit("lb", 453.59237*Gram)
1 lb 

julia> as(0.25*Pound, Gram)
113.3980925 g 

julia> const Psi = DerivedUnit("psi", Pound * g_earth_gravity / Inch^2)
1 psi 

julia> as( 1.0*Psi, Pascal )
6894.757293168362 Pa 

1気圧は何psi かな?

julia> 1.0 * Atomsphere
1.0 atm

julia> as( ans, Psi)
14.695948775513449 psi 

単位付き数値ベクトルの利用

数値のコレクションに単位を付与できます。数値ベクトルや linspace 型に使えます。

julia> [ 0., 1., 2. ] * Meter
[0.0,1.0,2.0] m 

単位付き数値ベクトルの計算

一次元運動の数値解を求めてみましょう。

球を鉛直上向きに放り投げたとき、その球が鉛直下向きの重力のみを感じて運動するとします。
球の速度 $v$ と高さ $y$ は、以下の式で表されます ($g$ は重力加速度)。
$$ v = v_0 - g t ,$$
$$ y = v_0 t - \frac{1}{2}g t^2 .$$
ただし、時刻 $t=0~\textrm{s}$における速度を $v_0$、高さを $y = 0~\textrm{m}$ としました。

$v$ と $y$ を算出する時刻 $t$ のベクトルを作ります。

julia> ts = linspace(0,2)  * Second
linspace(0.0,2.0,50) s 

初速度を、次のようにしました。

julia> v0=13.* Meter/Second
13.0 s⁻¹m 

時刻 $t$ における速度 $v$ と高さ $y$ を計算します。上の式をそのまま書けばよいですね。$.*$ は、ベクトルの要素同士の乗算です。

julia> vs = v0 - g_earth_gravity .* ts
linspace(13.0,-6.613299999999999,50) s⁻¹m 

julia> ys = v0 .* ts - g_earth_gravity * ts .* ts / 2.
[0.0,0.522443,1.02855,1.51832,1.99175,2.44884,2.8896,3.31401,3.72209,4.11384  ……
  8.1544,8.02334,7.87594,7.71221,7.53213,7.33572,7.12297,6.89389,6.64846,6.3867]
 m 

PyPlot を用いて $v(t)$, $y(t)$ をグラフに描きましょう。
PyPlot は、Python の 2次元プロットライブラリ matplotlibを Juliaから使うためのパッケージです。
matplotlibでダブルYグラフ (x軸が共通で、y軸が左右にあるグラフ)を描くサンプルプログラムが api example code: two_scales.py にあります。
これを Juliaで実装しましょう。量の数字部分を取り出すには .value を使うのでした。

using PyPlot
plot( ts.value ,vs.value, "b.")
ax1 = gca()
ax1[:set_xlabel]("time (s)")
ax1[:set_ylabel]("velocity (m/s)", color="b")
for t1 in ax1[:get_yticklabels]()
    t1[:set_color]("b")
end
ax2 = ax1[:twinx]()
ax2[:plot](ts.value, ys.value, "r-")
ax2[:set_ylabel]("height (m)", color="r")
for tl in ax2[:get_yticklabels]()
    tl[:set_color]("r")
end

output_73_0.png

なお、PyPlotで matplotlib の任意の関数を呼ぶ方法は、拙文で紹介しました。
- Qiita: 決定版?「Juliaでジュリア集合を描く」http://qiita.com/tenfu2tea/items/6bcbdd7586ea070cc25d
- Drawing Julia sets in Julia language matplotllib, APIの呼出し http://nbviewer.ipython.org/gist/tenfu2tea/fb8741db797aa42b6585#matplotllib-API%E3%81%AE%E5%91%BC%E5%87%BA%E3%81%97

まとめ

以上、Physical パッケージの機能を紹介しました。
本パッケージは、Julia のコマンドライン (REPL)を、量の電卓として使うのに十分な機能を提供します。ぜひ試してみてください。