当前位置: 首页 > article >正文

2024高教社杯全国大学生数学建模竞赛(A题)深度剖析 _ 建模完整过程+详细思路+代码全解析

问题1解答过程

1.1 螺线运动的基本几何模型

板凳龙的舞动路径为等距螺线。螺线是极坐标中一类常见曲线,其特点是半径随角度线性增加。我们可以用以下极坐标方程描述这条螺线:

r ( θ ) = p 2 π θ r(\theta) = \frac{p}{2\pi} \theta r(θ)=2πpθ

其中, r ( θ ) r(\theta) r(θ) 是螺线在角度 θ \theta θ 处的半径, p p p 是螺线的螺距。题目中给定螺距为 p = 55 p = 55 p=55 cm。螺线盘入从外向内进行,龙头最初位于螺线第16圈,这意味着起始位置对应的角度为 θ 0 = 16 × 2 π = 32 π \theta_0 = 16 \times 2\pi = 32\pi θ0=16×2π=32π

在极坐标中,龙头的运动路径需要转换为直角坐标表示,以便描述每个时刻的具体位置。极坐标到直角坐标的转换公式如下:

x ( θ ) = r ( θ ) cos ⁡ ( θ ) = p 2 π θ cos ⁡ ( θ ) x(\theta) = r(\theta) \cos(\theta) = \frac{p}{2\pi} \theta \cos(\theta) x(θ)=r(θ)cos(θ)=2πpθcos(θ)

y ( θ ) = r ( θ ) sin ⁡ ( θ ) = p 2 π θ sin ⁡ ( θ ) y(\theta) = r(\theta) \sin(\theta) = \frac{p}{2\pi} \theta \sin(\theta) y(θ)=r(θ)sin(θ)=2πpθsin(θ)

1.2 运动速度与角速度的关系

龙头沿螺线运动的速度 v v v 是一个已知常量,即 v = 1 v = 1 v=1 m/s。在极坐标中,线速度 v v v 和角速度 ω \omega ω 的关系为:

v = r ( θ ) ⋅ d θ d t v = r(\theta) \cdot \frac{d\theta}{dt} v=r(θ)dtdθ

由此可以得到角速度 ω \omega ω

d θ d t = v r ( θ ) = 1 p 2 π θ = 2 π p θ \frac{d\theta}{dt} = \frac{v}{r(\theta)} = \frac{1}{\frac{p}{2\pi} \theta} = \frac{2\pi}{p \theta} dtdθ=r(θ)v=2πpθ1=2π

该微分方程描述了角速度随时间的变化关系。通过分离变量并对时间 t t t 进行积分,得到角度 θ ( t ) \theta(t) θ(t) 随时间的变化:

∫ θ   d θ = ∫ 2 π p   d t \int \theta \, d\theta = \int \frac{2\pi}{p} \, dt θdθ=p2πdt

积分后得到:

θ 2 ( t ) = 4 π t p + θ 0 2 \theta^2(t) = \frac{4\pi t}{p} + \theta_0^2 θ2(t)=p4πt+θ02

即角度随时间的变化公式为:

θ ( t ) = 4 π t p + θ 0 2 \theta(t) = \sqrt{\frac{4\pi t}{p} + \theta_0^2} θ(t)=p4πt+θ02

其中,初始角度 θ 0 = 32 π \theta_0 = 32\pi θ0=32π。这个方程能够精确描述龙头在每个时间 t t t 时的角度位置。

1.3 龙头的空间位置和速度

有了角度随时间变化的公式,我们可以进一步计算龙头的具体位置。将 θ ( t ) \theta(t) θ(t) 代入前述极坐标到直角坐标的转换公式,得到龙头在每个时刻的直角坐标位置:

x ( t ) = p 2 π θ ( t ) cos ⁡ ( θ ( t ) ) x(t) = \frac{p}{2\pi} \theta(t) \cos(\theta(t)) x(t)=2πpθ(t)cos(θ(t))

y ( t ) = p 2 π θ ( t ) sin ⁡ ( θ ( t ) ) y(t) = \frac{p}{2\pi} \theta(t) \sin(\theta(t)) y(t)=2πpθ(t)sin(θ(t))

同时,龙头的速度不仅仅是线速度,它还包含了沿螺线运动的切向速度和法向速度。由速度的极坐标分解公式,我们可以计算出龙头的速度向量:

v r = d r d t = p 2 π d θ d t v_r = \frac{dr}{dt} = \frac{p}{2\pi} \frac{d\theta}{dt} vr=dtdr=2πpdtdθ

v θ = r ( θ ) ⋅ d θ d t v_\theta = r(\theta) \cdot \frac{d\theta}{dt} vθ=r(θ)dtdθ

通过几何合成,龙头的总速度大小可以表示为:

v total = v r 2 + v θ 2 v_{\text{total}} = \sqrt{v_r^2 + v_\theta^2} vtotal=vr2+vθ2

由于题目规定龙头的线速度为1 m/s,因此切向速度占主导地位。

