scipy 如何拟合曲线(3d),其中点已指定正常的python?

3gtaxfhh  于 2022-11-09  发布在  Python
关注(0)|答案(1)|浏览(164)

我有以下三个点在三维空间与他们各自的法向量。
A、B、C是位置,而N_A、N_B和N_C是它们各自的法向矢量。

A = np.array([  348.92065834, -1402.3305998,     32.69313966])
N_A = np.array([-0.86925426,  0.02836434, -0.49355091])

B =  np.array([282.19332067,  82.52027998,  -5.92595371])
N_B = np.array([-0.82339849,  0.43041935,  0.3698028])

C = np.array([247.37475615,  -3.70129865, -22.10494737])
N_C = np.array([-0.83989222, 0.23796899, 0.48780305])

三个点几乎在一个平面上,但两个最近的点B和C之间的方向略有变化。从那里到点A,我假设在X-Y坐标中可能存在曲率,如x1c 0d1x所示,但在X-Z坐标中可能存在抛物面,如

所示
假设的条件是,如果曲率非常明显,圆柱体可以拟合这三个点。考虑到它们各自在X和Z坐标上的法向量,B和C的法向量朝下,而A的法向量朝上。所以,总的来说,它可能是一个抛物面。问题是如何拟合它们,考虑它们的法向量。如果不可能,然后如何从X和Y方向用一定曲率来拟合它们。
这是一个情节的代码

import numpy as np
import matplotlib.pyplot as plt
def set_axes_radius(ax, origin, radius):

    ax.set_xlim3d([origin[0] - radius, origin[0] + radius])
    ax.set_ylim3d([origin[1] - radius, origin[1] + radius])
    ax.set_zlim3d([origin[2] - radius, origin[2] + radius])

def set_axes_equal(ax, zoom=1.):
    '''
        Make axes of 3D plot have equal scale so that spheres appear as spheres,
        cubes as cubes, etc..  This is one possible solution to Matplotlib's
        ax.set_aspect("equal") and ax.axis("equal") not working for 3D.
        input:
          ax:   a matplotlib axis, e.g., as output from plt.gca().

    '''

    limits = np.array([
        ax.get_xlim3d(),
        ax.get_ylim3d(),
        ax.get_zlim3d(),
    ])

    origin = np.mean(limits, axis=1)
    radius = 0.5 * np.max(np.abs(limits[:, 1] - limits[:, 0])) / zoom
    set_axes_radius(ax, origin, radius)
%matplotlib qt 

# positions and their respective normal vectors

A = np.array([  348.92065834, -1402.3305998,     32.69313966])
N_A = np.array([-0.86925426,  0.02836434, -0.49355091])

B =  np.array([282.19332067,  82.52027998,  -5.92595371])
N_B = np.array([-0.82339849,  0.43041935,  0.3698028])

C = np.array([247.37475615,  -3.70129865, -22.10494737])
N_C = np.array([-0.83989222, 0.23796899, 0.48780305])

# A plane is given by

# a*x + b*y + c*z + d = 0

# where (a, b, c) is the normal.

# If the point (x, y, z) lies on the plane, then solving for d yield:

# d = -(a*x + b*y + c*z)

d_A = -np.sum(N_A * A)
d_B = -np.sum(N_B * B)
d_C = -np.sum(N_C * C)

# Create a meshgrid:

delta = 200

xlim_A = A[0] - delta, A[0] + delta
ylim_A = A[1] - delta, A[1] + delta
xx_A, yy_A = np.meshgrid(np.arange(*xlim_A), np.arange(*ylim_A))

xlim_B = B[0] - delta, B[0] + delta
ylim_B = B[1] - delta, B[1] + delta
xx_B, yy_B = np.meshgrid(np.arange(*xlim_B), np.arange(*ylim_B))

xlim_C = C[0] - delta, C[0] + delta
ylim_C = C[1] - delta, C[1] + delta
xx_C, yy_C = np.meshgrid(np.arange(*xlim_C), np.arange(*ylim_C))

# Solving the equation above for z:

# z = -(a*x + b*y +d) / c

