uCRM-9 01:SHARPy 全机模型生成与可视化¶
这篇 Notebook 读取仓库中的 uCRM-9 低保真生成器,生成 .fem.h5、.aero.h5 和 .sharpy,然后把柔性主翼梁、近刚性机身/尾翼梁、UVLM 面以及控制面叠加显示出来。这里检查的是 SHARPy 模型骨架,不是 CAD 外形。
学习目标与路线¶
适合已经能够运行 SHARPy、希望理解全机梁—UVLM 模型输入的读者。运行前需要激活安装了 SHARPy、NumPy、Matplotlib、h5py 和 IPython 的环境。
完成后应能:
- 从生成器得到可复现的 uCRM-9 HDF5 输入;
- 核对结构梁、气动面、舵面和发动机质量点的编号;
- 在三维图中区分完整结构骨架与 5 个 UVLM 面;
- 查看主翼弦长、扭转、弹性轴和刚度的公开数据分布。
0. 导入公共工具¶
import os
import sys
from pathlib import Path
os.environ.setdefault("MPLCONFIGDIR", str(Path("_sharpy_runs") / ".mplconfig"))
candidate_dirs = [
Path.cwd(),
Path.cwd() / "docs" / "reference-aircraft" / "ucrm9",
Path("docs/reference-aircraft/ucrm9"),
]
for candidate in candidate_dirs:
if (candidate / "ucrm9_utils.py").exists():
sys.path.insert(0, str(candidate.resolve()))
break
else:
raise FileNotFoundError(
"没有找到 ucrm9_utils.py。请从仓库根目录或 docs/reference-aircraft/ucrm9 目录运行本 Notebook。"
)
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML, display
import ucrm9_utils as ucrm9
ucrm9.configure_plots()
generator = ucrm9.load_generator()
Matplotlib is building the font cache; this may take a moment.
1. 生成并读取 uCRM-9 输入文件¶
生成器把公开的 uCRM-9 主翼几何、弹性轴、等效弯曲/扭转刚度和 21 个翼型剖面写成 SHARPy 输入。机身和平、垂尾使用有限高刚度梁;发动机用两个集中质量点表示。
所有运行文件写到 _sharpy_runs/,不会污染 models/ucrm9/ 下的源数据。
FORCE_REGENERATE = True
case_dir = ucrm9.prepare_case("notebook_visualization", force=FORCE_REGENERATE)
model = ucrm9.read_model(case_dir)
print("case directory:", case_dir)
for suffix in [".fem.h5", ".aero.h5", ".sharpy", ".model.json"]:
file_path = case_dir / f"{ucrm9.CASE_NAME}{suffix}"
print(file_path.name, "exists:", file_path.exists(), "size:", file_path.stat().st_size)
case directory: /Users/raiot/Documents/Programing/Steps-to-Aeroelastic-Sim/_sharpy_runs/ucrm9_full_aircraft/notebook_visualization ucrm9_full_aircraft.fem.h5 exists: True size: 61672 ucrm9_full_aircraft.aero.h5 exists: True size: 96719 ucrm9_full_aircraft.sharpy exists: True size: 3088 ucrm9_full_aircraft.model.json exists: True size: 1027
2. 模型清单与质量核对¶
模型共有 5 个气动面:左右主翼、左右平尾和垂尾。控制面 0 是升降舵,控制面 1 是方向舵。质量表按梁单元弧长积分线质量,并叠加两个发动机集中质量。
display(HTML(ucrm9.html_table(ucrm9.surface_summary(model))))
display(HTML(ucrm9.html_table(ucrm9.control_surface_summary(model))))
display(HTML(ucrm9.html_table(ucrm9.mass_summary(model))))
display(HTML(ucrm9.html_table(ucrm9.model_checks(model))))
| surface id | name | chordwise panels | span/y range [m] | height/z range [m] | control |
|---|---|---|---|---|---|
| 0 | right main wing | 8 | 26.4420 | 0.9394 | - |
| 1 | left main wing | 8 | 26.4420 | 0.9394 | - |
| 2 | right horizontal tail / elevator | 4 | 10.8000 | 0.9449 | elevator |
| 3 | left horizontal tail / elevator | 4 | 10.8000 | 0.9449 | elevator |
| 4 | vertical tail / rudder | 4 | 0.0000 | 10.5000 | rudder |
| control id | role | initial deflection [deg] | surfaces |
|---|---|---|---|
| 0 | elevator | 0.0000 | right horizontal tail / elevator left horizontal tail / elevator |
| 1 | rudder | 0.0000 | vertical tail / rudder |
| component | mass [kg] |
|---|---|
| main wings | 29895.0000 |
| fuselage | 105806.0000 |
| empennage | 5806.0000 |
| engine lumped masses | 15786.0000 |
| estimated total | 157293.0000 |
| check | passed |
|---|---|
| five aerodynamic surfaces | yes |
| elevator and rudder | yes |
| quadratic beam-tree node count | yes |
| one clamped reference node | yes |
| finite structural coordinates | yes |
| positive aerodynamic chords | yes |
3. 完整结构骨架¶
先只看梁和关键节点。蓝色是左右柔性主翼,灰色是机身,青色是平尾,紫色是垂尾。两个红色标记是发动机集中质量/推力节点。这样可以直接确认模型不是一片孤立机翼,而是以机身参考节点连接的完整飞机树形结构。
structure_traces = ucrm9.beam_traces_from_model(model)
engine_node_ids = [
model["metadata"]["node_ids"]["right_engine_node"],
model["metadata"]["node_ids"]["left_engine_node"],
]
engine_points = model["fem"]["coordinates"][engine_node_ids]
structure_traces.append(
ucrm9.label_trace(engine_points, ["right engine mass", "left engine mass"])
)
ucrm9.show_plotly(
structure_traces,
"uCRM-9 structural skeleton: flexible wings, rigid-body beams and engine nodes",
camera={"eye": {"x": 1.55, "y": -1.85, "z": 0.82}},
)
4. 梁、UVLM 面和控制面叠加¶
下面把 5 个 UVLM 面覆盖到结构骨架上。橙色区域是平尾升降舵,红色区域是垂尾方向舵。半透明面板显示的是 SHARPy 气动网格,而不是封闭实体表面。
traces = ucrm9.aircraft_traces_from_model(model, show_controls=True)
label_points, labels = ucrm9.aircraft_label_points(model)
traces.append(ucrm9.label_trace(label_points, labels))
ucrm9.show_plotly(
traces,
"uCRM-9 SHARPy model: beams, five UVLM surfaces and control regions",
camera={"eye": {"x": 1.55, "y": -1.95, "z": 0.92}},
)
5. 主翼公开数据的沿展向分布¶
SHARPy 主翼梁不是任意设定的等截面梁。生成器直接插值 Taylor 与 Hunsaker 给出的 uCRM-9 表格数据:弦长和扭转来自 Table A1,弹性轴、垂向弯曲刚度和扭转刚度来自 Table A8。
xi = np.linspace(0.0, 1.0, 301)
chord = np.interp(xi, generator.UCRM_XI, generator.UCRM_CHORD)
twist_deg = np.interp(xi, generator.UCRM_XI, generator.UCRM_TWIST_DEG)
elastic_axis = np.interp(xi, generator.A8_XI, generator.A8_ELASTIC_AXIS)
ei = np.interp(xi, generator.A8_XI, generator.A8_EI)
gj = np.interp(xi, generator.A8_XI, generator.A8_GJ)
fig, axes = plt.subplots(2, 2, figsize=(10.5, 6.2), sharex=True)
axes[0, 0].plot(xi, chord, color=ucrm9.COLORS["blue"])
axes[0, 0].scatter(generator.UCRM_XI, generator.UCRM_CHORD, s=14, color=ucrm9.COLORS["dark"])
axes[0, 0].set_ylabel("chord [m]")
axes[0, 0].set_title("Chord", loc="left")
axes[0, 1].plot(xi, twist_deg, color=ucrm9.COLORS["orange"])
axes[0, 1].scatter(generator.UCRM_XI, generator.UCRM_TWIST_DEG, s=14, color=ucrm9.COLORS["dark"])
axes[0, 1].set_ylabel("twist [deg]")
axes[0, 1].set_title("Jig twist", loc="left")
axes[1, 0].plot(xi, elastic_axis, color=ucrm9.COLORS["teal"])
axes[1, 0].scatter(generator.A8_XI, generator.A8_ELASTIC_AXIS, s=10, color=ucrm9.COLORS["dark"])
axes[1, 0].set_xlabel("semispan ratio, xi")
axes[1, 0].set_ylabel("elastic axis / chord")
axes[1, 0].set_title("Elastic-axis location", loc="left")
axes[1, 1].semilogy(xi, ei, label="vertical bending EI", color=ucrm9.COLORS["purple"])
axes[1, 1].semilogy(xi, gj, label="torsional GJ", color=ucrm9.COLORS["red"])
axes[1, 1].set_xlabel("semispan ratio, xi")
axes[1, 1].set_ylabel("rigidity [N m²]")
axes[1, 1].set_title("Equivalent wing rigidities", loc="left")
axes[1, 1].legend()
for ax in axes.flat:
ax.grid(True, color=ucrm9.COLORS["light_grey"], linewidth=0.6)
ax.set_xlim(0.0, 1.0)
ucrm9.finish_figure(fig)
6. 结果怎么理解¶
- 主翼采用公开 uCRM-9 外形和等效刚度,因此是模型中真正的柔性部件。
- 机身和平、垂尾的主要作用是形成全机连接、质量和控制面拓扑;它们目前不是高保真结构降阶结果。
- UVLM 使用弯度线、弦长、弹性轴和扭转生成面板,不需要 STEP 或封闭实体。
- 当前基线已经通过加载、模态、纯气动和静气动弹性耦合冒烟测试;默认配平初值仍需要后续校准。
常见错误是把半透明 UVLM 面理解为 CAD 蒙皮,或者只看气动面而忽略灰色机身梁。判断模型是否“全机”,应同时核对梁连接、surface_id、控制面和集中质量节点。
7. 小练习:改变视角并隐藏控制面¶
把 SHOW_CONTROLS 改为 True/False,比较尾翼区域是否出现橙色升降舵和红色方向舵;再修改 CAMERA 的三个数值,观察后掠主翼、平尾和垂尾的相对位置。
SHOW_CONTROLS = False
CAMERA = {"eye": {"x": 0.15, "y": -2.25, "z": 1.35}}
exercise_traces = ucrm9.aircraft_traces_from_model(model, show_controls=SHOW_CONTROLS)
ucrm9.show_plotly(
exercise_traces,
f"Exercise view: show_controls={SHOW_CONTROLS}",
height=580,
camera=CAMERA,
)
后续扩展¶
下一步可以把 StaticCoupled 的变形后节点和 zeta 网格叠加到这里,用同一套颜色对比未变形/变形构型;也可以在配平参数完成校准后增加迎角、升降舵偏角和推力的收敛过程。