1 解析方法与几何建模

1.1.1 几何建模的思想

人类对数学世界的探索源于两样东西:计数与丈量。计数让我们认识到“多少”以及如何计算增加或减少的数量,这就催生了数字的概念及后来的代数学;丈量则源自测量土地、角度和几何关系,进而发展为几何学。尽管我们高中毕业后可能对数学模型的理解还较为浅薄,但几何模型无疑是最直观的。通过一张图,我们可以迅速判断两个平面是否平行,哪两条线是否垂直。借助几何定理,我们还可以推算线段的长度等。

几何建模不仅仅是简单的图形分析,实际上它涉及到了两种基本的数学关系:位置关系和数量关系。位置关系包括平行、垂直、异面、相交等,而数量关系则涉及边长、角度、面积等的求解。在这些问题中,方程和函数是解决问题的基础。

现在我们可以通过三种主要方法来分析几何问题:

  1. 传统几何的演绎证明体系:这种方法依赖于已被证明的公理和定理体系,例如勾股定理、正弦定理等。通过构造辅助线、辅助平面等,利用严密的逻辑推理来解决问题,计算量较小,但分析过程较为复杂。

  2. 基于向量的计算几何:向量最初用于表示有向线段,但后来人们发现,借助向量的一些运算特性,许多几何问题可以转化为计算问题。例如,边长、角度、面积等可以通过向量的模长、内积等来求解,平行、垂直等关系可以通过向量共线或内积为0来判定。计算过程更加高效。

  3. 基于极坐标与方程的解析几何:通过将几何图形的关系转化为方程求解,这种方法可以将几何问题转化为代数问题。极坐标和参数方程的使用,使得一些曲线问题的求解变得更加方便。

高中阶段,我们曾学习过一些几何公式和定理,例如:

  • 三角形的角度关系:三角形内角和定理,直角三角形的角度关系等。
  • 勾股定理:直角三角形中,两直角边的平方和等于斜边的平方。
  • 正弦定理和余弦定理:在三角形中,边与角的关系可以通过正弦、余弦等函数来表达。
  • 圆幂定理与切割线定理:涉及圆与切线、割线之间的关系。
  • 四点共圆:判断四点是否共圆。
  • 圆锥曲线的几何性质:包括椭圆、双曲线和抛物线的几何特性。

通过这些公式和定理,我们能够解决各种几何问题。几何学不仅仅是一个简单的图形计算,而是一门充满丰富数学关系的学科。

1.1.2 向量表示与坐标变换

高中阶段的向量知识通常限于三维空间,但事实上,向量可以有任意维数。数学上,向量可以看作是一个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])

通过这样的方式,我们能够更便捷地进行向量的计算。

向量的引入,不仅为了表示几何中的方向和距离,更是为了解决几何问题。许多物理问题(如力、速度、加速度)都可以用向量表示,这使得我们可以直接通过向量的运算来计算合力、相对速度等,而不必借助复杂的几何图形。在计算机图形学中,向量也被广泛应用,帮助我们实现图形的旋转、平移、缩放等变换。

解析几何方法本质上就是通过函数和方程表示几何曲线。这种方法将几何问题转化为代数问题,借助计算来快速求解。这种思路可以在计算机编程中得到广泛应用,特别是在工程、物理学和图形学中,极大地提高了解题效率。


1.2 NumPy 与线性代数

在本节中,我们将介绍 Python 中最强大的科学计算库之一——NumPy。在深入学习之前,我们首先需要了解线性代数在实际应用中的重要性。线性代数不仅是理解数据结构、解决数学问题的基础,也是计算机图形学、机器学习等领域中不可或缺的工具。NumPy 在这里发挥着至关重要的作用,因为它为我们提供了一个高效且便捷的平台,用于处理数值计算和线性代数运算。接下来的内容将通过一些实际示例,展示如何使用 NumPy 执行基本的线性代数操作。

1.2.1 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]]
1.2.2 使用 NumPy 进行线性代数基本运算

在 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.]
1.2.3 numpy.linalg 的使用

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)

1.3 平面几何模型的构建

1.3.1 问题背景介绍

单波束测深与多波束测深:

  • 单波束测深:利用声波在水中传播的原理,通过测量声波发射到接收的时间来计算水深。数据特点是沿航迹的测量数据密集,而测线间无数据。
  • 多波束测深:在单波束的基础上发展,能够在一个平面内发射多个波束,克服了单波束测深的缺点,能够全覆盖测量水深,适用于平坦海底区域。

问题背景:

  • 多波束测深的覆盖宽度(W)受换能器开角(θ)和水深(D)等因素的影响。
  • 需要建立模型来计算相邻条带之间的重叠率(η),确保测量的完整性。
  • 对于海底地形起伏大的情况,设计测线间隔时需要考虑不同深度的影响,避免出现漏测或数据冗余。
1.3.2 问题分析

