前几天看到了,不过这几天很忙没时间回,今天有点时间我仔细看了一下。首先我觉得楼主在推力与总冲的计算上是没有问题的,用了一些近似,认为喷嘴面积远小于内部截面积。如果要考虑喷嘴面积,那么火箭加速度会带来一...
感谢您的回复和鼓励,看到之后我也是思考了几天,在这里想和您讨论一下(望多多包涵)。首先我看了一下您对于软件积分的计算方法,又对比了一下我汉化的代码。由于我当时在AI帮助下选择了一种简单易行的方法,也方便我理解,因为诚然我没有高数基础,所以导致并不是很精密的推算。我发的软件中使用的矩形积分,您的中是梯形积分,精度会更高,让Grok看了一下,改一个函数就行。
这是汉化代码
import math
import tkinter as tk
from tkinter import ttk
from tkinter import filedialog
from tkinter import messagebox
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import matplotlib.pyplot as plt
import matplotlib.pyplot
# 设置中文字体(以黑体为例,可根据系统字体调整)
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'WenQuanYi Micro Hei']
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示异常
# 常量声明
delta_t = 0.0001
P_atm = float(1*101325)
# 仿真输出数据
array_time = []
array_h = []
array_Ft = []
array_mass = []
array_temperature = []
array_pressure = []
array_V_water = []
array_V_air = []
# 优化输出数据
array_opt_x = []
array_opt_Ic = []
array_opt_tc = []
array_opt_delta_v = []
array_opt_Ist = []
opt_variable_name = ""
# 导出数据
engine_name = ""
engine_diameter = 0
engine_lenght = 0
engine_dry_mass = 0
engine_full_mass = 0
engine_manufacturer = ""
# 效率数据
efficiency_sim_rod = 1
efficiency_sim_water = 1
efficiency_sim_gas = 1
efficiency_opt_rod = 1
efficiency_opt_water = 1
efficiency_opt_gas = 1
# 用于优化的仿真函数
def opt_sim(k_const, Rs, water_density, P_ins, At, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter):
try:
# 局部输出变量声明
Ic = float(0)
max_h = float(0)
total_time = float(0)
delta_v = float(0)
# 局部仿真变量
s = float(0.0)
vrod = float(0.0)
# 考虑导向杆的存在修正初始空气体积
V_air = V_air - At * rod_lenght
# 定义绝热常数
C_const = P_ins * pow(V_air, k_const)
# 计算空气质量
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
total_time = 0
if(rod_inside_diameter > 0 and rod_lenght > 0):
while(s < rod_lenght):
# 更新时间
total_time = total_time + delta_t
# 计算推力和冲量
Ft = P_ins * At * efficiency_opt_rod
# 更新冲量
Ic += Ft * delta_t
arod = Ft / Roc_mass
vrod += delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
if(rod_inside_diameter == 0 and rod_lenght > 0):
while(s < rod_lenght):
total_time = total_time + delta_t
# 计算推力和冲量
Ft = P_ins * At * efficiency_opt_rod
Ic += Ft * delta_t
arod = Ft / Roc_mass
vrod += delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
delta_V = At * vrod * delta_t
V_air += delta_V
P_ins = C_const / pow(V_air, k_const)
T = (P_ins * V_air) / (mass_air * Rs)
# 水喷出阶段循环
while(float(V_water) > float(0) and float(P_ins) > float(P_atm)):
total_time = total_time + delta_t
# 计算推力
Ft = 2 * At * (P_ins - P_atm) * efficiency_opt_water
Ic += Ft * delta_t
ve = math.sqrt(2 * (P_ins - P_atm) / water_density)
# 计算体积变化
delta_V = At * ve * delta_t
# 计算温度
T = P_ins * V_air / (mass_air * Rs)
# 更新质量
Roc_mass = Roc_mass - delta_V * water_density
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
# 更新体积值
V_air = V_air + delta_V
V_water = V_water - delta_V
# 计算压力
P_ins = C_const * pow(V_air, -k_const)
# 马赫数1的排气阶段
while(P_ins > P_atm and P_ins/P_atm >= pow((k_const+1)/2, k_const/(k_const-1))):
total_time = total_time + delta_t
Tt = T * 2 / (k_const + 1)
dot_m = P_ins * At * pow(2/(k_const+1), 0.5 * (k_const+1)/(k_const-1)) * math.sqrt(k_const/(Rs*T))
ve_air = math.sqrt(k_const * Rs * Tt)
P_throat = pow(2 / (k_const + 1), k_const / (k_const - 1)) * P_ins
Ft = (dot_m * ve_air + At * (P_throat - P_atm)) * efficiency_opt_gas
Ic += Ft * delta_t
delta_m = dot_m * delta_t
# 更新火箭质量
Roc_mass = Roc_mass - delta_m
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
P_ins = mass_air * Rs * T / V_air
# 亚音速排气阶段
while(P_ins > P_atm):
total_time = total_time + delta_t
Mach = math.sqrt(2 / (k_const-1) * (pow(P_ins / P_atm, (k_const-1) / k_const) - 1))
Tt = T / (1 + 0.5 * (k_const-1) * Mach * Mach)
ve_air = Mach * math.sqrt(k_const * Rs * Tt)
density_chamber = mass_air / V_air
density_throat = density_chamber / pow(1 + 0.5 * (k_const - 1) * Mach * Mach, 1 / (k_const-1))
dot_m = At * density_throat * ve_air
Ft = dot_m * ve_air * efficiency_opt_gas
Ic += Ft * delta_t
delta_m = dot_m * delta_t
# 更新火箭质量
Roc_mass = Roc_mass - delta_m
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
P_ins = mass_air * Rs * T / V_air
return [Ic, total_time, Ic / (mass_propelant * 9.81), delta_v]
except ValueError:
error_label_r.config(text="输入无效。")
# 主优化函数
def optimalize():
global opt_variable_name
array_opt_x.clear()
array_opt_Ic.clear()
array_opt_tc.clear()
array_opt_delta_v.clear()
array_opt_Ist.clear()
gas_name = choosen_gas_opt.get()
if(gas_name == "空气"):
k_const = 1.4
Rs = 287
if(gas_name == "氩气"):
k_const = 1.67
Rs = 208
if(gas_name == "氦气"):
k_const = 1.66
Rs = 2077
if(gas_name == "氢气"):
k_const = 1.41
Rs = 4124
if(gas_name == "氮气"):
k_const = 1.4
Rs = 297
if(gas_name == "二氧化碳"):
k_const = 1.3
Rs = 188
if(gas_name == "氙气"):
k_const = 1.65
Rs = 208
try:
if(gas_name == "自定义"):
k_const = float(entry_combobox1_opt.get())
Rs = float(entry_combobox2_opt.get())
water_density = float(entry_6_r.get())
# 读取输入值
P_ins = float(entry_0_r.get())*100000
At = 3.1415*pow(0.001*float(entry_1_r.get())/2, 2)
V_total = float(entry_2_r.get())*0.001
water_content = float(entry_3_r.get()) * 0.01
V_air = float(V_total - water_content * V_total)
V_water = float(water_content * V_total)
dry_mass = float(entry_4_r.get())
T = float(entry_5_r.get())+273.15
rod_lenght = float(entry_launch_lenght_opt.get()) * 0.001
rod_inside_diameter = float(entry_launch_diameter_opt.get()) * 0.001
# 错误保护
if(P_ins <= 0):
raise ValueError
if(k_const <= 0):
raise ValueError
if(Rs <= 0):
raise ValueError
if(water_density <= 0):
raise ValueError
if(At <= 0):
raise ValueError
if(V_total <= 0):
raise ValueError
if(water_content < 0 or water_content >= 1):
raise ValueError
if(dry_mass <= 0):
raise ValueError
if(T <= 0):
raise ValueError
if(rod_inside_diameter < 0):
raise ValueError
if(rod_lenght < 0):
raise ValueError
if(rod_inside_diameter > 0.001 * float(entry_1_r.get())):
raise ValueError
s = float(0.0)
vrod = float(0.0)
# 考虑导向杆的存在修正初始空气体积
V_air = V_air - At * rod_lenght
# 定义绝热常数
C_const = P_ins * pow(V_air, k_const)
# 计算空气质量
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
# 获取优化变量
opt_var = choosen_opt_variable.get()
opt_range_min = float(entry_opt_min.get())
opt_range_max = float(entry_opt_max.get())
opt_it = int(entry_opt_itteration.get())
# 优化变量错误保护
if(opt_range_max <= opt_range_min):
raise ValueError
if(opt_var == "含水量"):
if(opt_range_min < 0 or opt_range_max >= 100):
raise ValueError
if(opt_range_min == 0 and (opt_var == "喉径" or opt_var == "容积")):
raise ValueError
if(opt_it <= 0 and opt_var != "气体温度"):
raise ValueError
if(opt_var == "气体温度" and opt_range_min < -273):
raise ValueError
opt_variable_name = opt_var
if(opt_var == "压强"):
opt_range_min *= 100000
opt_range_max *= 100000
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
mass_air = opt_range_min * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, opt_range_min, At, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
if(opt_var == "喉径"):
opt_range_min = 3.1415*pow(0.001*opt_range_min/2, 2)
opt_range_max = 3.1415*pow(0.001*opt_range_max/2, 2)
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, P_ins, opt_range_min, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
if(opt_var == "容积"):
opt_range_min *= 0.001
opt_range_max *= 0.001
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
V_air = opt_range_min - water_content * opt_range_min
V_water = water_content * opt_range_min
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, P_ins, At, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
if(opt_var == "含水量"):
opt_range_min *= 0.01
opt_range_max *= 0.01
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
V_air = float(V_total - opt_range_min * V_total)
V_water = float(opt_range_min * V_total)
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, float(P_ins), At, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
if(opt_var == "干重"):
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = opt_range_min + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, float(P_ins), At, V_air, V_water, Roc_mass, T, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
if(opt_var == "气体温度"):
opt_range_min += 273.15
opt_range_max += 273.15
opt_eps = (opt_range_max - opt_range_min) / float(opt_it)
for i in range(opt_it + 1):
array_opt_x.append(opt_range_min)
mass_air = P_ins * V_air / (opt_range_min * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
temp_data_opt = opt_sim(k_const, Rs, water_density, float(P_ins), At, V_air, V_water, Roc_mass, opt_range_min, rod_lenght, rod_inside_diameter)
array_opt_Ic.append(temp_data_opt[0])
array_opt_tc.append(temp_data_opt[1])
array_opt_Ist.append(temp_data_opt[2])
array_opt_delta_v.append(temp_data_opt[3])
opt_range_min += opt_eps
plot_opt_Ic()
# 清除错误信息
error_label_r.config(text="")
except ValueError:
error_label_r.config(text="输入无效。")
def plot_opt_Ic():
try:
# 清除上一个图形
ax_right.clear()
# 绘制新数据
ax_right.plot(array_opt_x, array_opt_Ic, linestyle='-', color='b')
# 设置标签和标题
ax_right.set_xlabel(opt_variable_name)
ax_right.set_ylabel('冲量 Ic [Ns]')
ax_right.set_title('冲量曲线')
# 更新画布
canvas_right.draw()
# 清除错误信息
error_label_r.config(text="")
except ValueError:
error_label_r.config(text="输入无效。")
def plot_opt_tc():
try:
# 清除上一个图形
ax_right.clear()
# 绘制新数据
ax_right.plot(array_opt_x, array_opt_tc, linestyle='-', color='b')
# 设置标签和标题
ax_right.set_xlabel(opt_variable_name)
ax_right.set_ylabel('总时间 [s]')
ax_right.set_title('工作时间曲线')
# 更新画布
canvas_right.draw()
# 清除错误信息
error_label_r.config(text="")
except ValueError:
error_label_r.config(text="输入无效。")
def plot_opt_Ist():
try:
# 清除上一个图形
ax_right.clear()
# 绘制新数据
ax_right.plot(array_opt_x, array_opt_Ist, linestyle='-', color='b')
# 设置标签和标题
ax_right.set_xlabel(opt_variable_name)
ax_right.set_ylabel('比冲 [s]')
ax_right.set_title('比冲曲线')
# 更新画布
canvas_right.draw()
# 清除错误信息
error_label_r.config(text="")
except ValueError:
error_label_r.config(text="输入无效。")
def plot_opt_delta_v():
try:
# 清除上一个图形
ax_right.clear()
# 绘制新数据
ax_right.plot(array_opt_x, array_opt_delta_v, linestyle='-', color='b')
# 设置标签和标题
ax_right.set_xlabel(opt_variable_name)
ax_right.set_ylabel('速度增量 Δv [m/s]')
ax_right.set_title('速度增量曲线')
# 更新画布
canvas_right.draw()
# 清除错误信息
error_label_r.config(text="")
except ValueError:
error_label_r.config(text="输入无效。")
# 主仿真函数
def simulate():
global engine_dry_mass
global engine_full_mass
# 输出变量声明
Ic = float(0)
max_h = float(0)
total_time = float(0)
delta_v = float(0)
gas_name = choosen_gas.get()
try:
if(gas_name == "空气"):
k_const = 1.4
Rs = 287
if(gas_name == "氩气"):
k_const = 1.67
Rs = 208
if(gas_name == "氦气"):
k_const = 1.66
Rs = 2077
if(gas_name == "氢气"):
k_const = 1.41
Rs = 4124
if(gas_name == "氮气"):
k_const = 1.4
Rs = 297
if(gas_name == "二氧化碳"):
k_const = 1.3
Rs = 188
if(gas_name == "氙气"):
k_const = 1.65
Rs = 208
if(gas_name == "自定义"):
k_const = float(entry_combobox1.get())
Rs = float(entry_combobox2.get())
water_density = float(entry_6.get())
# 清除总时间值
total_time = 0
Ic = 0
delta_v = 0
# 清空所有数组
array_time.clear()
array_h.clear()
array_Ft.clear()
array_mass.clear()
array_temperature.clear()
array_pressure.clear()
array_V_water.clear()
array_V_air.clear()
# 读取输入值
P_ins = float(entry_0.get())*100000
At = 3.1415*pow(0.001*float(entry_1.get())/2, 2)
V_total = float(entry_2.get())*0.001
water_content = float(entry_3.get()) * 0.01
V_air = V_total - water_content * V_total
V_water = water_content * V_total
dry_mass = float(entry_4.get())
engine_dry_mass = dry_mass
T = float(entry_5.get())+273.15
rod_lenght = float(entry_launch_lenght.get()) * 0.001
rod_inside_diameter = float(entry_launch_diameter.get()) * 0.001
# 错误保护
if(P_ins <= 0):
raise ValueError
if(k_const <= 0):
raise ValueError
if(Rs <= 0):
raise ValueError
if(water_density <= 0):
raise ValueError
if(At <= 0):
raise ValueError
if(V_total <= 0):
raise ValueError
if(water_content < 0 or water_content >= 1):
raise ValueError
if(dry_mass <= 0):
raise ValueError
if(T <= 0):
raise ValueError
if(rod_inside_diameter < 0):
raise ValueError
if(rod_lenght < 0):
raise ValueError
if(rod_inside_diameter >= 0.001 * float(entry_1.get())):
raise ValueError
s = float(0.0)
vrod = float(0.0)
# 考虑导向杆的存在修正初始空气体积
V_air = V_air - At * rod_lenght
# 定义绝热常数
C_const = P_ins * pow(V_air, k_const)
# 计算空气质量
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
engine_full_mass = Roc_mass
if(rod_inside_diameter > 0 and rod_lenght > 0):
while(s < rod_lenght):
# 数组更新
array_time.append(total_time)
total_time = total_time + delta_t
array_V_water.append(V_water)
array_V_air.append(V_air)
array_mass.append(Roc_mass)
array_pressure.append(P_ins)
array_temperature.append(T)
# 计算推力和冲量
Ft = (P_ins * At) * efficiency_sim_rod
array_Ft.append(Ft)
Ic += Ft * delta_t
arod = Ft / Roc_mass
vrod += delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
if(rod_inside_diameter == 0 and rod_lenght > 0):
while(s < rod_lenght):
# 数组更新
array_time.append(total_time)
total_time = total_time + delta_t
array_mass.append(Roc_mass)
array_V_air.append(V_air)
array_V_water.append(V_water)
array_temperature.append(T)
array_pressure.append(P_ins)
# 计算推力和冲量
Ft = (P_ins * At) * efficiency_sim_rod
array_Ft.append(Ft)
Ic += Ft * delta_t
arod = Ft / Roc_mass
vrod = vrod + delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
delta_V = At * vrod * delta_t
V_air += delta_V
P_ins = C_const / pow(V_air, k_const)
T = (P_ins * V_air) / (mass_air * Rs)
# 水喷出阶段循环
while(V_water > 0 and P_ins > P_atm):
# 更新时间数组用于绘图
array_time.append(total_time)
total_time = total_time + delta_t
# 计算推力
Ft = (2 * At * (P_ins - P_atm)) * efficiency_sim_water
array_Ft.append(Ft)
Ic += Ft * delta_t
ve = math.sqrt(2 * (P_ins - P_atm) / water_density)
# 计算体积变化
delta_V = At * ve * delta_t
# 更新体积数组
array_V_water.append(V_water)
array_V_air.append(V_air)
# 计算温度
T = P_ins * V_air / (mass_air * Rs)
array_temperature.append(T)
# 更新质量数组
array_mass.append(Roc_mass)
Roc_mass = Roc_mass - delta_V * water_density
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
# 更新体积值
V_air = V_air + delta_V
V_water = V_water - delta_V
# 计算压力并更新数组
P_ins = C_const * pow(V_air, -k_const)
array_pressure.append(P_ins)
# 马赫数1的排气阶段
while(P_ins > P_atm and P_ins/P_atm >= pow((k_const+1)/2, k_const/(k_const-1))):
# 更新时间数组用于绘图
array_time.append(total_time)
total_time = total_time + delta_t
# 添加不变化的值用于绘图
array_V_water.append(V_water)
array_V_air.append(V_air)
Tt = T * 2 / (k_const + 1)
dot_m = P_ins * At * pow(2/(k_const+1), 0.5 * (k_const+1)/(k_const-1)) * math.sqrt(k_const/(Rs*T))
ve_air = math.sqrt(k_const * Rs * Tt)
P_throat = pow(2 / (k_const + 1), k_const / (k_const - 1)) * P_ins
Ft = (dot_m * ve_air + At * (P_throat - P_atm)) * efficiency_sim_gas
array_Ft.append(Ft)
Ic += Ft * delta_t
delta_m = dot_m * delta_t
# 更新火箭质量
Roc_mass = Roc_mass - delta_m
array_mass.append(Roc_mass)
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
array_temperature.append(T)
P_ins = mass_air * Rs * T / V_air
array_pressure.append(P_ins)
# 亚音速排气阶段
while(P_ins > P_atm):
# 更新时间数组用于绘图
array_time.append(total_time)
total_time = total_time + delta_t
# 添加不变化的值用于绘图
array_V_water.append(V_water)
array_V_air.append(V_air)
Mach = math.sqrt(2 / (k_const-1) * (pow(P_ins / P_atm, (k_const-1) / k_const) - 1))
Tt = T / (1 + 0.5 * (k_const-1) * Mach * Mach)
ve_air = Mach * math.sqrt(k_const * Rs * Tt)
density_chamber = mass_air / V_air
density_throat = density_chamber / pow(1 + 0.5 * (k_const - 1) * Mach * Mach, 1 / (k_const-1))
dot_m = At * density_throat * ve_air
Ft = (dot_m * ve_air) * efficiency_sim_gas
array_Ft.append(Ft)
Ic += Ft * delta_t
delta_m = dot_m * delta_t
# 更新火箭质量
Roc_mass = Roc_mass - delta_m
array_mass.append(Roc_mass)
# 更新速度增量
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
array_temperature.append(T)
P_ins = mass_air * Rs * T / V_air
array_pressure.append(P_ins)
# 清除错误信息
error_label.config(text="")
# 打印输出值
text_widget_output = "冲量 Ic = {:.2f} Ns\n".format(Ic) + "工作时间 tc = {:.2f} s\n".format(total_time) + "比冲 Ist = {:.2f} s\n".format(Ic / (mass_propelant * 9.81)) + "速度增量 Δv = {:.2f} m/s\n\n".format(delta_v)
text_widget.insert("1.0", text_widget_output)
plot_Ft()
except ValueError:
error_label.config(text="输入无效。")
def plot_Ft():
try:
# 清除上一个图形
ax_left.clear()
# 绘制新数据
ax_left.plot(array_time, array_Ft, linestyle='-', color='b')
# 设置标签和标题
ax_left.set_xlabel('时间 [s]')
ax_left.set_ylabel('推力 [N]')
ax_left.set_title('推力曲线')
# 更新画布
canvas_left.draw()
# 清除错误信息
error_label.config(text="")
except ValueError:
error_label.config(text="输入无效。")
def plot_mass():
try:
# 清除上一个图形
ax_left.clear()
# 绘制新数据
ax_left.plot(array_time, array_mass, linestyle='-', color='b')
# 设置标签和标题
ax_left.set_xlabel('时间 [s]')
ax_left.set_ylabel('质量 [kg]')
ax_left.set_title('质量变化曲线')
# 更新画布
canvas_left.draw()
# 清除错误信息
error_label.config(text="")
except ValueError:
error_label.config(text="输入无效。")
def plot_temperature():
try:
# 清除上一个图形
ax_left.clear()
# 绘制新数据
ax_left.plot(array_time, array_temperature, linestyle='-', color='b')
# 设置标签和标题
ax_left.set_xlabel('时间 [s]')
ax_left.set_ylabel('温度 [K]')
ax_left.set_title('温度曲线')
# 更新画布
canvas_left.draw()
# 清除错误信息
error_label.config(text="")
except ValueError:
error_label.config(text="输入无效。")
def plot_pressure():
try:
# 清除上一个图形
ax_left.clear()
# 将压力单位转换为 bar
for i in range(len(array_pressure)):
array_pressure[i] /= 100000
# 绘制新数据
ax_left.plot(array_time, array_pressure, linestyle='-', color='b')
# 设置标签和标题
ax_left.set_xlabel('时间 [s]')
ax_left.set_ylabel('压强 [bar]')
ax_left.set_title('压强曲线')
# 更新画布
canvas_left.draw()
# 清除错误信息
error_label.config(text="")
except ValueError:
error_label.config(text="输入无效。")
def plot_volume():
try:
# 清除上一个图形
ax_left.clear()
# 绘制新数据
ax_left.plot(array_time, array_V_water, linestyle='-', color='b', label = "水")
ax_left.plot(array_time, array_V_air, linestyle='-', color='c', label = "空气")
# 设置标签和标题
ax_left.set_xlabel('时间 [s]')
ax_left.set_ylabel('体积 [m³]')
ax_left.set_title('体积变化曲线')
ax_left.legend()
# 更新画布
canvas_left.draw()
# 清除错误信息
error_label.config(text="")
except ValueError:
error_label.config(text="输入无效。")
def save_to_file(entry_text):
file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("文本文件", "*.txt")])
if file_path:
with open(file_path, "w") as file:
# frame_simulate
file.write(choosen_gas.get()+"\n")
file.write(entry_combobox1.get()+"\n")
file.write(entry_combobox2.get()+"\n")
file.write(entry_launch_lenght.get()+"\n")
file.write(entry_launch_diameter.get()+"\n")
# frame_left
file.write(entry_0.get()+"\n")
file.write(entry_1.get()+"\n")
file.write(entry_2.get()+"\n")
file.write(entry_3.get()+"\n")
file.write(entry_4.get()+"\n")
file.write(entry_5.get()+"\n")
file.write(entry_6.get()+"\n")
# frame_simulate_r
file.write(choosen_opt_variable.get()+"\n")
file.write(entry_opt_min.get()+"\n")
file.write(entry_opt_max.get()+"\n")
file.write(entry_opt_itteration.get()+"\n")
file.write(choosen_gas_opt.get()+"\n")
file.write(entry_combobox1_opt.get()+"\n")
file.write(entry_combobox2_opt.get()+"\n")
file.write(entry_launch_lenght_opt.get()+"\n")
file.write(entry_launch_diameter_opt.get()+"\n")
# frame_right
file.write(entry_0_r.get()+"\n")
file.write(entry_1_r.get()+"\n")
file.write(entry_2_r.get()+"\n")
file.write(entry_3_r.get()+"\n")
file.write(entry_4_r.get()+"\n")
file.write(entry_5_r.get()+"\n")
file.write(entry_6_r.get()+"\n")
def load_from_file(entry_text):
array_load_file = []
file_path = filedialog.askopenfilename(filetypes=[("文本文件", "*.txt")])
if file_path:
with open(file_path, "r") as file:
line = file.readline()
# 继续读取行直到文件末尾
while line:
array_load_file.append(line.strip())
line = file.readline()
combobox.set(array_load_file[0])
entry_combobox1.delete(0, tk.END)
entry_combobox1.insert(0, array_load_file[1])
entry_combobox2.delete(0, tk.END)
entry_combobox2.insert(0, array_load_file[2])
entry_launch_lenght.delete(0, tk.END)
entry_launch_lenght.insert(0, array_load_file[3])
entry_launch_diameter.delete(0, tk.END)
entry_launch_diameter.insert(0, array_load_file[4])
entry_0.delete(0, tk.END)
entry_0.insert(0, array_load_file[5])
entry_1.delete(0, tk.END)
entry_1.insert(0, array_load_file[6])
entry_2.delete(0, tk.END)
entry_2.insert(0, array_load_file[7])
entry_3.delete(0, tk.END)
entry_3.insert(0, array_load_file[8])
entry_4.delete(0, tk.END)
entry_4.insert(0, array_load_file[9])
entry_5.delete(0, tk.END)
entry_5.insert(0, array_load_file[10])
entry_6.delete(0, tk.END)
entry_6.insert(0, array_load_file[11])
combobox_variable_opt.set(array_load_file[12])
entry_opt_min.delete(0, tk.END)
entry_opt_min.insert(0, array_load_file[13])
entry_opt_max.delete(0, tk.END)
entry_opt_max.insert(0, array_load_file[14])
entry_opt_itteration.delete(0, tk.END)
entry_opt_itteration.insert(0, array_load_file[15])
combobox_gas_opt.set(array_load_file[16])
entry_combobox1_opt.delete(0, tk.END)
entry_combobox1_opt.insert(0, array_load_file[17])
entry_combobox2_opt.delete(0, tk.END)
entry_combobox2_opt.insert(0, array_load_file[18])
entry_launch_lenght_opt.delete(0, tk.END)
entry_launch_lenght_opt.insert(0, array_load_file[19])
entry_launch_diameter_opt.delete(0, tk.END)
entry_launch_diameter_opt.insert(0, array_load_file[20])
entry_0_r.delete(0, tk.END)
entry_0_r.insert(0, array_load_file[21])
entry_1_r.delete(0, tk.END)
entry_1_r.insert(0, array_load_file[22])
entry_2_r.delete(0, tk.END)
entry_2_r.insert(0, array_load_file[23])
entry_3_r.delete(0, tk.END)
entry_3_r.insert(0, array_load_file[24])
entry_4_r.delete(0, tk.END)
entry_4_r.insert(0, array_load_file[25])
entry_5_r.delete(0, tk.END)
entry_5_r.insert(0, array_load_file[26])
entry_6_r.delete(0, tk.END)
entry_6_r.insert(0, array_load_file[27])
def export_to_file():
entry_window = tk.Toplevel(root)
entry_window.title("导出数据")
label_export_name = ttk.Label(entry_window, text="发动机名称:")
label_export_name.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
entry_export_name = ttk.Entry(entry_window, width=10)
entry_export_name.grid(row=0, column=2, pady=5)
entry_export_name.insert(0, "0")
label_export_diameter = ttk.Label(entry_window, text="发动机直径 [mm]:")
label_export_diameter.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
entry_export_diameter = ttk.Entry(entry_window, width=10)
entry_export_diameter.grid(row=1, column=2, pady=5)
entry_export_diameter.insert(0, "0")
label_export_lenght = ttk.Label(entry_window, text="发动机长度 [mm]:")
label_export_lenght.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
entry_export_lenght = ttk.Entry(entry_window, width=10)
entry_export_lenght.grid(row=2, column=2, pady=5)
entry_export_lenght.insert(0, "0")
label_export_man = ttk.Label(entry_window, text="发动机制造商:")
label_export_man.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
entry_export_man = ttk.Entry(entry_window, width=10)
entry_export_man.grid(row=3, column=2, pady=5)
entry_export_man.insert(0, "0")
ok_button = ttk.Button(entry_window, text="确定", command=lambda: save_and_close(entry_export_name, entry_export_diameter, entry_export_lenght, entry_export_man, entry_window))
ok_button.grid(row=4, column=1, columnspan=2, pady=10)
def save_and_close(entry_export_name, entry_export_diameter, entry_export_lenght, entry_export_man, window):
global engine_name
global engine_diameter
global engine_lenght
global engine_manufacturer
engine_name = entry_export_name.get()
engine_diameter = entry_export_diameter.get()
engine_lenght = entry_export_lenght.get()
engine_manufacturer = entry_export_man.get()
# 预期错误
try:
if(float(engine_diameter) <= 0 ):
raise ValueError
if(float(engine_lenght) <= 0):
raise ValueError
save_to_export()
window.destroy()
except ValueError:
messagebox.showinfo("错误", "输入无效。")
def save_to_export():
file_path = filedialog.asksaveasfilename(defaultextension=".eng", filetypes=[("发动机文件", "*.eng")])
if file_path:
with open(file_path, "w") as file:
file.write(engine_name + " ")
file.write(str(engine_diameter) + " ")
file.write(str(engine_lenght) + " ")
file.write("P" + " ")
file.write(str(engine_dry_mass) + " ")
file.write(str(engine_full_mass) + " ")
file.write(engine_manufacturer + "\n")
for el_t, el_F in zip(array_time, array_Ft):
file.write(str(el_t) + " " + str(el_F) + "\n")
def efficiency_sim_window():
entry_window = tk.Toplevel(root)
entry_window.title("仿真效率设置")
label_export_name = ttk.Label(entry_window, text="导向杆效率:")
label_export_name.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
entry_export_name = ttk.Entry(entry_window, width=10)
entry_export_name.grid(row=0, column=2, pady=5)
entry_export_name.insert(0, str(efficiency_sim_rod))
label_export_diameter = ttk.Label(entry_window, text="液相效率:")
label_export_diameter.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
entry_export_diameter = ttk.Entry(entry_window, width=10)
entry_export_diameter.grid(row=1, column=2, pady=5)
entry_export_diameter.insert(0, str(efficiency_sim_water))
label_export_lenght = ttk.Label(entry_window, text="气相效率:")
label_export_lenght.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
entry_export_lenght = ttk.Entry(entry_window, width=10)
entry_export_lenght.grid(row=2, column=2, pady=5)
entry_export_lenght.insert(0, str(efficiency_sim_gas))
ok_button = ttk.Button(entry_window, text="确定", command=lambda: efficiency_sim_save(entry_export_name, entry_export_diameter, entry_export_lenght, entry_window))
ok_button.grid(row=4, column=1, columnspan=2, pady=10)
def efficiency_sim_save(entry_export_name, entry_export_diameter, entry_export_lenght, window):
global efficiency_sim_rod
global efficiency_sim_water
global efficiency_sim_gas
# 预期错误
try:
efficiency_sim_rod = float(entry_export_name.get())
efficiency_sim_water = float(entry_export_diameter.get())
efficiency_sim_gas = float(entry_export_lenght.get())
if(efficiency_sim_rod <= 0 or efficiency_sim_water <= 0 or efficiency_sim_gas <= 0):
raise ValueError
if(efficiency_sim_rod > 100 or efficiency_sim_water > 100 or efficiency_sim_gas > 100):
raise ValueError
window.destroy()
except ValueError:
messagebox.showinfo("错误", "输入无效。")
efficiency_sim_rod = 1
efficiency_sim_water = 1
efficiency_sim_gas = 1
def efficiency_opt_window():
entry_window = tk.Toplevel(root)
entry_window.title("优化效率设置")
label_export_name = ttk.Label(entry_window, text="导向杆效率:")
label_export_name.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
entry_export_name = ttk.Entry(entry_window, width=10)
entry_export_name.grid(row=0, column=2, pady=5)
entry_export_name.insert(0, str(efficiency_opt_rod))
label_export_diameter = ttk.Label(entry_window, text="液相效率:")
label_export_diameter.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
entry_export_diameter = ttk.Entry(entry_window, width=10)
entry_export_diameter.grid(row=1, column=2, pady=5)
entry_export_diameter.insert(0, str(efficiency_opt_water))
label_export_lenght = ttk.Label(entry_window, text="气相效率:")
label_export_lenght.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
entry_export_lenght = ttk.Entry(entry_window, width=10)
entry_export_lenght.grid(row=2, column=2, pady=5)
entry_export_lenght.insert(0, str(efficiency_opt_gas))
ok_button = ttk.Button(entry_window, text="确定", command=lambda: efficiency_opt_save(entry_export_name, entry_export_diameter, entry_export_lenght, entry_window))
ok_button.grid(row=4, column=1, columnspan=2, pady=10)
def efficiency_opt_save(entry_export_name, entry_export_diameter, entry_export_lenght, window):
global efficiency_opt_rod
global efficiency_opt_water
global efficiency_opt_gas
# 预期错误
try:
efficiency_opt_rod = float(entry_export_name.get())
efficiency_opt_water = float(entry_export_diameter.get())
efficiency_opt_gas = float(entry_export_lenght.get())
if(efficiency_opt_rod <= 0 or efficiency_opt_water <= 0 or efficiency_opt_gas <= 0):
raise ValueError
if(efficiency_opt_rod > 100 or efficiency_opt_water > 100 or efficiency_opt_gas > 100):
raise ValueError
window.destroy()
except ValueError:
messagebox.showinfo("错误", "输入无效。")
efficiency_opt_rod = 1
efficiency_opt_water = 1
efficiency_opt_gas = 1
# 创建主 Tkinter 窗口
root = tk.Tk()
root.title("水火箭仿真器")
menubar = tk.Menu(root)
file_menu = tk.Menu(menubar, tearoff=0)
file_menu.add_command(label="保存", command=lambda: save_to_file(entry_0))
file_menu.add_command(label="加载", command=lambda: load_from_file(entry_0))
file_menu.add_command(label="导出为 .eng", command=lambda: export_to_file())
menubar.add_cascade(label="文件", menu=file_menu)
root.config(menu=menubar)
# 设置窗口为全屏
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
root.geometry(f"{screen_width}x{screen_height}")
##########################################################################
# 左侧区域
##########################################################################
frame_simulate = ttk.Frame(root, padding="10")
frame_simulate.grid(row=1, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
simulate_button = ttk.Button(frame_simulate, text="仿真", command=simulate)
simulate_button.grid(row=0, column=0, columnspan=1, pady=5, sticky="w")
efficiency_button = ttk.Button(frame_simulate, text="效率", command=efficiency_sim_window)
efficiency_button.grid(row=0, column=2, columnspan=1, pady=5, sticky="w")
# 显示所选选项的标签
label_gas = ttk.Label(frame_simulate, text="选择气体:")
label_gas.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
# 创建 StringVar 来保存组合框的选定值
default_option = "空气"
choosen_gas = tk.StringVar(value=default_option)
# 创建组合框(下拉菜单)
options = ["空气", "氩气", "氦气", "氢气", "氮气", "二氧化碳", "氙气", "自定义"]
combobox = ttk.Combobox(frame_simulate, textvariable=choosen_gas, values=options, state="readonly", width=10)
combobox.grid(row=1, column=2, columnspan=2, pady=5, sticky="w")
label_custom_gas_info = ttk.Label(frame_simulate, text="自定义气体数据:")
label_custom_gas_info.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
label_combobox1 = ttk.Label(frame_simulate, text="比热比:")
label_combobox1.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
entry_combobox1 = ttk.Entry(frame_simulate, width=10)
entry_combobox1.grid(row=4, column=2, pady=5)
entry_combobox1.insert(0, "0")
label_combobox2 = ttk.Label(frame_simulate, text="气体常数 [J/(kg*K)]:")
label_combobox2.grid(row=5, column=0, columnspan=2, pady=5, sticky="w")
entry_combobox2 = ttk.Entry(frame_simulate, width=10)
entry_combobox2.grid(row=5, column=2, pady=5)
entry_combobox2.insert(0, "0")
# 导向杆数据
label_launch_lenght = ttk.Label(frame_simulate, text="导向杆长度 [mm]:")
label_launch_lenght.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
entry_launch_lenght = ttk.Entry(frame_simulate, width=10)
entry_launch_lenght.grid(row=6, column=2, pady=5)
entry_launch_lenght.insert(0, "0")
label_launch_diameter = ttk.Label(frame_simulate, text="导向杆内径 [mm]:")
label_launch_diameter.grid(row=7, column=0, columnspan=2, pady=5, sticky="w")
entry_launch_diameter = ttk.Entry(frame_simulate, width=10)
entry_launch_diameter.grid(row=7, column=2, pady=5)
entry_launch_diameter.insert(0, "0")
# 左侧输入框架
frame_left = ttk.Frame(root, padding="10")
frame_left.grid(row=1, column=1, sticky=(tk.W, tk.E, tk.N, tk.S))
label_0 = ttk.Label(frame_left, text="初始压强 [bar]:")
label_0.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
entry_0 = ttk.Entry(frame_left, width=10)
entry_0.grid(row=0, column=2, pady=5)
entry_0.insert(0, "0")
label_1 = ttk.Label(frame_left, text="喉部直径 [mm]:")
label_1.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
entry_1 = ttk.Entry(frame_left, width=10)
entry_1.grid(row=1, column=2, pady=5)
entry_1.insert(0, "0")
label_2 = ttk.Label(frame_left, text="总容积 [L]:")
label_2.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
entry_2 = ttk.Entry(frame_left, width=10)
entry_2.grid(row=2, column=2, pady=5)
entry_2.insert(0, "0")
label_3 = ttk.Label(frame_left, text="含水量 [%]:")
label_3.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
entry_3 = ttk.Entry(frame_left, width=10)
entry_3.grid(row=3, column=2, pady=5)
entry_3.insert(0, "0")
label_4 = ttk.Label(frame_left, text="干重 [kg]:")
label_4.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
entry_4 = ttk.Entry(frame_left, width=10)
entry_4.grid(row=4, column=2, pady=5)
entry_4.insert(0, "0")
label_5 = ttk.Label(frame_left, text="初始温度 [°C]:")
label_5.grid(row=5, column=0, columnspan=2, pady=5, sticky="w")
entry_5 = ttk.Entry(frame_left, width=10)
entry_5.grid(row=5, column=2, pady=5)
entry_5.insert(0, "0")
# 自定义液体密度
label_6 = ttk.Label(frame_left, text="液体密度 [kg/m³]:")
label_6.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
entry_6 = ttk.Entry(frame_left, width=10)
entry_6.grid(row=6, column=2, pady=5)
entry_6.insert(0, "1000")
frame_button = ttk.Frame(root, padding="10")
frame_button.grid(row=1, column=2, sticky=(tk.W, tk.E, tk.N, tk.S))
# 绘图按钮
plot_button = ttk.Button(frame_button, text="绘制推力", command=plot_Ft)
plot_button.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
plot_button = ttk.Button(frame_button, text="绘制压强", command=plot_pressure)
plot_button.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
plot_button = ttk.Button(frame_button, text="绘制体积", command=plot_volume)
plot_button.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
plot_button = ttk.Button(frame_button, text="绘制质量", command=plot_mass)
plot_button.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
plot_button = ttk.Button(frame_button, text="绘制温度", command=plot_temperature)
plot_button.grid(row=5, column=0, columnspan=2, pady=5,sticky="w")
# 错误标签
error_label = ttk.Label(frame_button, text="", foreground="red")
error_label.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
frame_text_widget = ttk.Frame(root, padding="10")
frame_text_widget.grid(row=1, column=3, sticky=(tk.W, tk.E, tk.N, tk.S))
text_widget = tk.Text(frame_text_widget, height=11, width=30)
text_widget.grid(row=0, column=0, sticky="w")
# 左侧绘图区域
frame_plot_left = ttk.Frame(root, padding="10")
frame_plot_left.grid(row=0, column=0, columnspan=4, sticky=(tk.W, tk.E, tk.N, tk.S))
# 创建 Matplotlib 图形和画布嵌入到 Tkinter 窗口
fig_left, ax_left = plt.subplots(figsize=(screen_width / 200, screen_height / 150))
canvas_left = FigureCanvasTkAgg(fig_left, master=frame_plot_left)
canvas_widget = canvas_left.get_tk_widget()
canvas_widget.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
##########################################################################
# 右侧区域(优化部分)
##########################################################################
frame_simulate_r = ttk.Frame(root, padding="10")
frame_simulate_r.grid(row=1, column=4, sticky=(tk.W, tk.E, tk.N, tk.S))
simulate_button = ttk.Button(frame_simulate_r, text="优化", command=optimalize)
simulate_button.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
# 显示所选选项的标签
label_choose_opt = ttk.Label(frame_simulate_r, text="选择优化变量")
label_choose_opt.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
# 创建 StringVar 来保存组合框的选定值
choosen_opt_variable = tk.StringVar()
# 创建组合框(下拉菜单)
options_variable_opt = ["压强", "喉径", "容积", "含水量", "干重", "气体温度"]
combobox_variable_opt = ttk.Combobox(frame_simulate_r, textvariable=choosen_opt_variable, values=options_variable_opt, state="readonly", width=10)
combobox_variable_opt.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
# 优化范围
label_opt_range = ttk.Label(frame_simulate_r, text="优化范围:")
label_opt_range.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
entry_opt_min = ttk.Entry(frame_simulate_r, width=7)
entry_opt_min.grid(row=4, column=0, sticky="w", pady=5)
entry_opt_min.insert(0, "最小值")
entry_opt_max = ttk.Entry(frame_simulate_r, width=7)
entry_opt_max.grid(row=5, column=0, sticky="w", pady=5)
entry_opt_max.insert(0, "最大值")
# 迭代次数
label_opt_itteration = ttk.Label(frame_simulate_r, text="迭代次数:")
label_opt_itteration.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
entry_opt_itteration = ttk.Entry(frame_simulate_r, width=7)
entry_opt_itteration.grid(row=6, column=1, sticky="w", pady=5)
entry_opt_itteration.insert(0, "1")
efficiency_button = ttk.Button(frame_simulate_r, text="效率", command=efficiency_opt_window)
efficiency_button.grid(row=0, column=1, columnspan=2, pady=5, sticky="w")
# 右侧第二个框架
frame_overall_data_right = ttk.Frame(root, padding="10")
frame_overall_data_right.grid(row=1, column=5, sticky=(tk.W, tk.E, tk.N, tk.S))
# 显示所选选项的标签
label_gas_r = ttk.Label(frame_overall_data_right, text="选择气体")
label_gas_r.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
# 创建 StringVar 来保存组合框的选定值
choosen_gas_opt = tk.StringVar(value=default_option)
# 创建组合框(下拉菜单)
options_gas_opt = ["空气", "氩气", "氦气", "氢气", "氮气", "二氧化碳", "氙气", "自定义"]
combobox_gas_opt = ttk.Combobox(frame_overall_data_right, textvariable=choosen_gas_opt, values=options_gas_opt, state="readonly", width=10)
combobox_gas_opt.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
label_custom_gas_info_opt = ttk.Label(frame_overall_data_right, text="自定义气体数据:")
label_custom_gas_info_opt.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
label_combobox1_opt = ttk.Label(frame_overall_data_right, text="比热比:")
label_combobox1_opt.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
entry_combobox1_opt = ttk.Entry(frame_overall_data_right, width=10)
entry_combobox1_opt.grid(row=4, column=2, pady=5)
entry_combobox1_opt.insert(0, "0")
label_combobox2_opt = ttk.Label(frame_overall_data_right, text="气体常数 [J/(kg*K)]:")
label_combobox2_opt.grid(row=5, column=0, columnspan=2, pady=5, sticky="w")
entry_combobox2_opt = ttk.Entry(frame_overall_data_right, width=10)
entry_combobox2_opt.grid(row=5, column=2, pady=5)
entry_combobox2_opt.insert(0, "0")
# 导向杆数据
label_launch_lenght_opt = ttk.Label(frame_overall_data_right, text="导向杆长度 [mm]:")
label_launch_lenght_opt.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
entry_launch_lenght_opt = ttk.Entry(frame_overall_data_right, width=10)
entry_launch_lenght_opt.grid(row=6, column=2, pady=5)
entry_launch_lenght_opt.insert(0, "0")
label_launch_diameter_opt = ttk.Label(frame_overall_data_right, text="导向杆内径 [mm]:")
label_launch_diameter_opt.grid(row=7, column=0, columnspan=2, pady=5, sticky="w")
entry_launch_diameter_opt = ttk.Entry(frame_overall_data_right, width=10)
entry_launch_diameter_opt.grid(row=7, column=2, pady=5)
entry_launch_diameter_opt.insert(0, "0")
# 右侧输入框架
frame_right = ttk.Frame(root, padding="10")
frame_right.grid(row=1, column=6, sticky=(tk.W, tk.E, tk.N, tk.S))
label_0_r = ttk.Label(frame_right, text="初始压强 [bar]:")
label_0_r.grid(row=0, column=0, columnspan=2, pady=5, sticky="w")
entry_0_r = ttk.Entry(frame_right, width=10)
entry_0_r.grid(row=0, column=2, pady=5)
entry_0_r.insert(0, "0")
label_1_r = ttk.Label(frame_right, text="喉部直径 [mm]:")
label_1_r.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
entry_1_r = ttk.Entry(frame_right, width=10)
entry_1_r.grid(row=1, column=2, pady=5)
entry_1_r.insert(0, "0")
label_2_r = ttk.Label(frame_right, text="总容积 [L]:")
label_2_r.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
entry_2_r = ttk.Entry(frame_right, width=10)
entry_2_r.grid(row=2, column=2, pady=5)
entry_2_r.insert(0, "0")
label_3_r = ttk.Label(frame_right, text="含水量 [%]:")
label_3_r.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
entry_3_r = ttk.Entry(frame_right, width=10)
entry_3_r.grid(row=3, column=2, pady=5)
entry_3_r.insert(0, "0")
label_4_r = ttk.Label(frame_right, text="干重 [kg]:")
label_4_r.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
entry_4_r = ttk.Entry(frame_right, width=10)
entry_4_r.grid(row=4, column=2, pady=5)
entry_4_r.insert(0, "0")
label_5_r = ttk.Label(frame_right, text="初始温度 [°C]:")
label_5_r.grid(row=5, column=0, columnspan=2, pady=5, sticky="w")
entry_5_r = ttk.Entry(frame_right, width=10)
entry_5_r.grid(row=5, column=2, pady=5)
entry_5_r.insert(0, "0")
# 自定义液体密度
label_6_r = ttk.Label(frame_right, text="液体密度 [kg/m³]:")
label_6_r.grid(row=6, column=0, columnspan=2, pady=5, sticky="w")
entry_6_r = ttk.Entry(frame_right, width=10)
entry_6_r.grid(row=6, column=2, pady=5)
entry_6_r.insert(0, "1000")
frame_button_r = ttk.Frame(root, padding="10")
frame_button_r.grid(row=1, column=7, sticky=(tk.W, tk.E, tk.N, tk.S))
# 绘图按钮
plot_button_r = ttk.Button(frame_button_r, text="绘制冲量", command=plot_opt_Ic)
plot_button_r.grid(row=1, column=0, columnspan=2, pady=5, sticky="w")
plot_button_r = ttk.Button(frame_button_r, text="绘制时间", command=plot_opt_tc)
plot_button_r.grid(row=2, column=0, columnspan=2, pady=5, sticky="w")
plot_button_r = ttk.Button(frame_button_r, text="绘制速度增量", command=plot_opt_delta_v)
plot_button_r.grid(row=3, column=0, columnspan=2, pady=5, sticky="w")
plot_button_r = ttk.Button(frame_button_r, text="绘制比冲", command=plot_opt_Ist)
plot_button_r.grid(row=4, column=0, columnspan=2, pady=5, sticky="w")
# 错误标签
error_label_r = ttk.Label(frame_button_r, text="", foreground="red")
error_label_r.grid(row=5, column=0, columnspan=2, pady=5, sticky="w")
# 右侧绘图区域
frame_plot_right = ttk.Frame(root, padding="10")
frame_plot_right.grid(row=0, column=4, columnspan=5, sticky=(tk.W, tk.E, tk.N, tk.S))
# 创建 Matplotlib 图形和画布嵌入到 Tkinter 窗口
fig_right, ax_right = plt.subplots(figsize=(screen_width / 200, screen_height / 150))
canvas_right = FigureCanvasTkAgg(fig_right, master=frame_plot_right)
canvas_widget_right = canvas_right.get_tk_widget()
canvas_widget_right.grid(row=0, column=0, columnspan=4, sticky=(tk.W, tk.E, tk.N, tk.S))
################################################
# 运行 Tkinter 事件循环
root.mainloop()下面替换原代码中的整个 simulate() 函数
# MAIN SIMULATION FUNCTION
def simulate():
global engine_dry_mass
global engine_full_mass
# Output variables declaration
Ic = float(0)
total_time = float(0)
delta_v = float(0)
gas_name = choosen_gas.get()
try:
if(gas_name == "Air"):
k_const = 1.4
Rs = 287
if(gas_name == "Argon"):
k_const = 1.67
Rs = 208
if(gas_name == "Helium"):
k_const = 1.66
Rs = 2077
if(gas_name == "Hydrogen"):
k_const = 1.41
Rs = 4124
if(gas_name == "Nitrogen"):
k_const = 1.4
Rs = 297
if(gas_name == "CO2"):
k_const = 1.3
Rs = 188
if(gas_name == "Xenon"):
k_const = 1.65
Rs = 208
if(gas_name == "Custom"):
k_const = float(entry_combobox1.get())
Rs = float(entry_combobox2.get())
water_density = float(entry_6.get())
# Clear total_time value
total_time = 0
Ic = 0
delta_v = 0
# Clear all arrays
array_time.clear()
array_h.clear()
array_Ft.clear()
array_mass.clear()
array_temperature.clear()
array_pressure.clear()
array_V_water.clear()
array_V_air.clear()
# Entry values read
P_ins = float(entry_0.get())*100000
At = 3.1415*pow(0.001*float(entry_1.get())/2, 2)
V_total = float(entry_2.get())*0.001
water_content = float(entry_3.get()) * 0.01
V_air = V_total - water_content * V_total
V_water = water_content * V_total
dry_mass = float(entry_4.get())
engine_dry_mass = dry_mass
T = float(entry_5.get())+273.15
rod_lenght = float(entry_launch_lenght.get()) * 0.001
rod_inside_diameter = float(entry_launch_diameter.get()) * 0.001
# Error safety net
if(P_ins <= 0):
raise ValueError
if(k_const <= 0):
raise ValueError
if(Rs <= 0):
raise ValueError
if(water_density <= 0):
raise ValueError
if(At <= 0):
raise ValueError
if(V_total <= 0):
raise ValueError
if(water_content < 0 or water_content >= 1):
raise ValueError
if(dry_mass <= 0):
raise ValueError
if(T <= 0):
raise ValueError
if(rod_inside_diameter < 0):
raise ValueError
if(rod_lenght < 0):
raise ValueError
if(rod_inside_diameter >= 0.001 * float(entry_1.get())):
raise ValueError
s = float(0.0)
vrod = float(0.0)
# V_air fix for existing rod
V_air = V_air - At * rod_lenght
# Define adiabatic constant
C_const = P_ins * pow(V_air, k_const)
# Calculate mass of air
mass_air = P_ins * V_air / (T * Rs)
mass_propelant = mass_air + V_water * water_density
Roc_mass = dry_mass + mass_propelant
engine_full_mass = Roc_mass
# ==================== 模拟阶段(保持原有逻辑)====================
if(rod_inside_diameter > 0 and rod_lenght > 0):
while(s < rod_lenght):
array_time.append(total_time)
total_time = total_time + delta_t
array_V_water.append(V_water)
array_V_air.append(V_air)
array_mass.append(Roc_mass)
array_pressure.append(P_ins)
array_temperature.append(T)
Ft = (P_ins * At) * efficiency_sim_rod
array_Ft.append(Ft)
# Ic += Ft * delta_t # 已删除
arod = Ft / Roc_mass
vrod += delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
if(rod_inside_diameter == 0 and rod_lenght > 0):
while(s < rod_lenght):
array_time.append(total_time)
total_time = total_time + delta_t
array_mass.append(Roc_mass)
array_V_air.append(V_air)
array_V_water.append(V_water)
array_temperature.append(T)
array_pressure.append(P_ins)
Ft = (P_ins * At) * efficiency_sim_rod
array_Ft.append(Ft)
# Ic += Ft * delta_t # 已删除
arod = Ft / Roc_mass
vrod = vrod + delta_t * arod
delta_v = vrod
s += vrod * delta_t + 0.5 * arod * delta_t * delta_t
delta_V = At * vrod * delta_t
V_air += delta_V
P_ins = C_const / pow(V_air, k_const)
T = (P_ins * V_air) / (mass_air * Rs)
# Loop for water phase
while(V_water > 0 and P_ins > P_atm):
array_time.append(total_time)
total_time = total_time + delta_t
Ft = (2 * At * (P_ins - P_atm)) * efficiency_sim_water
array_Ft.append(Ft)
# Ic += Ft * delta_t # 已删除
ve = math.sqrt(2 * (P_ins - P_atm) / water_density)
delta_V = At * ve * delta_t
array_V_water.append(V_water)
array_V_air.append(V_air)
T = P_ins * V_air / (mass_air * Rs)
array_temperature.append(T)
array_mass.append(Roc_mass)
Roc_mass = Roc_mass - delta_V * water_density
delta_v = delta_v + delta_t * Ft / Roc_mass
V_air = V_air + delta_V
V_water = V_water - delta_V
P_ins = C_const * pow(V_air, -k_const)
array_pressure.append(P_ins)
# Loop for Mach 1 on exit (choked flow)
while(P_ins > P_atm and P_ins/P_atm >= pow((k_const+1)/2, k_const/(k_const-1))):
array_time.append(total_time)
total_time = total_time + delta_t
array_V_water.append(V_water)
array_V_air.append(V_air)
Tt = T * 2 / (k_const + 1)
dot_m = P_ins * At * pow(2/(k_const+1), 0.5 * (k_const+1)/(k_const-1)) * math.sqrt(k_const/(Rs*T))
ve_air = math.sqrt(k_const * Rs * Tt)
P_throat = pow(2 / (k_const + 1), k_const / (k_const - 1)) * P_ins
Ft = (dot_m * ve_air + At * (P_throat - P_atm)) * efficiency_sim_gas
array_Ft.append(Ft)
# Ic += Ft * delta_t # 已删除
delta_m = dot_m * delta_t
Roc_mass = Roc_mass - delta_m
array_mass.append(Roc_mass)
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
array_temperature.append(T)
P_ins = mass_air * Rs * T / V_air
array_pressure.append(P_ins)
# Loop for sub Mach 1 on exit
while(P_ins > P_atm):
array_time.append(total_time)
total_time = total_time + delta_t
array_V_water.append(V_water)
array_V_air.append(V_air)
Mach = math.sqrt(2 / (k_const-1) * (pow(P_ins / P_atm, (k_const-1) / k_const) - 1))
Tt = T / (1 + 0.5 * (k_const-1) * Mach * Mach)
ve_air = Mach * math.sqrt(k_const * Rs * Tt)
density_chamber = mass_air / V_air
density_throat = density_chamber / pow(1 + 0.5 * (k_const - 1) * Mach * Mach, 1 / (k_const-1))
dot_m = At * density_throat * ve_air
Ft = (dot_m * ve_air) * efficiency_sim_gas
array_Ft.append(Ft)
# Ic += Ft * delta_t # 已删除
delta_m = dot_m * delta_t
Roc_mass = Roc_mass - delta_m
array_mass.append(Roc_mass)
delta_v = delta_v + delta_t * Ft / Roc_mass
mass_air = mass_air - delta_m
T = (P_ins / Rs) * pow(V_air / (mass_air + delta_m), k_const) * pow(V_air / mass_air, 1 - k_const)
array_temperature.append(T)
P_ins = mass_air * Rs * T / V_air
array_pressure.append(P_ins)
# ====================== 新增:梯形积分计算总冲 ======================
Ic = calculate_impulse_trapezoidal()
# Erase error message
error_label.config(text="")
# Print output values
text_widget_output = "Ic = {:.2f} Ns\n".format(Ic) + \
"tc = {:.2f} s\n".format(total_time) + \
"Ist = {:.2f} s\n".format(Ic / (mass_propelant * 9.81)) + \
"delta_v = {:.2f} m/s\n\n".format(delta_v)
text_widget.insert("1.0", text_widget_output)
plot_Ft()
except ValueError:
error_label.config(text="Invalid input.")
def calculate_impulse_trapezoidal():
if len(array_time) < 2 or len(array_Ft) < 2:
return 0.0
impulse = 0.0
for i in range(1, len(array_time)):
dt = array_time[i] - array_time[i-1]
if dt > 0:
impulse += 0.5 * (array_Ft[i-1] + array_Ft[i]) * dt
return impulse我有时间的话pyinstaller打包一下。
您还谈到了我的代码问题,我现在python只会写到循环,并且我想学一下TK库的使用。其他的话就是C语言的 STM32F103了,现在套装还没学完,我了解过Hal库,但是好像网上说建议先学标准库。我的角度计算很别扭是因为只学过个I2C通信计算MPU6050角速度…您说的F4系列好像401和407出名,如果有时间我也很想学。我先在其实很焦虑,代码写几行就不会了,没思路;买了十余本火箭的书,但是我的数理水平无法理解。您有什么建议吗?但是我发现 python和C的语言逻辑真的很像,或许在未来的某一天一通百通吧。
最后我想请您一个问题(可能描述有所磕绊):我想用现在的 STM32F103C8T6进行远距离通信,比如用 PWM的控制一个 SG90,您推荐用什么模块(就是我现在的环境,8266吗?),可以用笔计本电脑软件控制吗,我在这方面不太懂,希望您可以指点我一下,感谢大佬
