189 lines
6.9 KiB
Python
189 lines
6.9 KiB
Python
import math
|
||
from decimal import Decimal, ROUND_HALF_EVEN
|
||
|
||
"""
|
||
Viscosity Coefficient Calculator (Stokes' Law)
|
||
蓖麻油粘滞系数计算器 (斯托克斯定律)
|
||
|
||
参考了杨氏模量代码的高精度与不确定度修约逻辑。
|
||
(注:由于实验提供的是同一距离20cm的5次重复时间测量,此处直接求平均计算,不适用逐差法。逐差法通常用于等间距的多组累积物理量测量。)
|
||
|
||
公式说明:
|
||
1. 粘滞系数计算公式 (考虑管壁修正):
|
||
η = (ρ - ρ0) * g * d^2 * t / [18 * l * (1 + 2.4 * d/D)]
|
||
其中:
|
||
ρ : 小球密度
|
||
ρ0 : 液体(蓖麻油)密度
|
||
d : 小球直径
|
||
D : 玻璃管内径
|
||
l : 下落距离
|
||
t : 下落平均时间
|
||
|
||
2. 雷诺数 (Re) 判断和修正公式:
|
||
Re = ρ0 * v * d / η
|
||
其中 v = l / t。
|
||
当 Re < 0.1 时,斯托克斯定律完全适用。
|
||
当 0.1 <= Re <= 1.0 时,可使用奥辛(Oseen)修正:
|
||
η_corrected = η / (1 + 3/16 * Re)
|
||
|
||
3. 不确定度传递公式 (相对不确定度):
|
||
假定 ρ, ρ0, g 的不确定度可忽略,则:
|
||
u_r(η) = u_η / η = sqrt( (2 * u_d / d)^2 + (u_t / t)^2 + (u_l / l)^2 + (u_D / D)^2 )
|
||
|
||
绝对不确定度:
|
||
u_η = η * u_r(η)
|
||
|
||
其中各个量 X 的不确定度 u_X = sqrt( u_A,X^2 + u_B,X^2 )
|
||
u_A,X = s_X / sqrt(n)
|
||
u_B,X = Δ_inst / sqrt(3)
|
||
"""
|
||
|
||
def scientific_round(value, uncertainty):
|
||
"""
|
||
按照“四舍六入五凑偶”修约:
|
||
1. 不确定度 u 保留一位有效数字
|
||
2. 平均值末位与 u 对齐
|
||
"""
|
||
if uncertainty <= 0:
|
||
return str(value), "0"
|
||
|
||
u_float = float(uncertainty)
|
||
first_digit_pos = math.floor(math.log10(u_float))
|
||
prec = Decimal('1e' + str(first_digit_pos))
|
||
|
||
u_final = uncertainty.quantize(prec, rounding=ROUND_HALF_EVEN)
|
||
val_final = value.quantize(prec, rounding=ROUND_HALF_EVEN)
|
||
|
||
return val_final, u_final
|
||
|
||
def calculate_stats(data_list, delta_inst):
|
||
"""计算一组数据的平均值、A类、B类及合成不确定度"""
|
||
n = len(data_list)
|
||
mean = sum(data_list) / Decimal(n)
|
||
|
||
if n > 1:
|
||
variance = sum((x - mean)**2 for x in data_list) / Decimal(n - 1)
|
||
s = Decimal(str(math.sqrt(float(variance))))
|
||
u_a = s / Decimal(str(math.sqrt(n)))
|
||
else:
|
||
u_a = Decimal("0")
|
||
|
||
u_b = Decimal(delta_inst) / Decimal(str(math.sqrt(3)))
|
||
u_combined = Decimal(str(math.sqrt(float(u_a**2 + u_b**2))))
|
||
|
||
return mean, u_combined
|
||
|
||
def input_data_group(name, count, unit=""):
|
||
"""输入一组重复测量的数值"""
|
||
print(f"\n请输入 {name} 的 {count} 次测量值" + (f" (单位: {unit})" if unit else "") + ":")
|
||
data = []
|
||
for i in range(count):
|
||
while True:
|
||
try:
|
||
val = input(f"第 {i+1} 次 = ").strip()
|
||
if not val: continue
|
||
data.append(Decimal(val))
|
||
break
|
||
except Exception:
|
||
print("输入无效,请输入数字。")
|
||
return data
|
||
|
||
def main():
|
||
print("========================================")
|
||
print(" 蓖麻油粘滞系数计算 (斯托克斯定律) ")
|
||
print("========================================")
|
||
|
||
# --- 1. 常量设置 ---
|
||
G = Decimal("9.80") # 重力加速度 m/s^2
|
||
RHO_BALL = Decimal("7800") # 钢球密度 kg/m^3 (默认为钢球,通常实验室用此值)
|
||
RHO_OIL = Decimal("960") # 蓖麻油密度 kg/m^3 (随温度变化,常温附近约 960)
|
||
|
||
print(f"重力加速度 g = {G} m/s^2")
|
||
print(f"小球密度 ρ = {RHO_BALL} kg/m^3")
|
||
print(f"蓖麻油密度 ρ0 = {RHO_OIL} kg/m^3")
|
||
|
||
# --- 2. 测量数据输入 ---
|
||
print("\n--- 仪器与实验参数设定 ---")
|
||
D_mean = Decimal("20.0")
|
||
d_mean = Decimal("1.0")
|
||
l_mean = Decimal("20.0") # 默认单位 cm,后续转化为 mm 或 m 计算
|
||
|
||
ans = input("使用默认参数 (玻璃管直径D=20mm, 小球直径d=1mm, 下落距离l=20cm) 吗?[Y/n]: ").strip().lower()
|
||
if ans == 'n':
|
||
D_mean = Decimal(input("玻璃管直径 D (mm): ").strip() or "20.0")
|
||
d_mean = Decimal(input("小球直径 d (mm): ").strip() or "1.0")
|
||
l_mean = Decimal(input("下落距离 l (cm): ").strip() or "20.0")
|
||
|
||
l_mean_mm = l_mean * Decimal("10") # 统一 cm 转为 mm
|
||
|
||
print("\n--- 输入仪器误差 Δ_inst ---")
|
||
delta_D = Decimal(input("D 的仪器误差 (mm, 默认 0): ").strip() or "0")
|
||
delta_d = Decimal(input("d 的仪器误差 (mm, 默认 0): ").strip() or "0")
|
||
delta_l = Decimal(input("l 的仪器误差 (mm, 默认 0): ").strip() or "0")
|
||
delta_t = Decimal(input("t(时间)的仪器误差 (s, 默认 0.01): ").strip() or "0.01")
|
||
|
||
# D, d, l 我们假设只进行了单次测量或作为已知常数处理,所以只算B类不确定度
|
||
D_u = delta_D / Decimal(str(math.sqrt(3)))
|
||
d_u = delta_d / Decimal(str(math.sqrt(3)))
|
||
l_u = delta_l / Decimal(str(math.sqrt(3)))
|
||
|
||
# 输入5个时间数据
|
||
t_vals = input_data_group("小球下落时间 t", 5, "s")
|
||
t_mean, t_u = calculate_stats(t_vals, delta_t)
|
||
|
||
# --- 3. 粘滞系数计算 ---
|
||
# 统一转化为国际标准单位 (m, kg, s)
|
||
D_m = D_mean / Decimal("1000")
|
||
d_m = d_mean / Decimal("1000")
|
||
l_m = l_mean_mm / Decimal("1000")
|
||
|
||
# η = (ρ - ρ0) * g * d^2 * t / [18 * l * (1 + 2.4 * d/D)]
|
||
correction_factor = Decimal("1") + Decimal("2.4") * (d_m / D_m)
|
||
numerator = (RHO_BALL - RHO_OIL) * G * (d_m**2) * t_mean
|
||
denominator = Decimal("18") * l_m * correction_factor
|
||
eta_val = numerator / denominator
|
||
|
||
# --- 4. 雷诺数判断与修正 ---
|
||
# v = l / t
|
||
v_val = l_m / t_mean
|
||
# Re = ρ0 * v * d / η
|
||
Re = RHO_OIL * v_val * d_m / eta_val
|
||
|
||
eta_corrected = eta_val
|
||
if Re > Decimal("0.1"):
|
||
# Oseen 修正
|
||
eta_corrected = eta_val / (Decimal("1") + Decimal("3") / Decimal("16") * Re)
|
||
|
||
# --- 5. 不确定度传播 ---
|
||
# 相对不确定度平方和
|
||
rel_u_sq = (Decimal("2") * d_u / d_mean)**2 + (t_u / t_mean)**2 + (l_u / l_mean_mm)**2 + (D_u / D_mean)**2
|
||
rel_u = Decimal(str(math.sqrt(float(rel_u_sq))))
|
||
|
||
# 绝对不确定度
|
||
eta_u = eta_corrected * rel_u
|
||
|
||
# --- 6. 修约与输出 ---
|
||
eta_final, u_final = scientific_round(eta_corrected, eta_u)
|
||
|
||
print("\n" + "="*40)
|
||
print(" 计算结果")
|
||
print("="*40)
|
||
print(f"下落时间 t = {t_mean:.3f} ± {t_u:.3f} s")
|
||
print(f"下落速度 v = {v_val:.5f} m/s")
|
||
print("-" * 40)
|
||
print(f"雷诺数 Re = {Re:.4f}")
|
||
if Re <= Decimal("0.1"):
|
||
print("Re <= 0.1,满足斯托克斯定律条件,无需 Oseen 修正。")
|
||
else:
|
||
print("Re > 0.1,已应用 Oseen 修正。")
|
||
print(f"修正前 η = {eta_val:.4f} Pa·s")
|
||
print("-" * 40)
|
||
print(f"相对不确定度 u_r = {rel_u*100:.2f}%")
|
||
print(f"绝对不确定度 u_η = {eta_u:.4f} Pa·s")
|
||
print("-" * 40)
|
||
print(f"最终结果: η = {eta_final} ± {u_final} Pa·s")
|
||
print("="*40)
|
||
|
||
if __name__ == "__main__":
|
||
main()
|