単振動坂

# 問題
質点が変形しない坂を転がることを考える。働く力は、重力と垂直抗力のみとする。
真上から見下ろしたとき、質点が単振動しているように見える坂の形状はどのような形だろう。

# 計算
水平方向に$x$、鉛直方向に$y$軸をとる。
坂の角度を$\theta$としたとき、水平方向に働く力は
```math
mg \sin\theta\cos\theta
```
である。ただし、$m$は質量、$g$は重力加速度である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/d4199f83-b00f-ef62-c501-120f70169507.png)

坂の形状は$\theta(x)$で定義できる。力の大きさが距離に比例すれば単振動となるので、
$$
k x = mg\sin\theta\cos\theta
$$
が成立する必要がある。$k$は任意の正の定数である。これを解けば、
```math
\theta(x) = \frac{1}{2} \sin^{-1}\left(\frac{2k}{mg}x\right)
```
となる。
さらに、
$$
\tan\theta = \frac{\Delta y}{\Delta x}
$$
より、
$$
dy = \tan\theta dx
$$
となる。これを積分すると、
$$
y(x) = \int_0^x \tan\theta(X) dX
$$
となる。

# STL形式で出力する
STL形式で形状を出力するため、CadQueryというツールを使う。インストールなしで使えるし、便利。
```
import cadquery as cq
import math
pts = []

y = 0.0
dx = 0.05
k = 0.2
xmax = 1.0 / k
N = int(xmax/dx)-1

for n in range(0, N):
    x = n * dx
    theta = 0.5 * math.asin(k * x)
    y += math.tan(theta) * dx
    pts.append((x, y))

pts.append((xmax-2*dx, 0.))
T = 5
slope = cq.Workplane("XZ" ).polyline(pts).close().mirrorY().extrude(T).translate((0,T/2.,0))
cq.exporters.export(slope, r"C:\Users\physn\Downloads\CQ-editor-Windows\CQ-editor\slope.stl")
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/609d127b-bf34-d680-edb3-f82b424f4140.png)

# 本当に単振動になってる？
Unityで試しに球を転がしてみる。Unityで取り込むためにはobjファイルに変換する必要がある。blenderを使えば簡単に変換できる。

Unityでプロジェクトを作る。Assetsのところに作成したobjファイルをドラッグアンドドロップする。Assetsに表示されたオブジェクトを３D空間にドラッグアンドドロップする。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/8aa8b067-cacc-cc9b-cfad-e4d381f605a4.png)

次に、球を追加する。メニューのGameObject -> 3D Object -> Sphere で追加します。
重力を作用させる。Add Component -> Physics -> Rigidbodyで追加する。
速度を減衰させたくないので、Angular Dragをゼロに設定する。
衝突判定を追加します。Add Component -> Physics -> Sphere Collider で設定する。

次に坂の衝突判定を設定する。Add Component -> Physics -> Mesh Collider で設定する。衝突判定の形状を設定したいので、Meshの項目をdefaultにする。
最初は、球もmesh colliderで設定したのだが、mesh collider同士の衝突は、convexをオンにしないといけないらしく、正しく判定されなかった。

次に摩擦等の設定をする。Assetsのウィンドウで右クリックし、Create -> Phisic materialで材料を追加する。すべての項目をゼロに設定する。球と坂のmaterialをこの材料に設定する。

球の位置を取得するため、スクリプトを書く。Assets -> C# Scriptでコードを書く。
```c#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System;
using System.IO;
using System.Text;

public class getpos : MonoBehaviour
{
    // Start is called before the first frame update
    StreamWriter writer;
    void Start()
    {
        Encoding enc = Encoding.GetEncoding("Shift_JIS");
        writer = new StreamWriter("./pos.txt", false, enc);
    }

    // Update is called once per frame
    void Update()
    {
        Vector3 tmp = GameObject.Find("Sphere").transform.position;
        writer.WriteLine(Time.frameCount + " " + tmp.x);
    }
}
```
<iframe width="560" height="315" src="https://www.youtube.com/embed/O3P98JSNmNk?si=D3DhPaB1LYWoGzmR" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

```
Final set of parameters            Asymptotic Standard Error
=======================            ==========================
a               = 2.59838          +/- 0.004235     (0.163%)
b               = 816.636          +/- 0.2551       (0.03124%)
c               = 3.49383          +/- 0.003906     (0.1118%)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/520857/90b5e357-e7fb-e5db-3504-853b3b995bf8.png)


それっぽいがなぜか減衰する。