web-dev-qa-db-ja.com

numpyの曲線曲率

特別なカメラで1秒の固定時間間隔でオブジェクトのX、Y座標(cm)を測定しています。 numpy配列にデータがあります:

_a = np.array([ [  0.  ,   0.  ],[  0.3 ,   0.  ],[  1.25,  -0.1 ],[  2.1 ,  -0.9 ],[  2.85,  -2.3 ],[  3.8 ,  -3.95],[  5.  ,  -5.75],[  6.4 ,  -7.8 ],[  8.05,  -9.9 ],[  9.9 , -11.6 ],[ 12.05, -12.85],[ 14.25, -13.7 ],[ 16.5 , -13.8 ],[ 19.25, -13.35],[ 21.3 , -12.2 ],[ 22.8 , -10.5 ],[ 23.55,  -8.15],[ 22.95,  -6.1 ],[ 21.35,  -3.95],[ 19.1 ,  -1.9 ]])
_

そして、曲線は次のようになります。

_plt.scatter(a[:,0], a[:,1])
_

enter image description here

質問:

各ポイントで接線方向と放射状の加速度ベクトルを計算するにはどうすればよいですか?私は関連しているかもしれないいくつかの式を見つけました:

enter image description here

vxvyの投影をnp.diff(a, axis=0)で簡単に計算できますが、私はnumpy/pythonの初心者であり、続行するのは大変です。各点の曲率を計算できれば、問題も解決します。誰か助けてもらえますか?

16
Elian