1.4 龙身和龙尾的运动描述

接下来,我们考虑龙身和龙尾各节板凳的运动。每节板凳的长度已知,其中龙头的板凳长为341 cm,龙身和龙尾的板凳长均为220 cm。我们可以利用这种长度关系,通过逐步迭代的方法确定龙身和龙尾每节板凳的具体位置。

假设第 n n n 节板凳的前把手中心位于极角 θ n ( t ) \theta_n(t) θn(t) 处,前一节板凳的极角为 θ n − 1 ( t ) \theta_{n-1}(t) θn1(t),则这两节板凳之间的距离约束条件为:

l n = ( r ( θ n − 1 ) − r ( θ n ) ) 2 + ( r ( θ n − 1 ) ⋅ θ n − 1 − r ( θ n ) ⋅ θ n ) 2 l_n = \sqrt{\left( r(\theta_{n-1}) - r(\theta_n) \right)^2 + \left( r(\theta_{n-1}) \cdot \theta_{n-1} - r(\theta_n) \cdot \theta_n \right)^2} ln=(r(θn1)r(θn))2+(r(θn1)θn1r(θn)θn)2

其中 l n l_n ln 为两节板凳的长度。通过这一约束,可以逐步推算出每节板凳在每一时刻的极角 θ n ( t ) \theta_n(t) θn(t) 和位置坐标 x n ( t ) , y n ( t ) x_n(t), y_n(t) xn(t),yn(t)

由于龙身各节板凳之间的距离是固定的,因此每节板凳相对于龙头的位置也遵循一定的相对几何关系。龙尾的最后一节板凳需要考虑全队的长度和相对运动。

1.5 关键时刻的分析

根据问题的要求,我们需要记录0秒、60秒、120秒、180秒、240秒和300秒时,龙头和特定几节板凳的位置和速度。具体来说,龙头、龙身第1、51、101、151、201节板凳前把手和龙尾的后把手位置可以通过前述公式计算得出:

x n ( t ) = p 2 π θ n ( t ) cos ⁡ ( θ n ( t ) ) x_n(t) = \frac{p}{2\pi} \theta_n(t) \cos(\theta_n(t)) xn(t)=2πpθn(t)cos(θn(t))

y n ( t ) = p 2 π θ n ( t ) sin ⁡ ( θ n ( t ) ) y_n(t) = \frac{p}{2\pi} \theta_n(t) \sin(\theta_n(t)) yn(t)=2πpθn(t)sin(θn(t))

对于速度,切向速度和总速度分别为:

v n ( t ) = v r 2 + v θ 2 v_n(t) = \sqrt{v_r^2 + v_\theta^2} vn(t)=vr2+vθ2

所有这些信息都可以通过分析角速度、螺线几何关系和板凳相对位置来精确计算。最终的结果可以呈现为各节板凳在每个时间点的空间位置与速度。

python代码实现

import numpy as np
import pandas as pd

# 基本参数
p = 0.55  # 螺距(米)
v_head = 1.0  # 龙头行进速度(米/秒)
theta_0 = 32 * np.pi  # 初始角度(龙头位于第16圈)
dragon_lengths = [3.41] + [2.2] * 221 + [2.2]  # 每节板凳的长度(米)
times = np.arange(0, 301)  # 0秒到300秒的时间序列

# 极坐标下螺线方程
def theta_t(t):
    return np.sqrt(4 * np.pi * t / p + theta_0 ** 2)

# 计算龙头(第1节)的坐标
def polar_to_cartesian(theta):
    r = p * theta / (2 * np.pi)
    x = r * np.cos(theta)
    y = r * np.sin(theta)
    return x, y

# 计算每节板凳的位置,依次推算龙身、龙尾的位置
def compute_positions(t, dragon_lengths):
    theta_head = theta_t(t)
    x_head, y_head = polar_to_cartesian(theta_head)
    
    positions = [(x_head, y_head)]  # 龙头的位置
    theta_prev = theta_head
    x_prev, y_prev = x_head, y_head
    
    for length in dragon_lengths[1:]:
        # 假设每节板凳沿螺线均匀分布,使用长度约束计算位置
        delta_theta = length / p  # 每节板凳对应的角度差
        theta_curr = theta_prev - delta_theta  # 相邻板凳的极角
        x_curr, y_curr = polar_to_cartesian(theta_curr)
        
        positions.append((x_curr, y_curr))
        theta_prev, x_prev, y_prev = theta_curr, x_curr, y_curr
        
    return positions

# 计算每节板凳的速度
def compute_velocity(t):
    theta_t0 = theta_t(t)
    r_t0 = p * theta_t0 / (2 * np.pi)
    omega_t0 = 2 * np.pi / (p * theta_t0)  # 角速度
    v_r = 0  # 在螺线中,径向速度为0
    v_theta = r_t0 * omega_t0  # 切向速度
    
    return np.sqrt(v_r ** 2 + v_theta ** 2)