本问题属于几何模型问题。已知条件:

  • 开角为120°,坡度为1.5°,海底深度D = 70m,求覆盖宽度W。
  • 该问题实质是已知角度和边长,求解三角形对边的几何问题。
1.3.3 模型建立

几何模型的抽象:

  • 设船的行进方向垂直纸面,发射波束至海底形成多个交点。
  • 设定海底平面角度、开角等,通过正弦定理求解波束落点的距离(即覆盖宽度W)。

关键公式:

  1. 覆盖宽度计算:

    W=D(sin⁡60∘sin⁡28.5∘+sin⁡60∘sin⁡31.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°为通过几何关系求出的角度。

  2. 相邻测线重叠率计算: 通过相似三角形和正弦定理,求解两条相邻测线的重叠宽度λ,进而计算重叠率(η)。

重叠部分的计算:

λ=(Dk+dtan⁡α)⋅(sin⁡60∘sin⁡31.5∘+sin⁡60∘sin⁡28.5∘)−dcos⁡1.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为某一测线的海底深度,α为坡度。

1.3.4 数值解法与讨论

通过建模与编程求解,可以得到不同测线距离下的计算结果,包括海水深度、覆盖宽度和重叠率。结果表明,覆盖宽度与海水深度呈现典型的函数关系,随着距离的增加,覆盖宽度逐渐减小,且在一定距离内,重叠率会达到最小值。

1.3.5 Python实现

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)

该脚本通过数值计算得出了不同测线距离下的海水深度、覆盖宽度以及重叠率。

结果分析:
  1. 海水深度D随着测线的增加逐渐减小。
  2. 覆盖宽度W在测线距离增大时逐渐减小。
  3. 重叠率η与海水深度和测线的距离有关,呈现凸函数关系。

通过这些结果,可以优化测线设计,以提高测量效率并减少漏测或冗余数据。


1.4 立体几何模型的构建

问题二背景: 考虑一个矩形待测海域,测线方向与海底坡面法向投影的夹角为,建立多波束测深覆盖宽度的数学模型。测量场景从二维扩展到三维空间,利用正弦定理和三面角定理求解波束覆盖宽度。

1.4.1 问题二的分析
  • 从二维问题延续到三维问题,采用正弦定理和三面角公式构建模型。
  • 测线与坡面法向的夹角为,测量波束的最大开角为120°,利用这些信息计算覆盖宽度。
  • 通过几何构造和方程求解,获得测量覆盖区域的几何模型和优化解。
1.4.2 模型的建立
  • 通过构造四面体几何模型,使用三面角公式及正弦定理求解涉及的角度和长度。
  • 主要方程:
    • 三面角公式:cos⁡(∠ACB)⋅cos⁡(∠BCE)=cos⁡(∠ACE)\cos(\angle ACB) \cdot \cos(\angle BCE) = \cos(\angle ACE)
    • 使用正弦定理和余弦定理计算长度和角度。
1.4.3 模型的求解与讨论
  • 使用编程计算覆盖宽度,结果表明测量船距离海域中心点的距离与覆盖宽度、测线方向夹角之间存在一定关系。
  • 分析结果显示覆盖宽度随着测量船距离增大而增加,且在某些角度下数据表现出对称性。
1.4.4 Python实现
  • 使用numpyscipy库,通过编程解方程计算不同测量位置下的波束覆盖宽度。
  • 结果以矩阵形式输出,展现了覆盖宽度与测量位置之间的关系。
1.4.5 第二种解法(解析方法)
  • 采用三维坐标系分析,通过构建直线方程和海底坡面方程,解联立方程求得波束与海底交点的坐标。
  • 进一步推导出相邻测线的覆盖宽度,最终得到落点坐标集合,从而求解所有测线的覆盖宽度。

1.5 使用Python解方程与方程组

在科学计算和工程应用中,方程与方程组的求解是非常常见的需求。Python 提供了多个库,可以帮助我们简便地求解各种数学问题,尤其是在数值计算和符号计算方面,Numpy 和 Sympy 是最常用的工具。

1.5.1 利用 Numpy 求解线性方程(组)的数值解

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.]
1.5.2 利用 Sympy 求解方程(组)的解析解

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)}
1.5.3 利用 Scipy 求解方程(组)的数值解

在遇到无法用符号方法(如 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 库来求解方程和方程组。我们分别讨论了:

  • Numpy:用于求解线性方程组,适合处理数值解。
  • Sympy:用于求解符号方程组,提供解析解。
  • Scipy:提供了多种数值方法(如 fsolve)来解决复杂的非线性方程组,适用于没有简洁解析解的情况。

通过这些工具,我们能够灵活地解决不同类型的数学问题,推动科学计算和工程应用的进展。在后续的章节中,我们将进一步探讨更多高级的数学建模技巧。

你可能感兴趣的:(线性代数,矩阵,机器学习)