数学建模
解析方法与几何模型
- 数学建模
-
- [1.1 向量表示法与几何建模基本案例](#1.1 向量表示法与几何建模基本案例)
-
- [1.1.1 几何建模的思想](#1.1.1 几何建模的思想)
- [1.1.2 向量表示与坐标变换](#1.1.2 向量表示与坐标变换)
- [1.2 Numpy 与线性代数](#1.2 Numpy 与线性代数)
-
- [1.2.1 Numpy向量与矩阵的操作](#1.2.1 Numpy向量与矩阵的操作)
- [1.2.2 利用Numpy进行线性代数基本运算](#1.2.2 利用Numpy进行线性代数基本运算)
- [1.2.3 `numpy.linalg` 的使用](#1.2.3
numpy.linalg
的使用)
1.1 向量表示法与几何建模基本案例
1.1.1 几何建模的思想
人类对于数学世界的探索起源于两样东西:一是计数,二是丈量。计数用以表示多少,要计算多了多少少了多少,于是有了数字的概念和四则运算,也就有了后来的代数学;丈量是测量土地的长宽面积、测量角度、分析几何关系等,也就有了后来的几何学。高中毕业以后,我们对于数学模型的理解其实还很浅薄,但几何模型对我们来讲是最直观的东西。有一张图,我们就可以直观地感受:哪两个平面平行,哪两条线垂直......通过一系列的几何定理还可以推算线段的长度等等。所以,我们就以几何模型作为了解数学建模的切入点。
1.1.2 向量表示与坐标变换
在数学中,坐标变换通常涉及到一系列的矩阵运算,这些矩阵描述了一个坐标系相对于另一个坐标系的位置和方向。旋转变换就是其中的一个典型例子。当我们说一个坐标系相对于另一个坐标系进行了旋转,我们通常是指它绕着一个轴或者点旋转了一定的角度。二维空间的旋转可以简化为点绕原点旋转,而三维空间则涉及到更复杂的轴向旋转。
在二维空间中,如果我们要将坐标系绕原点旋转一个角度,就可以通过旋转矩阵来实现。旋转矩阵是一个非常简单而又强大的工具,它可以将原始坐标系中的点通过线性变换映射到新坐标系中。对于逆时针旋转,二维旋转矩阵的形式是
[ cos θ − sin θ sin θ cos θ ] . (1.1.2) \left[ \begin{matrix} \cos \theta & -\sin \theta\\ \sin \theta & \cos \theta \end{matrix} \right] . \tag{1.1.2} [cosθsinθ−sinθcosθ].(1.1.2)
这里, θ \theta θ是旋转角度,当应用这个旋转矩阵于一个点 ( x , y ) (x, y) (x,y),它会给出新的坐标 ( x ′ , y ′ ) (x', y') (x′,y′),这表示了原始点在新坐标系中的位置。
使用NumPy进行这样的变换非常简单。首先,我们创建一个表示点坐标的NumPy数组,然后创建表示旋转矩阵的二维数组。通过对这两个数组进行点积运算(也就是矩阵乘法),我们就可以得到新的坐标,在Python中可以这样实现:
python
import numpy as np
# 设定旋转角度,这里我们以30度为例
theta = np.radians(30) # 将30度转换为弧度
# 创建旋转矩阵
rotation_matrix = np.array([
[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]
])
# 假设我们有一个点 (a, b)
point = np.array([a, b])
# 通过旋转矩阵变换这个点的坐标
rotated_point = rotation_matrix.dot(point)
print("原坐标为:", point)
print("旋转后的坐标为:", rotated_point)
# 原坐标为: [5 3]
# 旋转后的坐标为: [2.83012702 5.09807621]
在三维空间中,物体的旋转可以围绕三个主轴进行:$\mathrm{x}$轴, $\mathrm{y}$轴和$\mathrm{z}$轴。这些轴旋转代表了不同方向的运动,并且可以通过旋转矩阵来数学描述。例如,一个点$P(x, y, z)$绕$\mathrm{z}$轴旋转角度$\alpha$可以表示为
$$
R_{\mathrm{z}}(\alpha) = \left[ \begin{matrix}
\cos\alpha & -\sin\alpha & 0\\sin\alpha & \cos\alpha & 0\\0 & 0 &1
\end{matrix} \right], \tag{1.1.3}
$$
这个旋转保持$\mathrm{z}$坐标不变,同时在$XY$平面上变换$\mathrm{x}$和$\mathrm{y}$坐标。相似地,点$P$绕$\mathrm{y}$轴旋转角度$\beta$的旋转矩阵为
$$
R_{\mathrm{y}}(\beta) = \left[ \begin{matrix}
\cos\beta & 0 & \sin\beta\\
0 & 1 & 0\\
-\sin\beta & 0 & \sin\beta
\end{matrix} \right], \tag{1.1.4}
$$
这个旋转保持$\mathrm{y}$坐标不变,同时在$XZ$平面上变换$\mathrm{x}$和$\mathrm{z}$坐标。而点$P$绕$\mathrm{x}$轴旋转角度$\gamma$的旋转矩阵为
$$
R_{\mathrm{x}}(\gamma) = \left[ \begin{matrix}
1 & 0 & 0\\
0 & \cos\gamma & -\sin\gamma\\
0 & \sin\gamma & \cos\gamma
\end{matrix} \right], \tag{1.1.5}
$$
这个旋转保持$\mathrm{x}$坐标不变,同时在$YZ$平面上变换$\mathrm{y}$和$\mathrm{z}$坐标。若点$P$需同时围绕三个轴旋转,则最终旋转矩阵$R$为这三个矩阵的乘积,即$R = R_{\mathrm{z}}(\alpha)R_{\mathrm{y}}(\beta)R_{\mathrm{x}}(\gamma)$。需要注意的是,由于矩阵乘法的非交换性,旋转的顺序会影响最终结果。
在实际应用中,如机器人学、航空航天和计算机图形学,旋转顺序对于模拟和预测物体如何移动至关重要。例如,飞机的姿态控制就极依赖于绕不同轴的旋转顺序,以精确地模拟和控制飞机的行动。在三维建模和动画制作中,这些旋转变换同样是创建动态、逼真场景的基础。
在Python中,利用NumPy库,我们可以使用如下代码片段来实现三维旋转变换:
```python
import numpy as np
# 定义旋转角度(以弧度为单位)
alpha = np.radians(30) # 绕 Z 轴旋转
beta = np.radians(45) # 绕 Y 轴旋转
gamma = np.radians(60) # 绕 X 轴旋转
# 定义旋转矩阵
R_z = np.array([[np.cos(alpha), -np.sin(alpha), 0],
[np.sin(alpha), np.cos(alpha), 0],
[0, 0, 1]])
R_y = np.array([[np.cos(beta), 0, np.sin(beta)],
[0, 1, 0],
[-np.sin(beta), 0, np.cos(beta)]])
R_x = np.array([[1, 0, 0],
[0, np.cos(gamma), -np.sin(gamma)],
[0, np.sin(gamma), np.cos(gamma)]])
# 总旋转矩阵
R = R_z @ R_y @ R_x
# 定义点P的坐标
P = np.array([1, 2, 3])
# 计算旋转后的坐标
P_rotated = R @ P
print("旋转后P点的坐标为:", P_rotated)
# 旋转后P点的坐标为: [3.39062937 0.11228132 1.57829826]
在该代码中,点 P P P经过由 α \alpha α, β \beta β,和 γ \gamma γ定义的旋转后,其新坐标由 P rotated P_{\text{rotated}} Protated给出。该代码首先创建了绕 z \mathrm{z} z, y \mathrm{y} y,和 x \mathrm{x} x轴的三个旋转矩阵,然后将它们相乘得到一个总的旋转矩阵 R R R,并应用这个矩阵来转换点 P P P的坐标。
正是通过这些准确的数学变换和编程实现,我们能够在计算机模拟和实际应用中处理复杂的三维空间问题。无论是设计复杂的机械系统、创建逼真的三维动画,还是开发高级的虚拟现实环境,三维旋转都是不可或缺的基础。
欧拉角是三维空间中用于表示一个物体相对于一个固定坐标系(通常是参考坐标系或世界坐标系)的方向的一组角。这种表示方法定义了三次旋转,将物体从其初始方向旋转到期望方向。欧拉角通常表示为三个角度: α \alpha α, β \beta β,和 γ \gamma γ分别对应于绕 z \mathrm{z} z轴, x \mathrm{x} x轴(或 y \mathrm{y} y轴),以及再次 y \mathrm{y} y轴(或 x \mathrm{x} x轴)的旋转。
欧拉角旋转顺序的不同,定义了不同的旋转方式,最常见的是:
- Z-Y-X(Roll-Pitch-Yaw) :首先绕 z \mathrm{z} z轴旋转 α \alpha α(Yaw),然后绕新位置的 y \mathrm{y} y轴旋转 β \beta β(Pitch),最后绕新位置的 x \mathrm{x} x轴旋转 γ \gamma γ(Roll)。
- Z-X-Y(Yaw-Pitch-Roll) :首先绕 z \mathrm{z} z轴旋转 α \alpha α(Yaw),然后绕新位置的 x \mathrm{x} x轴旋转 β \beta β(Pitch),最后再次绕 y \mathrm{y} y轴旋转 γ \gamma γ(Roll)。
每次旋转都是围绕变换后的轴,而不是初始的固定轴。这些旋转通常通过旋转矩阵进行计算,并且可以合成为一个单一的矩阵,它描述了总的旋转。在实际应用中,如飞行动力学和计算机图形学,欧拉角非常重要。
这里是Python中计算欧拉角旋转的代码示例,假设采用 Z Z Z- Y Y Y- X X X顺序:
python
import numpy as np
# 定义欧拉角(以弧度为单位)
alpha = np.radians(30) # 绕 z 轴的 Yaw 角度
beta = np.radians(45) # 绕 y 轴的 Pitch 角度
gamma = np.radians(60) # 绕 x 轴的 Roll 角度
# 构建对应的旋转矩阵
R_z = np.array([[np.cos(alpha), -np.sin(alpha), 0],
[np.sin(alpha), np.cos(alpha), 0],
[0, 0, 1]])
R_y = np.array([[np.cos(beta), 0, np.sin(beta)],
[0, 1, 0],
[-np.sin(beta), 0, np.cos(beta)]])
R_x = np.array([[1, 0, 0],
[0, np.cos(gamma), -np.sin(gamma)],
[0, np.sin(gamma), np.cos(gamma)]])
# 总旋转矩阵,注意乘法的顺序
R = np.dot(R_x, np.dot(R_y, R_z))
print("组合旋转矩阵为:")
print(R)
# 组合旋转矩阵为:
# [[ 0.61237244 -0.35355339 0.70710678]
# [ 0.78033009 0.12682648 -0.61237244]
# [ 0.12682648 0.9267767 0.35355339]]
1.2 Numpy 与线性代数
在本节中,我们将探讨Python中最强大的科学计算库之一:NumPy。在深入学习之前,我们需要弄清楚线性代数在实际应用中的重要性。线性代数不仅是理解数据结构、解决数学问题的基础,也是计算机图形学、机器学习等高级领域不可或缺的工具。NumPy库在这里扮演了至关重要的角色,因为它为我们提供了一个高效、便捷的平台来处理数值计算和线性代数运算。接下来的内容,将通过实际的例子展示如何使用NumPy来执行一些基础但强大的线性代数操作。
1.2.1 Numpy向量与矩阵的操作
在科学计算的世界里,NumPy的数组对象是我们解决问题的得力助手。它能让我们轻松地执行向量化运算,这意味着可以一次性处理数据集而不需要使用循环。这种处理方式不仅代码更加简洁,而且运行速度也远快于传统的Python循环。在Numpy中,向量和矩阵都可以用二维数组表示,让我们来看看基本操作。
创建向量和矩阵
python
import numpy as np
# 创建向量
vector = np.array([1, 2, 3])
# 创建矩阵
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
向量和矩阵的基本属性
python
# 向量的维度
print(vector.shape) # (3, )
# 矩阵的维度
print(matrix.shape) # (3, 3)
# 矩阵的行数和列数
print(matrix.shape[0]) # 行数, 3
print(matrix.shape[1]) # 列数, 3
索引和切片
python
# 索引
print(vector[0]) # 输出第一个元素, 1
print(matrix[1, 1]) # 输出第二行第二列的元素, 5
# 切片
print(vector[0:2]) # 输出前两个元素, [1, 2]
print(matrix[0:2, 0:2]) # 输出左上角的2x2子矩阵, [[1, 2], [4, 5]]
向量和矩阵的运算
python
# 向量加法
vector1 = np.array([1, 2, 3])
vector2 = np.array([4, 5, 6])
print(np.add(vector1, vector2))
# [5, 7, 9]
# 矩阵乘法
matrix1 = np.array([[1, 2], [3, 4]])
matrix2 = np.array([[5, 6], [7, 8]])
print(np.dot(matrix1, matrix2)) # 或使用 matrix1 @ matrix2
# [[19, 22],
# [43, 50]]
1.2.2 利用Numpy进行线性代数基本运算
在NumPy中,我们可以利用数组的广播机制来进行各种线性代数运算。例如,你可以轻松地将一个标量与一个向量或矩阵相乘,而不需要编写任何循环。NumPy也提供了计算矩阵的转置、行列式、逆矩阵等常见操作的函数。
python
import numpy as np
# 数量乘法示例
scalar = 5
scaled_vector = scalar * vector
print("Scaled vector:", scaled_vector)
# Scaled vector: [ 5 10 15]
# 矩阵的转置示例
transposed_matrix = matrix.T
print("Transposed matrix:\n", transposed_matrix)
# Transposed matrix:
# [[1, 4, 7]
# [2, 5, 8]
# [3, 6, 9]]
# 计算行列式示例
matrix_determinant = np.linalg.det(matrix)
print("Matrix determinant:", matrix_determinant)
# Matrix determinant: 0.0
# 求解线性方程组示例
A = np.array([[3, 1], [1, 2]])
b = np.array([9, 8])
solution = np.linalg.solve(A, b)
print("Solution of the linear system:", solution)
# Solution of the linear system: [2. 3.]
1.2.3 numpy.linalg
的使用
最后,我们不能不提NumPy中的 linalg
子模块,它包含了一系列关于线性代数的函数。无论是求解方程组,还是计算特征值、特征向量,乃至执行奇异值分解,linalg
模块都能够提供帮助。通过这些工具,我们可以探索矩阵的深层属性,并应用于各种数学和工程问题。下面是一些 numpy.linalg
模块的使用示例:
计算逆矩阵
python
import numpy as np
# If the matrix is singular, use the pseudo-inverse
pseudo_inverse_matrix = np.linalg.pinv(matrix)
print("Pseudo-inverse of the matrix:")
print(pseudo_inverse_matrix)
# Pseudo-inverse of the matrix:
# [[-6.38888889e-01 -1.66666667e-01 3.05555556e-01]
# [-5.55555556e-02 4.20756436e-17 5.55555556e-02]
# [ 5.27777778e-01 1.66666667e-01 -1.94444444e-01]]
特征值和特征向量
python
eigenvalues, eigenvectors = np.linalg.eig(matrix)
print(eigenvalues)
# [ 1.61168440e+01 -1.11684397e+00 -1.30367773e-15]
print(eigenvectors)
# [[-0.23197069 -0.78583024 0.40824829]
# [-0.52532209 -0.08675134 -0.81649658]
# [-0.8186735 0.61232756 0.40824829]]
奇异值分解
python
U, S, V = np.linalg.svd(matrix)
print(U)
# [[-0.21483724 0.88723069 0.40824829]
# [-0.52058739 0.24964395 -0.81649658]
# [-0.82633754 -0.38794278 0.40824829]]
print(S)
# [1.68481034e+01 1.06836951e+00 4.41842475e-16]
print(V)
# [[-0.47967118 -0.57236779 -0.66506441]
# [-0.77669099 -0.07568647 0.62531805]
# [-0.40824829 0.81649658 -0.40824829]]
范数计算
python
norm = np.linalg.norm(vector)
print(norm)
# 3.7416573867739413