# 计算并保存结果到Excel
def save_to_excel(times, dragon_lengths):
    positions_list = []
    velocities_list = []
    
    for t in times:
        positions = compute_positions(t, dragon_lengths)
        velocities = [compute_velocity(t)] * len(dragon_lengths)
        
        positions_list.append(positions)
        velocities_list.append(velocities)
    
    # 将结果保存为Excel
    column_names = ['龙头x(m)', '龙头y(m)', '第1节龙身x(m)', '第1节龙身y(m)', 
                    '第51节龙身x(m)', '第51节龙身y(m)', '第101节龙身x(m)', '第101节龙身y(m)',
                    '第151节龙身x(m)', '第151节龙身y(m)', '第201节龙身x(m)', '第201节龙身y(m)', 
                    '龙尾(后)x(m)', '龙尾(后)y(m)']
    
    df_positions = pd.DataFrame(columns=column_names)
    df_velocities = pd.DataFrame(columns=['龙头(m/s)', '第1节龙身(m/s)', '第51节龙身(m/s)', 
                                          '第101节龙身(m/s)', '第151节龙身(m/s)', 
                                          '第201节龙身(m/s)', '龙尾(后)(m/s)'])
    
    for idx, t in enumerate(times):
        # 取出关键时刻的几个板凳位置:龙头,第1节,第51节,第101节,第151节,第201节,龙尾
        key_positions = [positions_list[idx][0], positions_list[idx][1], positions_list[idx][50], 
                         positions_list[idx][100], positions_list[idx][150], positions_list[idx][200], 
                         positions_list[idx][-1]]
        
        # 填充位置表
        df_positions.loc[t] = [coord for pos in key_positions for coord in pos]
        
        # 填充速度表
        df_velocities.loc[t] = [velocities_list[idx][0], velocities_list[idx][1], velocities_list[idx][50], 
                                velocities_list[idx][100], velocities_list[idx][150], velocities_list[idx][200], 
                                velocities_list[idx][-1]]
    
    # 保存到Excel文件
    with pd.ExcelWriter('result1.xlsx') as writer:
        df_positions.to_excel(writer, sheet_name='位置', index_label='时间(s)')
        df_velocities.to_excel(writer, sheet_name='速度', index_label='时间(s)')

# 执行并保存结果
save_to_excel(times, dragon_lengths)

问题2解答过程

本问题要求确定舞龙队在沿等距螺线盘入时,终止的时刻使得各节板凳之间不会发生碰撞。由于龙头始终以1m/s的速度沿着螺线盘入,板凳龙的整体行进可以理解为螺旋形收缩。在此过程中,随着板凳龙长度的限制,后续部分的盘入速度会逐渐减慢。我们的目标是确定一个时间点,此时舞龙队无法再继续向内盘入。

一、螺线盘入模型的建立

首先,我们依旧使用等距螺旋线的数学模型来描述舞龙队的路径。

  1. 螺线的极坐标方程
    螺旋线的极坐标方程可以表示为:

    r ( θ ) = p ⋅ θ 2 π r(\theta) = \frac{p \cdot \theta}{2 \pi} r(θ)=2πpθ

    其中, r r r 是半径, θ \theta θ 是极角,螺距 p = 0.55 p = 0.55 p=0.55 米。

    由上式可以看出,随着角度 θ \theta θ 增大,舞龙队的位置逐渐向螺线中心靠拢。

  2. 龙头速度与角速度的关系
    龙头的速度 v head v_{\text{head}} vhead 恒定为1 m/s。角速度 ω \omega ω 与径向速度 v r v_r vr 和切向速度 v θ v_{\theta} vθ 之间的关系为:

    v head = v θ = r ( θ ) ⋅ ω v_{\text{head}} = v_{\theta} = r(\theta) \cdot \omega vhead=vθ=r(θ)ω

    从而,角速度为:

    ω = v head r ( θ ) = 1 p ⋅ θ 2 π = 2 π p ⋅ θ \omega = \frac{v_{\text{head}}}{r(\theta)} = \frac{1}{\frac{p \cdot \theta}{2 \pi}} = \frac{2 \pi}{p \cdot \theta} ω=r(θ)vhead=2πpθ1=pθ2π

  3. 龙身和龙尾的动态分析
    每节板凳通过固定的把手间距连接在一起。在舞龙盘入过程中,后续的龙身与龙尾的运动受到前面的限制。特别地,随着螺线的收缩,龙尾距离龙头的位置也不断减少。

  4. 相邻板凳间的距离约束
    板凳之间的实际物理距离为:

    d = L + S d = L + S d=L+S

    其中, L L L 为板凳长度, S S S 为两把手之间的连接距离。对于龙头和龙身,板凳的总长度是固定的。若在某时刻,极角差 Δ θ \Delta \theta Δθ 满足:

    r ( θ n + 1 ) − r ( θ n ) ≤ L + S r(\theta_{n+1}) - r(\theta_n) \leq L + S r(θn+1)r(θn)L+S

    那么可以认为舞龙队接近了碰撞条件,此时无法再继续向内盘入。

