# 弹簧质点系统

## 受力分析

弹簧指点系统遵循胡克定律&牛顿运动定律：

![](/files/-MCzqYS-O1f8hRsbMT70)

并不复杂（当然需要考虑重力）。

## 时间积分

![](/files/-MCzqYS0XfGnn0HWHufs)

### 前向欧拉

通过当前的状态推测下一步的状态

* 通过当前的受力分析计算加速度，推断下一步的速度（ $$\times \delta t$$ ）
* 通过当前的速度计算下一步的位移

### 半隐式欧拉 （AKA. Symplectic Euler 对偶欧拉）

* 通过当前的受力分析计算加速度，推断下一步的速度（ $$\times \delta t$$ ）（和上面一样）
* 用计算出来的新速度计算下一步的位移

实现的时候，在更新计算和地面的碰撞的时候，更新位置之前首先计算和地面的碰撞（`pos.y<bottom_height?`），如果碰撞的，把速度设置为0。

上面两种都是显式时间积分器，问题在于对步长有限制，不可太大，否则容易爆炸：

![](/files/-MCzqYS23_RrVmBR5X6c)

这个公式的原因是：超过了Nyquist采样频率（TODO 找一些文献）

### 后向欧拉

隐式时间积分不止这一种，还有Middle-Point之类。

缺点：

* 难以实现，难以优化
* 每一步都会变得更加昂贵

优点：

* 可以容忍更加大的步长

![](/files/-MCzqYS3YBjl-4vSUheL)

可以看到，1和2互相依赖，所以代入求解：

![](/files/-MCzqYS4bwaSsufQY9xb)

按照道理说，求逆矩阵是最好的，但是时间复杂度不可接受，所以我们用雅可比迭代之类的方法替代：

![](/files/-MCzqYS5M-BiHTdgIjv0)

雅可比迭代的一个实现：

```python
@ti.kernel
def iterate():
    for i in range(n):
        r = b[i]
        for j in range(n):
            if i != j:
                r -= A[i, j] * x[j]

        new_x[i] = r / A[i, i]

    for i in range(n):
        x[i] = new_x[i]
```

但是雅可比迭代使用有限制，只能收敛一些性质比较好的矩阵，对谱半径有一些要求。

使用共轭梯度的话就会更快一点。

从这里就可以看出来不同求解器的区别和联系：

![](/files/-MCzqYS6kXoL69zJ7-HM)

### 大规模求解器

（仅仅是索引）

![](/files/-MCzqYS76c4G7rJevPr0)

### 实践记录


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://blog.tsingjyujing.com/game201/mass_spring.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
