0. 导入公共工具¶
In [1]:
Copied!
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",
Path("docs/reference-aircraft"),
]
for candidate in candidate_dirs:
if (candidate / "ttail_hale_utils.py").exists():
sys.path.insert(0, str(candidate.resolve()))
break
else:
raise FileNotFoundError("没有找到 ttail_hale_utils.py。请从仓库根目录或 docs/reference-aircraft 目录运行本 Notebook。")
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML, display
import ttail_hale_utils as hale
hale.configure_plots()
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",
Path("docs/reference-aircraft"),
]
for candidate in candidate_dirs:
if (candidate / "ttail_hale_utils.py").exists():
sys.path.insert(0, str(candidate.resolve()))
break
else:
raise FileNotFoundError("没有找到 ttail_hale_utils.py。请从仓库根目录或 docs/reference-aircraft 目录运行本 Notebook。")
import matplotlib.pyplot as plt
import numpy as np
from IPython.display import HTML, display
import ttail_hale_utils as hale
hale.configure_plots()
1. 生成模型并写入 trim 配置¶
这里的 flow 是:
BeamLoader -> AerogridLoader -> StaticTrim -> BeamLoads
StaticTrim 内部仍然会调用 StaticCoupled,但我们把输出集中在可解释的 trim 迭代表和最终构型上。
In [2]:
Copied!
case_dir = hale.prepare_hale_case("02_trim", force=True)
model = hale.read_model(case_dir)
trim_config = hale.write_solver_variant(
case_dir,
"ttail_hale_trim.sharpy",
["BeamLoader", "AerogridLoader", "StaticTrim", "BeamLoads"],
)
print("trim config:", trim_config)
display(HTML(hale.html_table(hale.control_surface_summary(model))))
case_dir = hale.prepare_hale_case("02_trim", force=True)
model = hale.read_model(case_dir)
trim_config = hale.write_solver_variant(
case_dir,
"ttail_hale_trim.sharpy",
["BeamLoader", "AerogridLoader", "StaticTrim", "BeamLoads"],
)
print("trim config:", trim_config)
display(HTML(hale.html_table(hale.control_surface_summary(model))))
trim config: _sharpy_runs/ttail_hale_reference_aircraft/02_trim/simple_HALE/ttail_hale_trim.sharpy
| control id | role | initial deflection [deg] | surfaces |
|---|---|---|---|
| 0 | elevator on horizontal tail | -2.0800 | right horizontal tail / elevator left horizontal tail / elevator |
| 1 | rudder on vertical fin | 0.0000 | vertical fin / rudder |
2. 运行 StaticTrim¶
求解器会调整迎角、升降舵偏角和推力,使纵向平衡残差收敛。下面保留最终数据对象,后面直接用它画 trim 后的气动网格。
In [3]:
Copied!
trim_data, trim_log = hale.run_solver(trim_config)
print("structure timesteps:", len(trim_data.structure.timestep_info))
print("aero timesteps:", len(trim_data.aero.timestep_info))
print("captured solver messages:", len(trim_log))
trim_data, trim_log = hale.run_solver(trim_config)
print("structure timesteps:", len(trim_data.structure.timestep_info))
print("aero timesteps:", len(trim_data.aero.timestep_info))
print("captured solver messages:", len(trim_log))
fatal: not a git repository (or any of the parent directories): .git
structure timesteps: 1 aero timesteps: 1 captured solver messages: 0
3. Trim 迭代表¶
trim_iterations.txt 中最重要的是三列残差:Fz、My、Fx。它们分别对应垂向力、俯仰力矩和轴向力/推力平衡。
In [4]:
Copied!
trim_rows = hale.trim_iterations(case_dir)
display(HTML(hale.html_table(trim_rows)))
hale.plot_trim_iterations(trim_rows)
final_trim = trim_rows[-1]
display(HTML(hale.html_table([final_trim])))
trim_rows = hale.trim_iterations(case_dir)
display(HTML(hale.html_table(trim_rows)))
hale.plot_trim_iterations(trim_rows)
final_trim = trim_rows[-1]
display(HTML(hale.html_table([final_trim])))
| iter | alpha[deg] | elev[deg] | thrust | Fx | Fy | Fz | Mx | My | Mz |
|---|---|---|---|---|---|---|---|---|---|
| 0.0000 | 4.3100 | -2.0800 | 6.1600 | -0.3600 | -0.0000 | 0.8011 | 0.0000 | -0.6942 | 0.0000 |
| 0.0000 | 7.1748 | -4.9448 | 6.1600 | -27.8570 | -0.0000 | 280.1531 | 0.0000 | -105.5365 | 0.0000 |
| 0.0000 | 4.3100 | 0.7848 | 6.1600 | -2.5530 | 0.0000 | 38.7843 | -0.0000 | -377.6456 | 0.0000 |
| 0.0000 | 4.3100 | -2.0800 | 8.1600 | -2.3600 | -0.0000 | 0.8011 | 0.0000 | -0.6942 | 0.0000 |
| 1.0000 | 4.3018 | -2.0771 | 5.8000 | 0.0660 | -0.0000 | -0.2783 | 0.0000 | 0.2441 | 0.0000 |
| 2.0000 | 4.3039 | -2.0778 | 5.8558 | -0.0068 | -0.0000 | 0.0003 | 0.0000 | 0.0006 | 0.0000 |
| iter | alpha[deg] | elev[deg] | thrust | Fx | Fy | Fz | Mx | My | Mz |
|---|---|---|---|---|---|---|---|---|---|
| 2.0000 | 4.3039 | -2.0778 | 5.8558 | -0.0068 | -0.0000 | 0.0003 | 0.0000 | 0.0006 | 0.0000 |
4. Trim 后三维构型¶
下面这张图使用 SHARPy 返回的 data.aero.timestep_info[-1].zeta 和 data.structure.timestep_info[-1].pos,不是重新画未变形输入文件。它代表 trim 求解之后的平衡构型。
In [5]:
Copied!
traces = hale.aircraft_traces_from_data(trim_data, timestep=-1, opacity=0.42, suffix=" (trim)")
hale.show_plotly(
traces,
"Trimmed T-Tail HALE: structural beam and aerodynamic grid",
camera={"eye": {"x": 1.55, "y": -1.9, "z": 0.85}},
)
traces = hale.aircraft_traces_from_data(trim_data, timestep=-1, opacity=0.42, suffix=" (trim)")
hale.show_plotly(
traces,
"Trimmed T-Tail HALE: structural beam and aerodynamic grid",
camera={"eye": {"x": 1.55, "y": -1.9, "z": 0.85}},
)
5. 最终载荷¶
下面把最后一个结构时间步的节点合力。
In [6]:
Copied!
ts = trim_data.structure.timestep_info[-1]
total_forces = hale.timestep_total_forces(ts)
force_row = {
"sum Fx": float(np.sum(total_forces[:, 0])),
"sum Fy": float(np.sum(total_forces[:, 1])),
"sum Fz": float(np.sum(total_forces[:, 2])),
"sum Mx": float(np.sum(total_forces[:, 3])),
"sum My": float(np.sum(total_forces[:, 4])),
"sum Mz": float(np.sum(total_forces[:, 5])),
}
display(HTML(hale.html_table([force_row])))
ts = trim_data.structure.timestep_info[-1]
total_forces = hale.timestep_total_forces(ts)
force_row = {
"sum Fx": float(np.sum(total_forces[:, 0])),
"sum Fy": float(np.sum(total_forces[:, 1])),
"sum Fz": float(np.sum(total_forces[:, 2])),
"sum Mx": float(np.sum(total_forces[:, 3])),
"sum My": float(np.sum(total_forces[:, 4])),
"sum Mz": float(np.sum(total_forces[:, 5])),
}
display(HTML(hale.html_table([force_row])))
| sum Fx | sum Fy | sum Fz | sum Mx | sum My | sum Mz |
|---|---|---|---|---|---|
| 53.2635 | 7.8311 | 50.1438 | 1.3412 | 0.1262 | -0.2752 |