二、板凳龙的盘入终止条件

1. 角度收缩与半径收缩

我们可以利用极坐标来描述每节板凳的运动。在某一时刻 t t t,板凳龙中相邻两节板凳的极角差为 Δ θ \Delta \theta Δθ,其对应的极径差为:

Δ r = r ( θ n + 1 ) − r ( θ n ) = p 2 π ⋅ ( θ n + 1 − θ n ) \Delta r = r(\theta_{n+1}) - r(\theta_n) = \frac{p}{2 \pi} \cdot (\theta_{n+1} - \theta_n) Δr=r(θn+1)r(θn)=2πp(θn+1θn)

根据板凳的物理长度 L L L 及连接间距 S S S,我们需要满足的约束为:

Δ r ≥ L + S \Delta r \geq L + S ΔrL+S

Δ r \Delta r Δr 小于 L + S L + S L+S,则表明两节板凳之间的距离过小,发生碰撞,舞龙队无法再继续盘入。

2. 计算盘入终止时刻

对于第 n n n 节板凳,其极角 θ n ( t ) \theta_n(t) θn(t) 在时间 t t t 时的变化速度与龙头角速度 ω \omega ω 有关。因为板凳龙整体沿螺线收缩,其后续板凳的速度会减小,导致相邻两节板凳的极角差不断减小。当某一时刻,这个极角差过小,两节板凳的极径差 Δ r \Delta r Δr 小于板凳长度时,即发生碰撞。

通过设定临界距离 d min = L + S d_{\text{min}} = L + S dmin=L+S,我们可以迭代计算每个时刻下各节板凳的位置与速度,直到发现某一时刻无法再满足距离条件,即为舞龙队的盘入终止时刻。

三、综合解法

  1. 初始条件设定:在初始时刻 t = 0 t = 0 t=0,龙头的极角为 θ head = 16 ⋅ 2 π \theta_{\text{head}} = 16 \cdot 2\pi θhead=162π,并从此处开始盘入。

  2. 每一时刻的迭代计算
    对于每一时刻 t t t,计算龙头和每节板凳的位置和速度,利用以下步骤:

    • 计算龙头的极角 θ head ( t ) \theta_{\text{head}}(t) θhead(t) 和极径 r head ( t ) r_{\text{head}}(t) rhead(t)
    • 依次计算每节板凳的位置 r ( θ n ) r(\theta_n) r(θn),通过板凳间的极角差 Δ θ \Delta \theta Δθ 计算相邻两节板凳的距离;
    • 若发现某一节板凳与其相邻板凳的极径差 Δ r \Delta r Δr 小于临界距离 L + S L + S L+S,则停止盘入。
  3. 输出终止时刻和位置速度数据
    记录舞龙队停止盘入的时间 t stop t_{\text{stop}} tstop,并输出此时刻下龙头及龙身各节板凳的位置和速度。

python代码实现

import numpy as np
import pandas as pd

# 板凳龙相关参数
p = 0.55  # 螺距,单位米
L_head = 3.41  # 龙头板长,单位米
L_body = 2.20  # 龙身和龙尾板长,单位米
S = 0.30  # 板凳宽(连接间距),单位米
v_head = 1.0  # 龙头速度,单位米/秒

# 初始参数
total_sections = 223  # 板凳总数
theta_initial = 16 * 2 * np.pi  # 初始龙头角度(16圈)
r_initial = (p * theta_initial) / (2 * np.pi)  # 初始龙头位置极径

# 时间步长和模拟时长
dt = 1  # 每步1秒
max_time = 1000  # 最大模拟时长,单位秒

# 龙身各板凳的初始状态(极角)
theta = np.zeros(total_sections)
r = np.zeros(total_sections)
v_theta = np.zeros(total_sections)

# 初始化龙头位置
theta[0] = theta_initial
r[0] = r_initial

# 计算其他板凳的初始位置
for i in range(1, total_sections):
    theta[i] = theta[i - 1] - (L_body + S) / r[i - 1]  # 每节板凳的极角递减
    r[i] = (p * theta[i]) / (2 * np.pi)

# 用于保存每一时刻的结果
results = []

# 迭代计算每一秒的运动
for t in range(max_time):
    # 更新龙头角度和位置
    theta[0] += v_head / r[0] * dt  # 根据角速度更新龙头极角
    r[0] = (p * theta[0]) / (2 * np.pi)  # 通过极角更新龙头极径
    
    # 依次更新每节龙身和龙尾的角度和位置
    for i in range(1, total_sections):
        # 计算当前板凳的角速度
        v_theta[i] = v_head / r[i - 1]  # 后续板凳的速度由前一节决定
        theta[i] = theta[i - 1] - (L_body + S) / r[i - 1]  # 更新板凳极角
        r[i] = (p * theta[i]) / (2 * np.pi)  # 更新板凳极径

    # 检查相邻板凳的距离
    collision_detected = False
    for i in range(1, total_sections):
        delta_r = r[i - 1] - r[i]  # 相邻板凳的极径差
        if delta_r < (L_body + S):
            collision_detected = True
            stop_time = t
            break

    # 保存每一时刻的位置和速度
    result = {
        'time': t,
        'head_x': r[0] * np.cos(theta[0]),
        'head_y': r[0] * np.sin(theta[0]),
        'tail_x': r[-1] * np.cos(theta[-1]),
        'tail_y': r[-1] * np.sin(theta[-1])
    }
    results.append(result)

    # 如果检测到碰撞,停止迭代
    if collision_detected:
        break