[〜#〜] edit [〜#〜]:私はこの回答を数時間かけてオンとオフにまとめたので、最新の編集を見逃しました曲率だけが必要であることを示します。うまくいけば、この答えは関係なく役立つでしょう。

カーブフィッティングを行う以外に、導関数を近似する方法は 有限差分 を使用します。ありがたいことに、numpyには gradient メソッドがあり、これらの差の計算を行って、各内部ポイントの前と次の勾配の平均化の詳細に注意し、それぞれエンドポイントのみなど.

_import numpy as np

a = np.array([ [  0.  ,   0.  ],[  0.3 ,   0.  ],[  1.25,  -0.1 ],
              [  2.1 ,  -0.9 ],[  2.85,  -2.3 ],[  3.8 ,  -3.95],
              [  5.  ,  -5.75],[  6.4 ,  -7.8 ],[  8.05,  -9.9 ],
              [  9.9 , -11.6 ],[ 12.05, -12.85],[ 14.25, -13.7 ],
              [ 16.5 , -13.8 ],[ 19.25, -13.35],[ 21.3 , -12.2 ],
              [ 22.8 , -10.5 ],[ 23.55,  -8.15],[ 22.95,  -6.1 ],
              [ 21.35,  -3.95],[ 19.1 ,  -1.9 ]])
_

次に、各変数の導関数を計算し、それらをまとめます(何らかの理由で、np.gradient(a)を呼び出すだけの場合は、配列のリストを取得します...何が起こっているのかわからないそこに、しかし私は今のところそれを回避します):

_dx_dt = np.gradient(a[:, 0])
dy_dt = np.gradient(a[:, 1])
velocity = np.array([ [dx_dt[i], dy_dt[i]] for i in range(dx_dt.size)])
_

これにより、velocityの次のベクトルが得られます。

_array([[ 0.3  ,  0.   ],
       [ 0.625, -0.05 ],
       [ 0.9  , -0.45 ],
       [ 0.8  , -1.1  ],
       [ 0.85 , -1.525],
       [ 1.075, -1.725],
       [ 1.3  , -1.925],
       [ 1.525, -2.075],
       [ 1.75 , -1.9  ],
       [ 2.   , -1.475],
       [ 2.175, -1.05 ],
       [ 2.225, -0.475],
       [ 2.5  ,  0.175],
       [ 2.4  ,  0.8  ],
       [ 1.775,  1.425],
       [ 1.125,  2.025],
       [ 0.075,  2.2  ],
       [-1.1  ,  2.1  ],
       [-1.925,  2.1  ],
       [-2.25 ,  2.05 ]])
_

これは、aの散布図を見たときに意味があります。

ここで、速度のために、速度ベクトルの長さをとります。ただし、ここでは実際に考慮していないことが1つあります。すべてがtの関数です。したがって、_ds/dt_は、_dx/dt_および_dy/dt_と同様に、実際にはtのスカラー関数です(tのベクトル関数とは対照的です)。したがって、_ds_dt_を1秒の時間間隔ごとの値のnumpy配列として表します。各値は、毎秒の速度の概算に対応します。

_ds_dt = np.sqrt(dx_dt * dx_dt + dy_dt * dy_dt)
_

これにより、次の配列が生成されます。

_array([ 0.3       ,  0.62699681,  1.00623059,  1.36014705,  1.74588803,
        2.03254766,  2.32284847,  2.57512136,  2.58311827,  2.48508048,
        2.41518633,  2.27513736,  2.50611752,  2.52982213,  2.27623593,
        2.31651678,  2.20127804,  2.37065392,  2.8487936 ,  3.04384625])
_

これも、aの散布図のドット間のギャップを見るとある程度わかります。オブジェクトは速度を上げて、コーナーを取りながら少し遅くなり、さらに速度が上がります。 。

ここで、単位接線ベクトルを見つけるために、サイズをvelocityと同じにするために、_ds_dt_への小さな変換を行う必要があります(これにより、ベクトルを分割できます-値関数velocity(スカラー関数_ds_dt_)(の表現):

_tangent = np.array([1/ds_dt] * 2).transpose() * velocity
_

これにより、次のnumpy配列が生成されます。

_array([[ 1.        ,  0.        ],
       [ 0.99681528, -0.07974522],
       [ 0.89442719, -0.4472136 ],
       [ 0.5881717 , -0.80873608],
       [ 0.48685826, -0.87348099],
       [ 0.52889289, -0.84868859],
       [ 0.55965769, -0.82872388],
       [ 0.5922051 , -0.80578727],
       [ 0.67747575, -0.73554511],
       [ 0.80480291, -0.59354215],
       [ 0.90055164, -0.43474907],
       [ 0.97796293, -0.2087786 ],
       [ 0.99755897,  0.06982913],
       [ 0.9486833 ,  0.31622777],
       [ 0.77979614,  0.62603352],
       [ 0.48564293,  0.87415728],
       [ 0.03407112,  0.99941941],
       [-0.46400699,  0.88583154],
       [-0.67572463,  0.73715414],
       [-0.73919634,  0.67349   ]])
_

2つのことに注意してください。1. tの各値で、tangentvelocityと同じ方向を指しています。2。tの各値で、tangentは単位ベクトルです。確かに:

[12]:

_In [12]: np.sqrt(tangent[:,0] * tangent[:,0] + tangent[:,1] * tangent[:,1])
Out[12]:
array([ 1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,  1.,
        1.,  1.,  1.,  1.,  1.,  1.,  1.])
_

ここで、接線ベクトルの導関数を取得し、その長さで除算して単位法線ベクトルを取得するため、同じトリックを実行します(tangentのコンポーネントを分離して便宜上):

_tangent_x = tangent[:, 0]
tangent_y = tangent[:, 1]

deriv_tangent_x = np.gradient(tangent_x)
deriv_tangent_y = np.gradient(tangent_y)

dT_dt = np.array([ [deriv_tangent_x[i], deriv_tangent_y[i]] for i in range(deriv_tangent_x.size)])

length_dT_dt = np.sqrt(deriv_tangent_x * deriv_tangent_x + deriv_tangent_y * deriv_tangent_y)

normal = np.array([1/length_dT_dt] * 2).transpose() * dT_dt
_

これにより、normalの次のベクトルが得られます。

_array([[-0.03990439, -0.9992035 ],
       [-0.22975292, -0.97324899],
       [-0.48897562, -0.87229745],
       [-0.69107645, -0.72278167],
       [-0.8292422 , -0.55888941],
       [ 0.85188045,  0.52373629],
       [ 0.8278434 ,  0.56095927],
       [ 0.78434982,  0.62031876],
       [ 0.70769355,  0.70651953],
       [ 0.59568265,  0.80321988],
       [ 0.41039706,  0.91190693],
       [ 0.18879684,  0.98201617],
       [-0.05568352,  0.99844847],
       [-0.36457012,  0.93117594],
       [-0.63863584,  0.76950911],
       [-0.89417603,  0.44771557],
       [-0.99992445,  0.0122923 ],
       [-0.93801622, -0.34659137],
       [-0.79170904, -0.61089835],
       [-0.70603568, -0.70817626]])
_

法線ベクトルは、カーブが回転する方向を表すことに注意してください。上記のベクトルは、aの散布図と組み合わせて表示すると意味があります。特に、5番目のポイントの後に下向きから上向きに移動し、12番目のポイントの後で(x軸に対して)左に向け始めます。

最後に、加速度の接線成分と法線成分を取得するには、sに関するxy、およびtの2次導関数が必要です。次に、曲率と残りのコンポーネントを取得できます(これらはすべてtのスカラー関数であることを覚えておいてください)。

_d2s_dt2 = np.gradient(ds_dt)
d2x_dt2 = np.gradient(dx_dt)
d2y_dt2 = np.gradient(dy_dt)

curvature = np.abs(d2x_dt2 * dy_dt - dx_dt * d2y_dt2) / (dx_dt * dx_dt + dy_dt * dy_dt)**1.5
t_component = np.array([d2s_dt2] * 2).transpose()
n_component = np.array([curvature * ds_dt * ds_dt] * 2).transpose()

acceleration = t_component * tangent + n_component * normal
_
37
user554546