zz_A = -(N_A[0] * xx_A + N_A[1] * yy_A + d_A) / N_A[2]
zz_B = -(N_B[0] * xx_B + N_B[1] * yy_B + d_B) / N_B[2]
zz_C = -(N_C[0] * xx_C + N_C[1] * yy_C + d_C) / N_C[2]

fig = plt.figure()
ax = fig.add_subplot(projection='3d')
ax.plot_surface(xx_A, yy_A, zz_A, alpha=0.5, color='g')
ax.plot_surface(xx_B, yy_B, zz_B, alpha=0.5, color='cyan')
ax.plot_surface(xx_C, yy_C, zz_C, alpha=0.5, color='crimson')

# Plot point.

x_A, y_A, z_A = A
x_B, y_B, z_B = B
x_C, y_C, z_C = C

Plane_A, = ax.plot(x_A, y_A, z_A, marker='o', markersize=5, color='g')
Plane_A.set_label('A position')
ax.legend()

Plane_B, = ax.plot(x_B, y_B, z_B, marker='o', markersize=5, color='cyan')
Plane_B.set_label('B position')
ax.legend()

Plane_C, = ax.plot(x_C, y_C, z_C, marker='o', markersize=5, color='crimson')
Plane_C.set_label('C position')
ax.legend()

# Plot normal.

dx_A, dy_A, dz_A = delta * N_A
ax.quiver(x_A, y_A, z_A, dx_A, dy_A, dz_A, arrow_length_ratio=0.15, linewidth=3, color='g')

dx_B, dy_B, dz_B = delta * N_B
ax.quiver(x_B, y_B, z_B, dx_B, dy_B, dz_B, arrow_length_ratio=0.15, linewidth=3, color='cyan')

dx_C, dy_C, dz_C = delta * N_C
ax.quiver(x_B, y_C, z_C, dx_C, dy_C, dz_C, arrow_length_ratio=0.15, linewidth=3, color='crimson')

# Enforce equal axis aspects so that the normal also appears to be normal.

ax.set_xlim(xmax=1500,xmin=-1500)
ax.set_ylim(ymax=400, ymin=-400)

zlim = max(A[2], B[2], C[2]) - delta, max(A[2], B[2], C[2]) + delta
ax.set_zlim(*zlim)

ax = plt.gca()

# ax.set_box_aspect([1,1,1])

set_axes_equal(ax)
ax.set_xlabel('X', fontsize=20)
ax.set_ylabel('Y', fontsize=20)
ax.set_zlabel('Z', fontsize=20)

plt.show()
bf1o4zei

bf1o4zei1#

元问题:下一次,

  • 解释你实际上在做什么(试图从卫星读数回归行星际电磁弓形冲击),否则这显然是一个x/y problem
  • 我花一些时间学习基本的向量微积分,这是不可避免的这类问题

不要丢弃现场读数中的震级。
尝试包含三个卫星点的曲面拟合在物理上是无效的。只有当在每个卫星上读取的星等 * 完全 * 相同时,曲面才适用,而您已经描述了它不是。磁场实际上是一个场:在时空中的所有点上都定义了方向的矢量场。
当您执行回归来建立向量场方向的估计值作为位置的函数时,您将不会有一个曲面。您将有 * 三个不同的等值面 *,每个等值面对应一个卫星,每个等值面都有不同的路径穿过场幅值为常数的空间。
不要在直线空间中进行计算。在极坐标空间中进行计算。单位法线有太多的自由度来进行回归(它们有三个自由度,而功能上它们只需要两个自由度)。
你需要很多很多的数据点来做有意义的回归。就目前而言,“你可以拟合任何东西”。所以下面的结果在数字上是准确的,但在物理上没有意义。
将系统解释为三个自变量(x,y,z)和两个因变量(θ和φ,单位法向转角)。这容易受到万向节锁定的影响,但我们在此忽略它。
在所有上述坏消息之后,好消息是,正如我们所理解的那样,这个系统是高度线性的(考虑到数据的贫乏,这并不奇怪)。您可以将拟合表示为线性矩阵变换:
第一个
因此,拟合基本上是完美的。上面的结果与梯度有关(虽然不等于)。要找到等值面--每个卫星一个等值面--你需要进行矢量积分。如果你不知道如何做,那么是时候在不同的社区(如物理或数学)进行研究了。

相关问题