# 将结果保存到文件
df = pd.DataFrame(results)
df.to_excel('result2.xlsx', index=False)

# 输出终止时刻
print(f"舞龙队盘入终止时刻: {stop_time} 秒")

问题3解答过程

问题3要求确定最小螺距,使得龙头前把手能够沿着盘入螺线到达调头空间的边界,调头空间是一个直径为9米的圆形区域,位于螺线的中心。龙头的行进速度保持1 m/s,螺线的形状为等距螺旋线。

为了解决这个问题,我们需要利用螺线方程与几何约束条件,结合龙头的行进速度和螺距的关系,建立一个数学模型。目标是计算出螺距的最小值,使龙头能够在指定条件下盘入到调头空间的边界。

极坐标系下的螺旋线方程

螺旋线在极坐标系中的表达式为:

r ( θ ) = p ⋅ θ 2 π r(\theta) = \frac{p \cdot \theta}{2\pi} r(θ)=2πpθ

其中, r ( θ ) r(\theta) r(θ) 表示点在螺旋线上的极径, θ \theta θ 表示极角, p p p 是螺旋线的螺距。螺距 p p p 是沿径向方向相邻两圈之间的垂直距离。

条件约束

1. 螺旋线边界

调头空间是一个直径为9米的圆形区域。因此,调头空间的半径为:

r m i n = 9 2 = 4.5  m r_{min} = \frac{9}{2} = 4.5 \ \text{m} rmin=29=4.5 m

龙头必须沿螺旋线盘入到这个边界位置。换句话说,当龙头盘入到螺旋线的极径等于4.5米时,必须停止盘入并进入调头阶段。

2. 螺旋线长度与时间的关系

由于龙头的速度恒定为 v h e a d = 1  m/s v_{head} = 1 \ \text{m/s} vhead=1 m/s,行进的距离与时间之间呈线性关系。假设从螺旋线的起点盘入到调头空间的边界,龙头行进的总时间为 T T T,则龙头的总行进距离为 S S S,即:

S = v h e a d ⋅ T = T  m S = v_{head} \cdot T = T \ \text{m} S=vheadT=T m

螺旋线的长度可以通过积分计算得到。螺旋线的长度微元 d s ds ds 由极坐标下的微分方程给出:

d s = d r 2 + r 2 d θ 2 ds = \sqrt{dr^2 + r^2 d\theta^2} ds=dr2+r2dθ2

r ( θ ) r(\theta) r(θ) 代入得到:

d s = ( p 2 π ) 2 + r 2 d θ ds = \sqrt{\left(\frac{p}{2\pi}\right)^2 + r^2} d\theta ds=(2πp)2+r2 dθ

螺旋线的总长度 S S S 从起点到 r = 4.5  m r = 4.5 \ \text{m} r=4.5 m 处可以通过积分表示为:

S = ∫ 0 θ e n d ( p 2 π ) 2 + r ( θ ) 2 d θ S = \int_0^{\theta_{end}} \sqrt{\left(\frac{p}{2\pi}\right)^2 + r(\theta)^2} d\theta S=0θend(2πp)2+r(θ)2 dθ

其中, θ e n d \theta_{end} θend 是龙头盘入到极径为4.5米时的极角。此时,极径 r ( θ ) r(\theta) r(θ) 满足:

r ( θ e n d ) = p ⋅ θ e n d 2 π = 4.5 r(\theta_{end}) = \frac{p \cdot \theta_{end}}{2\pi} = 4.5 r(θend)=2πpθend=4.5

由此可解出终止时刻对应的极角 θ e n d \theta_{end} θend

θ e n d = 4.5 ⋅ 2 π p \theta_{end} = \frac{4.5 \cdot 2\pi}{p} θend=p4.52π

最小螺距的确定

要确定最小螺距 p m i n p_{min} pmin,我们需要结合龙头的行进距离和行进时间的约束条件。

龙头的行进距离约束

龙头的行进距离 S S S 应该等于从螺旋线起点到调头空间边界的螺旋线总长度。因此,有:

T = ∫ 0 θ e n d ( p 2 π ) 2 + ( p ⋅ θ 2 π ) 2 d θ T = \int_0^{\theta_{end}} \sqrt{\left(\frac{p}{2\pi}\right)^2 + \left(\frac{p \cdot \theta}{2\pi}\right)^2} d\theta T=0θend(2πp)2+(2πpθ)2 dθ

