人类对数学世界的探索源于两样东西:计数与丈量。计数让我们认识到“多少”以及如何计算增加或减少的数量,这就催生了数字的概念及后来的代数学;丈量则源自测量土地、角度和几何关系,进而发展为几何学。尽管我们高中毕业后可能对数学模型的理解还较为浅薄,但几何模型无疑是最直观的。通过一张图,我们可以迅速判断两个平面是否平行,哪两条线是否垂直。借助几何定理,我们还可以推算线段的长度等。
几何建模不仅仅是简单的图形分析,实际上它涉及到了两种基本的数学关系:位置关系和数量关系。位置关系包括平行、垂直、异面、相交等,而数量关系则涉及边长、角度、面积等的求解。在这些问题中,方程和函数是解决问题的基础。
现在我们可以通过三种主要方法来分析几何问题:
传统几何的演绎证明体系:这种方法依赖于已被证明的公理和定理体系,例如勾股定理、正弦定理等。通过构造辅助线、辅助平面等,利用严密的逻辑推理来解决问题,计算量较小,但分析过程较为复杂。
基于向量的计算几何:向量最初用于表示有向线段,但后来人们发现,借助向量的一些运算特性,许多几何问题可以转化为计算问题。例如,边长、角度、面积等可以通过向量的模长、内积等来求解,平行、垂直等关系可以通过向量共线或内积为0来判定。计算过程更加高效。
基于极坐标与方程的解析几何:通过将几何图形的关系转化为方程求解,这种方法可以将几何问题转化为代数问题。极坐标和参数方程的使用,使得一些曲线问题的求解变得更加方便。
高中阶段,我们曾学习过一些几何公式和定理,例如:
通过这些公式和定理,我们能够解决各种几何问题。几何学不仅仅是一个简单的图形计算,而是一门充满丰富数学关系的学科。
高中阶段的向量知识通常限于三维空间,但事实上,向量可以有任意维数。数学上,向量可以看作是一个n维欧几里得空间中的点:
x=[x1,x2,…,xn]⊤x = [x_1, x_2, \dots, x_n]^\top
向量不仅可以进行加减运算,还可以进行数乘运算。比如在 Python 中,我们可以利用 NumPy 库来创建和操作向量:
import numpy as np
x = np.array([1, 2, 3, 5, 8])
通过这样的方式,我们能够更便捷地进行向量的计算。
向量的引入,不仅为了表示几何中的方向和距离,更是为了解决几何问题。许多物理问题(如力、速度、加速度)都可以用向量表示,这使得我们可以直接通过向量的运算来计算合力、相对速度等,而不必借助复杂的几何图形。在计算机图形学中,向量也被广泛应用,帮助我们实现图形的旋转、平移、缩放等变换。
解析几何方法本质上就是通过函数和方程表示几何曲线。这种方法将几何问题转化为代数问题,借助计算来快速求解。这种思路可以在计算机编程中得到广泛应用,特别是在工程、物理学和图形学中,极大地提高了解题效率。
在本节中,我们将介绍 Python 中最强大的科学计算库之一——NumPy。在深入学习之前,我们首先需要了解线性代数在实际应用中的重要性。线性代数不仅是理解数据结构、解决数学问题的基础,也是计算机图形学、机器学习等领域中不可或缺的工具。NumPy 在这里发挥着至关重要的作用,因为它为我们提供了一个高效且便捷的平台,用于处理数值计算和线性代数运算。接下来的内容将通过一些实际示例,展示如何使用 NumPy 执行基本的线性代数操作。
在科学计算中,NumPy 的数组对象是我们解决问题的重要工具。它使得我们能够轻松地进行向量化运算,也就是说,可以一次性处理整个数据集,而无需使用显式的循环。这种处理方式不仅简洁,而且计算速度比传统的 Python 循环要快得多。在 NumPy 中,向量和矩阵都可以通过二维数组来表示。以下是一些基本的操作示例:
import numpy as np
# 创建向量
vector = np.array([1, 2, 3])
# 创建矩阵
matrix = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
# 向量的维度
print(vector.shape) # (3, )
# 矩阵的维度
print(matrix.shape) # (3, 3)
# 矩阵的行数和列数
print(matrix.shape[0]) # 行数, 3
print(matrix.shape[1]) # 列数, 3
# 索引
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]]
# 向量加法
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]]
在 NumPy 中,数组的广播机制使得我们能够高效地进行各种线性代数运算。例如,我们可以直接将一个标量与向量或矩阵相乘,而无需编写显式的循环。NumPy 还提供了计算矩阵转置、行列式、逆矩阵等常见操作的函数。
import numpy as np
# 标量与向量相乘
scalar = 5
scaled_vector = scalar * vector
print("Scaled vector:", scaled_vector) # 输出: [ 5 10 15]
# 矩阵的转置
transposed_matrix = matrix.T
print("Transposed matrix:\n", transposed_matrix)
# 输出:
# [[1, 4, 7]
# [2, 5, 8]
# [3, 6, 9]]
# 计算行列式
matrix_determinant = np.linalg.det(matrix)
print("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) # 输出: [2. 3.]
NumPy 中的 linalg
子模块提供了一系列强大的线性代数函数。无论是求解方程组、计算特征值和特征向量,还是执行奇异值分解,这些工具都能为我们提供强大的支持。以下是一些常见的 numpy.linalg
函数示例:
import numpy as np
# 如果矩阵是奇异矩阵,可以使用伪逆
pseudo_inverse_matrix = np.linalg.pinv(matrix)
print("Pseudo-inverse of the matrix:")
print(pseudo_inverse_matrix)
eigenvalues, eigenvectors = np.linalg.eig(matrix)
print("Eigenvalues:", eigenvalues)
# 输出: [ 1.61168440e+01 -1.11684397e+00 -1.30367773e-15]
print("Eigenvectors:")
print(eigenvectors)
U, S, V = np.linalg.svd(matrix)
print("U matrix:")
print(U)
print("Singular values:")
print(S)
print("V matrix:")
print(V)
单波束测深与多波束测深:
问题背景:
本问题属于几何模型问题。已知条件:
几何模型的抽象:
关键公式:
覆盖宽度计算:
W=D(sin60∘sin28.5∘+sin60∘sin31.5∘)W = D \left( \frac{\sin 60^\circ}{\sin 28.5^\circ} + \frac{\sin 60^\circ}{\sin 31.5^\circ} \right)其中D为海水深度,28.5°和31.5°为通过几何关系求出的角度。
相邻测线重叠率计算: 通过相似三角形和正弦定理,求解两条相邻测线的重叠宽度λ,进而计算重叠率(η)。
重叠部分的计算:
λ=(Dk+dtanα)⋅(sin60∘sin31.5∘+sin60∘sin28.5∘)−dcos1.5∘\lambda = (D_k + d \tan \alpha) \cdot \left( \frac{\sin 60^\circ}{\sin 31.5^\circ} + \frac{\sin 60^\circ}{\sin 28.5^\circ} \right) - d \cos 1.5^\circ
其中d为相邻测线间的距离,Dk为某一测线的海底深度,α为坡度。
通过建模与编程求解,可以得到不同测线距离下的计算结果,包括海水深度、覆盖宽度和重叠率。结果表明,覆盖宽度与海水深度呈现典型的函数关系,随着距离的增加,覆盖宽度逐渐减小,且在一定距离内,重叠率会达到最小值。
Python脚本用于计算覆盖宽度、重叠率等指标:
import numpy as np
from scipy.optimize import fsolve
# 常量定义
theta = 2 * np.pi / 3 # 全开角
alpha = 1.5 / 180 * np.pi # 海底坡度
htheta = theta / 2 # 半开角
h = 70 # 中心点的海水深度
d = 200 # 测线距离
k = np.tan(np.pi / 2 - htheta) # 超声波直线的斜率
k0 = np.tan(alpha) # 海底斜率
# 初始化
Aleft = [] # 左端点坐标
Aright = [] # 右端点坐标
Acenter = [] # 中心点坐标
W = [] # 覆盖宽度
# 求解交点
for n in range(-4, 5):
leftsolve = lambda t: k * (t - n * d) - k0 * t + h
rightsolve = lambda t: -k * (t - n * d) - k0 * t + h
tleft = fsolve(leftsolve, 0)
tright = fsolve(rightsolve, 0)
Aleft.append([tleft[0], k0 * tleft[0] - h])
Aright.append([tright[0], k0 * tright[0] - h])
Acenter.append([200 * n, k0 * 200 * n - h])
Aleft = np.array(Aleft)
Aright = np.array(Aright)
Acenter = np.array(Acenter)
D = Acenter[:, 1] # 海水深度
W = np.sqrt((Aleft[:, 0] - Aright[:, 0]) ** 2 + (Aleft[:, 1] - Aright[:, 1]) ** 2) # 覆盖宽度
# 计算重合部分
cover = np.zeros(8)
for i in range(8):
cover[i] = np.sqrt((Aright[i, 0] - Aleft[i + 1, 0]) ** 2 + (Aright[i, 1] - Aleft[i + 1, 1]) ** 2)
# 判断是否有重叠,如果没有,则重叠率为负值
if Aright[i, 0] - Aleft[i + 1, 0] < 0:
cover[i] = -cover[i]
eta = cover / W[1:]
# 打印结果
print("海水深度 D:", D)
print("覆盖宽度 W:", W)
print("重合部分比例 eta:", eta)
该脚本通过数值计算得出了不同测线距离下的海水深度、覆盖宽度以及重叠率。
通过这些结果,可以优化测线设计,以提高测量效率并减少漏测或冗余数据。
问题二背景: 考虑一个矩形待测海域,测线方向与海底坡面法向投影的夹角为,建立多波束测深覆盖宽度的数学模型。测量场景从二维扩展到三维空间,利用正弦定理和三面角定理求解波束覆盖宽度。
numpy
和scipy
库,通过编程解方程计算不同测量位置下的波束覆盖宽度。在科学计算和工程应用中,方程与方程组的求解是非常常见的需求。Python 提供了多个库,可以帮助我们简便地求解各种数学问题,尤其是在数值计算和符号计算方面,Numpy 和 Sympy 是最常用的工具。
Numpy 是一个强大的数值计算库,提供了多种矩阵运算功能。在解决线性方程组时,linalg.solve
函数非常实用。假设我们有如下的线性方程组:
10x−y−2z=72,−x+10y−2z=83,−x−y+5z=42.\begin{aligned} 10x - y - 2z &= 72, \\ -x + 10y - 2z &= 83, \\ -x - y + 5z &= 42. \end{aligned}
可以将其表示为矩阵形式 Ax=bAx = b,其中:
A=(10−1−2−110−2−1−15),b=(728342)A = \begin{pmatrix} 10 & -1 & -2 \\ -1 & 10 & -2 \\ -1 & -1 & 5 \end{pmatrix}, \quad b = \begin{pmatrix} 72 \\ 83 \\ 42 \end{pmatrix}
我们可以用以下 Python 代码来求解:
import numpy as np
# 系数矩阵和常数向量
a = np.array([[10, -1, -2], [-1, 10, -2], [-1, -1, 5]])
b = np.array([72, 83, 42])
# 求解方程
c = np.linalg.solve(a, b)
print(c)
输出结果:
[11. 12. 13.]
此外,我们还可以使用矩阵的逆来求解方程组,即:
x = np.linalg.inv(a).dot(b)
print(x)
输出结果与上面相同:
[11. 12. 13.]
Sympy 是一个用于符号计算的 Python 库,可以为方程组提供解析解。解析解是使用符号表示的解,而不是数值解。
使用 Sympy 求解方程组时,我们首先定义符号变量,然后用 solve
函数来求解。例如,我们可以解以下方程:
2x−2=02x - 2 = 0
from sympy import symbols, solve
x = symbols('x')
solution = solve(2*x - 2, x)
print(solution) # 输出: [1]
对于方程组,例如:
x+y=35,2x+4y=94,\begin{aligned} x + y &= 35, \\ 2x + 4y &= 94, \end{aligned}
我们可以用以下代码求解:
y = symbols('y')
solution = solve([x + y - 35, 2*x + 4*y - 94], x, y)
print(solution) # 输出: {x: 23, y: 12}
Sympy 还支持求解非线性方程组,如:
from sympy import nonlinsolve
a, b = symbols('a b')
solution = nonlinsolve([a**2 + a + b, a - b], [a, b])
print(solution) # 输出: {(-2, -2), (0, 0)}
在遇到无法用符号方法(如 Sympy)求解的方程时,可以使用数值方法。fsolve
是 Scipy 库中用于求解非线性方程组的一个强大工具。它通过迭代的方法找到方程组的根。
下面是一个具体的示例,考虑一个三角形型的 Stewart 平台的求解问题:
from scipy.optimize import fsolve
from math import sin, cos, pi
def equations(vars):
x, y, theta = vars
L1, L2, L3 = 3, 3, 3
p1, p2, p3 = 5, 5, 3
x1, x2, y2 = 5, 0, 6
# 方程定义
eq1 = (x + L3*cos(theta) - x1)**2 + (y + L3*sin(theta))**2 - p1**2
eq2 = x**2 + y**2 - p2**2
eq3 = (x + L2*cos(pi/3 + theta))**2 + (y + L2*sin(pi/3 + theta) - y2)**2 - p3**2
return [eq1, eq2, eq3]
# 初始猜测值
initial_guess = [-1.37, 4.80, 0.12]
# 使用 fsolve 求解
result = fsolve(equations, initial_guess)
print(result)
输出结果:
[1.15769945 4.86412705 0.02143414]
fsolve
通过数值迭代找到方程组的解,其中 initial_guess
是初始猜测值。值得注意的是,数值方法依赖于初始猜测,且可能存在多个解,因此需要进行合理的选择和验证。
在本章中,我们介绍了如何使用 Python 中的 Numpy、Sympy 和 Scipy 库来求解方程和方程组。我们分别讨论了:
fsolve
)来解决复杂的非线性方程组,适用于没有简洁解析解的情况。通过这些工具,我们能够灵活地解决不同类型的数学问题,推动科学计算和工程应用的进展。在后续的章节中,我们将进一步探讨更多高级的数学建模技巧。