为了简化积分计算,我们可以将积分函数转化为更易处理的形式。首先,定义新的变量:

r 0 = p 2 π r_0 = \frac{p}{2\pi} r0=2πp

于是上式变为:

T = ∫ 0 θ e n d r 0 2 + ( p ⋅ θ 2 π ) 2 d θ T = \int_0^{\theta_{end}} \sqrt{r_0^2 + \left(\frac{p \cdot \theta}{2\pi}\right)^2} d\theta T=0θendr02+(2πpθ)2 dθ

这个积分方程的解可以使用椭圆积分或数值积分。

碰撞约束

最小螺距还必须满足另一个条件:保证板凳龙各节板凳之间不发生碰撞。相邻两节板凳的距离应大于等于板凳的长度加上连接距离 L b o d y + S L_{body} + S Lbody+S。假设螺距太小,螺旋线的曲率过大,板凳在弯道处的相对位置会靠得过近,导致碰撞。

因此,为了避免碰撞,螺距 p p p 必须大于某一临界值 p c r i t p_{crit} pcrit,由相邻板凳的几何约束给出。这个临界值可以通过板凳长度和螺旋线的曲率关系计算:

p c r i t = L b o d y + S cos ⁡ ( α ) p_{crit} = \frac{L_{body} + S}{\cos(\alpha)} pcrit=cos(α)Lbody+S

其中, α \alpha α 是螺线的局部切线角,可以通过螺线的几何微分计算得到。

结果总结

通过将螺距 p m i n p_{min} pmin 与碰撞条件下的临界螺距 p c r i t p_{crit} pcrit 结合起来,我们可以得出一个优化的最小螺距:

p = max ⁡ ( p m i n , p c r i t ) p = \max(p_{min}, p_{crit}) p=max(pmin,pcrit)

满足这个螺距的条件下,龙头可以安全地沿螺线盘入调头空间,并保证板凳龙各节之间不会发生碰撞。

python代码实现

import numpy as np
import scipy.integrate as integrate

# 板凳龙参数
r_turn = 4.5  # 调头空间的半径,单位:米
v_head = 1.0  # 龙头行进速度,单位:米/秒
L_body = 2.2  # 每节板凳长度,单位:米

# 定义螺旋线方程 r(θ)
def r_theta(p, theta):
    return (p * theta) / (2 * np.pi)

# 定义螺旋线的弧长微分方程
def ds_dtheta(p, theta):
    return np.sqrt((p / (2 * np.pi))**2 + r_theta(p, theta)**2)

# 计算螺旋线的总长度 S,从 θ=0 到 θ_end
def compute_spiral_length(p, theta_end):
    length, _ = integrate.quad(ds_dtheta, 0, theta_end, args=(p,))
    return length

# 计算终止时的角度 theta_end 对应 r(θ) = r_turn
def compute_theta_end(p, r_turn):
    return (2 * np.pi * r_turn) / p

# 计算碰撞约束下的临界螺距 p_crit
def compute_p_crit(L_body, safety_margin=0.1):
    # 这里我们假设在转弯处,螺线的切线角不应该过大,防止碰撞
    # 通过几何关系,我们需要使得螺距足够大,保持安全距离
    return L_body + safety_margin

# 定义最小螺距的求解函数
def find_min_pitch(L_body, r_turn, v_head, safety_margin=0.1):
    # 初步设置螺距范围
    p_crit = compute_p_crit(L_body, safety_margin)
    p_guess = p_crit  # 初始猜测为碰撞约束下的临界螺距

    # 迭代优化螺距,找到最小螺距
    tolerance = 1e-4
    step_size = 0.01
    while True:
        theta_end = compute_theta_end(p_guess, r_turn)
        spiral_length = compute_spiral_length(p_guess, theta_end)
        
        # 比较螺旋线的长度和龙头的总行进距离
        if abs(spiral_length - v_head * theta_end) < tolerance:
            break  # 找到最优解
        elif spiral_length < v_head * theta_end:
            p_guess += step_size  # 增大螺距
        else:
            p_guess -= step_size  # 减小螺距
    
    return p_guess

# 调用求解函数
min_pitch = find_min_pitch(L_body, r_turn, v_head)
print(f"最小螺距 p_min: {min_pitch:.4f} 米")

问题4解答过程

关键点:

  1. 螺线中心对称:盘出螺线与盘入螺线关于螺线中心呈中心对称。
  2. 调头曲线:调头区域内路径由两段圆弧相切形成 S 形曲线。
  3. 圆弧半径关系:前段圆弧半径是后一段圆弧的 2 倍。
  4. 相切条件:S 形曲线必须与盘入、盘出螺线相切。

为了解决此问题,需结合几何学和路径优化理论进行建模。

第一步:圆弧的几何关系建模

假设调头曲线由两段相切的圆弧构成,圆弧的半径分别为 R 1 R_1 R1 R 2 R_2 R2,且 R 1 = 2 R 2 R_1 = 2R_2 R1=2R2。调头曲线的总长度由这两个圆弧的长度和两者的连接点的几何关系决定。设这两个圆弧与盘入螺线和盘出螺线相切,曲线的起点和终点分别位于盘入和盘出的螺线上。

  1. 圆弧的几何公式

    • 对于一个圆弧,其弧长 L L L 可以表示为:

    L = R ⋅ θ L = R \cdot \theta L=Rθ

    其中, R R R 是圆弧的半径, θ \theta θ 是弧度制下圆弧的夹角。

  2. 两个圆弧的相切条件
    圆弧的相切条件表明,它们在切点处的切线斜率必须相同。假设第一个圆弧的起点在螺线的某一点上,其起始角度为 θ 1 \theta_1 θ1,结束角度为 θ 2 \theta_2 θ2,其与第二段圆弧的切点位置相同,意味着它们的几何切线在该点方向一致。

  3. 相切条件的几何表达
    对于两个相切圆弧,其在切点处的切线斜率相等意味着:

    d d θ ( R 1 ⋅ θ ) = d d θ ( R 2 ⋅ θ ) \frac{d}{d\theta}\left( R_1 \cdot \theta \right) = \frac{d}{d\theta}\left( R_2 \cdot \theta \right) dθd(R1θ)=dθd(R2θ)

    此外,结合 R 1 = 2 R 2 R_1 = 2R_2 R1=2R2 的关系,得出该条件的解析表达式,表明两段圆弧在几何上保持连续性。

第二步:S 形曲线的优化问题

为了最小化调头曲线的总长度,需要求解两段相切圆弧的最短路径。我们将其转换为经典的路径优化问题,通过优化弧长公式来找到最短的调头路径。

  1. 优化目标
    需要最小化调头曲线的总长度 L t o t a l L_{total} Ltotal,由两段圆弧的弧长和中间相切点的坐标约束构成:

    L t o t a l = L 1 + L 2 = R 1 ⋅ θ 1 + R 2 ⋅ θ 2 L_{total} = L_1 + L_2 = R_1 \cdot \theta_1 + R_2 \cdot \theta_2 Ltotal=L1+L2=R1θ1+R2θ2

    其中 θ 1 \theta_1 θ1 θ 2 \theta_2 θ2 分别是两段圆弧的角度,且满足 R 1 = 2 R 2 R_1 = 2R_2 R1=2R2

  2. 边界条件
    圆弧的起点和终点必须分别位于盘入和盘出的螺线上。假设盘入螺线和盘出螺线的螺距为 p i n p_{in} pin p o u t p_{out} pout,则圆弧的起点和终点可以通过螺旋线方程来表达:

    r i n ( θ ) = p i n ⋅ θ 2 π , r o u t ( θ ) = p o u t ⋅ θ 2 π r_{in}(\theta) = \frac{p_{in} \cdot \theta}{2\pi}, \quad r_{out}(\theta) = \frac{p_{out} \cdot \theta}{2\pi} rin(θ)=2πpinθ,rout(θ)=2πpoutθ

    起点和终点处的极径必须与圆弧的起始和结束半径相等,确保两条路径在螺线和圆弧之间的几何连续性。

  3. 约束条件
    为了确保调头曲线与螺线相切,我们需要在切点处的切线角度满足相切条件,即调头曲线在起点和终点处的切线斜率必须与螺旋线的切线一致。这种相切条件可以通过切线方向的导数来表示:

    d d θ ( R 1 ⋅ θ ) = p i n 2 π , d d θ ( R 2 ⋅ θ ) = p o u t 2 π \frac{d}{d\theta} \left( R_1 \cdot \theta \right) = \frac{p_{in}}{2\pi}, \quad \frac{d}{d\theta} \left( R_2 \cdot \theta \right) = \frac{p_{out}}{2\pi} dθd(R1θ)=2πpin,dθd(R2θ)=2πpout

    这些条件为曲线的几何连接提供了约束。

第三步:路径长度的数值优化

基于前面的几何关系和路径约束条件,我们可以将路径长度的优化问题转化为一个带有边界条件的数值优化问题。

  1. 最小化函数
    通过将路径长度公式代入优化目标,我们需要最小化调头路径的总长度:

    L t o t a l = ∫ θ i n θ o u t ( d r d θ ) 2 + r 2   d θ L_{total} = \int_{\theta_{in}}^{\theta_{out}} \sqrt{\left( \frac{dr}{d\theta} \right)^2 + r^2 } \, d\theta Ltotal=θinθout(dθdr)2+r2 dθ

    该公式为曲线弧长的经典计算公式,结合前述的几何约束条件,在两段圆弧上进行积分,求解最短路径。

  2. 数值解法
    利用拉格朗日乘数法或者直接的梯度下降法,可以对该最小化问题进行求解。通过数值方法优化 R 1 R_1 R1 θ 1 \theta_1 θ1 的取值,得到最短的调头曲线。

python代码实现

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import minimize

# 定义螺旋线函数
def spiral(theta, pitch):
    """计算螺旋线的极坐标 (r, theta),螺距为 pitch"""
    r = (pitch * theta) / (2 * np.pi)
    x = r * np.cos(theta)
    y = r * np.sin(theta)
    return x, y

# 定义圆弧曲线函数
def arc(theta, radius, theta_start):
    """计算圆弧的 (x, y) 坐标"""
    x = radius * np.cos(theta_start + theta)
    y = radius * np.sin(theta_start + theta)
    return x, y

# 定义路径长度计算函数
def path_length(params):
    """计算调头路径的总长度"""
    R1, R2, theta1, theta2 = params  # 两段圆弧的半径和角度
    # 第一段圆弧的长度
    L1 = R1 * theta1
    # 第二段圆弧的长度
    L2 = R2 * theta2
    return L1 + L2

# 定义目标函数用于优化
def objective(params):
    """目标函数,最小化总路径长度"""
    return path_length(params)

# 定义相切约束条件
def tangent_condition(params):
    """相切约束条件,确保两段圆弧在连接点处相切"""
    R1, R2, theta1, theta2 = params
    return R1 - 2 * R2  # R1 和 R2 的关系是 R1 = 2 * R2

# 初始参数 [R1, R2, theta1, theta2]
initial_params = [5.0, 2.5, np.pi / 2, np.pi / 2]

# 定义约束
constraints = ({'type': 'eq', 'fun': tangent_condition})

# 优化调头路径
result = minimize(objective, initial_params, constraints=constraints)

# 获取优化结果
R1_opt, R2_opt, theta1_opt, theta2_opt = result.x

print(f"最优圆弧参数:R1 = {R1_opt}, R2 = {R2_opt}, theta1 = {theta1_opt}, theta2 = {theta2_opt}")

# 生成螺旋线数据(盘入螺线和盘出螺线)
theta_values_in = np.linspace(0, 4 * np.pi, 100)
theta_values_out = np.linspace(0, 4 * np.pi, 100)

# 定义螺距
pitch_in = 1.7
pitch_out = 1.7

x_in, y_in = spiral(theta_values_in, pitch_in)
x_out, y_out = spiral(theta_values_out, pitch_out)

# 生成圆弧数据
theta_arc1 = np.linspace(0, theta1_opt, 50)
theta_arc2 = np.linspace(0, theta2_opt, 50)

x_arc1, y_arc1 = arc(theta_arc1, R1_opt, 0)
x_arc2, y_arc2 = arc(theta_arc2, R2_opt, theta1_opt)

# 绘制结果
plt.figure(figsize=(8, 8))
plt.plot(x_in, y_in, label="盘入螺线", color='blue')
plt.plot(x_out, y_out, label="盘出螺线", color='green')
plt.plot(x_arc1, y_arc1, label="调头曲线(第一段圆弧)", color='red')
plt.plot(x_arc2, y_arc2, label="调头曲线(第二段圆弧)", color='orange')

plt.legend()
plt.xlabel('x 坐标')
plt.ylabel('y 坐标')
plt.title('最优调头路径示意图')
plt.grid(True)
plt.axis('equal')
plt.show()

查看完整思路详见:
【腾讯文档】2024高教社杯全国大学生数学建模竞赛全题目深度解析(建模过程+代码实现+论文指导)
https://docs.qq.com/doc/DSGdreXpIYlN2RUlZ


http://www.kler.cn/a/293004.html

相关文章:

  • ubuntu连接orangepi-zero-2w桌面的几种方法
  • uniCloud云对象调用第三方接口,根据IP获取用户归属地的免费API接口,亲测可用
  • 探索Pillow库:Python图像处理的瑞士军刀
  • 在linux中使用nload实时查看网卡流量
  • -1大于4?负数与无符号整数类型:size_t的比较问题(strlen)
  • MySQL数据库:SQL语言入门 【上】(学习笔记)
  • Quartz.Net_依赖注入
  • GitHub Copilot的详细介绍
  • RHCE必过技巧,无需本人参加也可拿证?
  • 紫光展锐完成Android 15同步升级,驱动技术创新与生态共赢
  • 【区块链 + 人才服务】紫金研究院知识库管理系统 | FISCO BCOS应用案例
  • GAMES101(0~1作业)
  • django企业开发实战-学习小结1
  • hiprint打印/jsPDF使用/html2canvas
  • 本地使用Docker部署Nexus Maven私有仓库工具结合内网穿透实现远程管理
  • AI学习记录 - 旋转位置编码
  • python爬虫教学(四) Bs4
  • 最新版本是 FL Studio 的 24.1.1.4285 2024/08/07发布
  • 【2024数模国赛赛题思路公开】国赛C题第二套思路丨附可运行代码丨无偿自提
  • VS2022如何安装Spy+
  • ansible实战自动化运维项目
  • 优化 Webpack 打包体积的思路
  • vue3 uni app端使用uCharts
  • 华为鸿蒙系统和安卓的区别
  • java后端框架
  • 【Python机器学习】NLP词频背后的含义——反馈及改进