This commit is contained in:
SOR
2026-06-07 10:49:28 +08:00
commit 8ce7705ae8
11 changed files with 1524 additions and 0 deletions
+370
View File
@@ -0,0 +1,370 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
"""
Wheatstone Bridge Resistance Measurement Calculator
电桥法测量电阻计算器
参考了表面张力系数计算器的高精度与不确定度修约逻辑。
公式说明:
1. 惠斯通电桥平衡条件 (Bridge Balance Equation):
当检流计示数为零时,电桥平衡:
Rx / R0 = R1 / R2
即:
Rx = R0 * (R1 / R2) (也写作 Rx = R0 * C,C = R1/R2 为比例臂比值)
其中:
Rx : 待测电阻
R0 : 比较臂标准电阻(电桥读数)
R1/R2 : 比例臂之比,取 1:1, 1:10, 10:1
2. 灵敏度公式 (Bridge Sensitivity):
S = Δn / (ΔR0 / R0)
其中:
S : 电桥灵敏度(格/相对变化量)
Δn : 检流计偏转格数(通常取 5 小格)
ΔR0 : 使检流计偏转 Δn 格时 R0 的改变量
ΔR0 = |R0' - R0|,R0' 为偏转 5 格时的读数
R0 : 平衡时的标准电阻读数
也可写为:
S = Δn * R0 / ΔR0
3. 不确定度传递公式 (Uncertainty Propagation):
Rx = R0 * C (C 为比例臂比值)
(a) R0 的不确定度:
u(R0) = sqrt( u_A(R0)^2 + u_B(R0)^2 )
其中:
u_A(R0) = s(R0) / sqrt(n) (A 类不确定度, s 为标准偏差)
u_B(R0) = Δ_inst / sqrt(3) (B 类不确定度, Δ_inst 为仪器误差限)
(b) 仪器误差限 Δ_inst 的确定 (与灵敏度有关):
Δ_inst = R0 / S
即由灵敏度决定的电桥最小可分辨电阻变化量
(c) 比例臂 C 视为精确值(标准电阻箱),则:
u(Rx) = C * u(R0)
(d) 相对不确定度:
u_r(Rx) = u(Rx) / Rx = u(R0) / R0
(e) 修约规则:
不确定度保留一位有效数字,四舍六入五凑偶
Rx 末位与不确定度对齐
"""
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类及合成不确定度
u(X) = sqrt( u_A^2 + u_B^2 )
u_A = s / sqrt(n)
u_B = Δ_inst / sqrt(3)
"""
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_a, u_b, u_combined
def input_decimal(prompt, default=None):
"""输入一个 Decimal 值,支持默认值"""
while True:
try:
suffix = f" (默认 {default})" if default else ""
val = input(f"{prompt}{suffix}: ").strip()
if not val and default is not None:
return Decimal(str(default))
if not val:
continue
return Decimal(val)
except Exception:
print("输入无效,请输入数字。")
def input_int(prompt, default=None):
"""输入一个整数,支持默认值"""
while True:
try:
suffix = f" (默认 {default})" if default else ""
val = input(f"{prompt}{suffix}: ").strip()
if not val and default is not None:
return default
return int(val)
except Exception:
print("输入无效,请输入整数。")
def measure_one_ratio(ratio_label, C_value, R_nominal, n_measurements):
"""
对单一比例臂进行测量与分析
参数:
ratio_label: 比例臂标签,如 "1:1"
C_value: 比例臂比值 C = R1/R2
R_nominal: 标定电阻标称值 (Ω)
n_measurements: 测量次数
"""
C = Decimal(str(C_value))
print(f"\n{'─'*50}")
print(f" 比例臂 Rx:R0 = {ratio_label},比例因子 C = {C_value}")
print(f" 标定电阻标称值: {R_nominal} Ω")
print(f"{'─'*50}")
# --- 输入平衡时的 R0 读数 ---
print(f"\n请输入 {n_measurements} 次平衡时的 R0 读数 (Ω):")
R0_data = []
for i in range(n_measurements):
while True:
try:
val = input(f" 第 {i+1} 次 R0 = ").strip()
if not val: continue
R0_data.append(Decimal(val))
break
except Exception:
print(" 输入无效,请输入数字。")
# --- 输入偏差 5 小格时的 R0' ---
print(f"\n请输入偏转 5 小格时的 R0' 读数 (Ω):")
R0_prime = input_decimal(" R0'")
delta_n = Decimal("5") # 检流计偏转格数
# --- 计算 R0 的平均值 ---
R0_mean = sum(R0_data) / Decimal(len(R0_data))
# --- 计算灵敏度 ---
# S = Δn * R0 / |R0' - R0|
delta_R0 = abs(R0_prime - R0_mean)
if delta_R0 == 0:
print(" ⚠ 警告: R0' = R0,无法计算灵敏度,请检查数据!")
S = Decimal("Infinity")
delta_inst = Decimal("0")
else:
S = delta_n * R0_mean / delta_R0
# 仪器误差限 (由灵敏度决定)
# Δ_inst = R0 / S = |R0' - R0| / Δn = ΔR0 / 5
delta_inst = R0_mean / S
# --- 不确定度分析 ---
R0_mean_final, u_a_R0, u_b_R0, u_R0 = calculate_stats(R0_data, str(delta_inst))
# Rx = C * R0
Rx_mean = C * R0_mean_final
u_Rx = C * u_R0
# 相对不确定度
if Rx_mean != 0:
u_r_Rx = u_Rx / Rx_mean
else:
u_r_Rx = Decimal("0")
# --- 修约 ---
Rx_final, u_Rx_final = scientific_round(Rx_mean, u_Rx)
# --- 输出结果 ---
print(f"\n{'═'*50}")
print(f" 结果 (比例臂 {ratio_label}, 标定 {R_nominal} Ω)")
print(f"{'═'*50}")
# 打印 R0 测量数据表
print(f"\n R0 测量数据:")
for i, val in enumerate(R0_data):
print(f" 第 {i+1} 次: {val} Ω")
print(f"\n R0 平均值 = {R0_mean_final:.4f} Ω")
print(f" R0' = {R0_prime} Ω")
print(f" ΔR0 = |R0'-R0| = {delta_R0:.4f} Ω")
print(f" 偏转格数 Δn = {delta_n} 格")
print(f"{'─'*50}")
print(f" 灵敏度 S = Δn·R0/ΔR0 = {S:.2f}")
print(f" 仪器误差限 Δ_inst = R0/S = {delta_inst:.4f} Ω")
print(f"{'─'*50}")
print(f" u_A(R0) = {u_a_R0:.6f} Ω")
print(f" u_B(R0) = {u_b_R0:.6f} Ω")
print(f" u(R0) = {u_R0:.6f} Ω")
print(f"{'─'*50}")
print(f" Rx = C × R0 = {C} × {R0_mean_final:.4f} = {Rx_mean:.4f} Ω")
print(f" u(Rx) = C × u(R0) = {u_Rx:.6f} Ω")
print(f" 相对不确定度 u_r = {u_r_Rx*100:.2f}%")
print(f"{'─'*50}")
print(f" ★ 最终结果: Rx = {Rx_final} ± {u_Rx_final} Ω")
print(f"{'═'*50}")
return {
"ratio_label": ratio_label,
"C": C,
"R_nominal": R_nominal,
"R0_data": R0_data,
"R0_mean": R0_mean_final,
"R0_prime": R0_prime,
"delta_R0": delta_R0,
"S": S,
"delta_inst": delta_inst,
"u_a_R0": u_a_R0,
"u_b_R0": u_b_R0,
"u_R0": u_R0,
"Rx_mean": Rx_mean,
"u_Rx": u_Rx,
"u_r_Rx": u_r_Rx,
"Rx_final": Rx_final,
"u_Rx_final": u_Rx_final
}
def main():
print("════════════════════════════════════════════════")
print(" 电桥法测量电阻计算器 (Wheatstone Bridge)")
print("════════════════════════════════════════════════")
print()
print("实验原理:")
print(" 惠斯通电桥平衡条件: Rx = R0 × C (C = R1/R2)")
print(" 灵敏度: S = Δn × R0 / ΔR0")
print(" 不确定度: u(Rx) = C × u(R0), u(R0) = √(u_A² + u_B²)")
print()
# --- 1. 基本参数 ---
n_meas = input_int("每组测量次数 n", default=5)
# --- 2. 定义测量方案 ---
# 标定电阻: 10kΩ 和 2kΩ
# 比例臂: 1:1, 1:10, 10:1
# 注意: 2kΩ 不会有 1:10 的比例臂 (因为 R0 = Rx/(C) 会超出电阻箱量程)
calibration_plan = [
# (标定电阻标称值, 比例臂标签, C 值)
# ---- 10kΩ 标定 ----
("10000", "1:1", 1),
("10000", "10:1", 10),
# ---- 2kΩ 标定 ----
("2000", "1:1", 1),
("2000", "10:1", 10),
# ---- 200Ω 标定 ----
("200", "1:1", 1),
("200", "1:10", 0.1),
("200", "10:1", 10),
]
print(f"\n{'━'*55}")
print(" 测量方案如下:")
print(f"{'━'*55}")
print(f" {'序号':<6}{'标定电阻':>10}{'比例臂 Rx:R0':>14}{'C = R1/R2':>12}")
print(f" {'─'*46}")
for idx, (R_nom, ratio, C_val) in enumerate(calibration_plan, 1):
print(f" {idx:<6}{R_nom + ' Ω':>10}{ratio:>14}{C_val:>12}")
print(f"{'━'*55}")
print()
print(" 注: 2kΩ 标定不进行 1:10 比例臂测量")
print(" (R0 = 2000/0.1 = 20000 Ω,超出电阻箱量程)")
print()
# --- 3. 逐项测量 ---
all_results = []
for idx, (R_nom, ratio_label, C_val) in enumerate(calibration_plan, 1):
print(f"\n{'▓'*55}")
print(f" 第 {idx} 组: 标定 {R_nom} Ω,比例臂 Rx:R0 = {ratio_label}")
print(f"{'▓'*55}")
result = measure_one_ratio(ratio_label, C_val, R_nom, n_meas)
all_results.append(result)
if idx < len(calibration_plan):
input("\n按回车继续下一组测量...")
# --- 4. 汇总表 ---
print("\n")
print("╔══════════════════════════════════════════════════════════════════════════════╗")
print("║ 测 量 结 果 汇 总 表 ║")
print("╠══════════════════════════════════════════════════════════════════════════════╣")
header = (f" {'标定':>6} {'比例臂':>8} {'R0均值(Ω)':>12} "
f"{'S(灵敏度)':>10} {'Δ_inst(Ω)':>10} "
f"{'Rx(Ω)':>12} {'u(Rx)(Ω)':>10} {'u_r(%)':>8}")
print(header)
print(f" {'─'*74}")
for res in all_results:
S_str = f"{res['S']:.1f}" if res['S'] != Decimal("Infinity") else "∞"
line = (f" {res['R_nominal']:>6} {res['ratio_label']:>8} "
f"{res['R0_mean']:>12.4f} {S_str:>10} "
f"{res['delta_inst']:>10.4f} "
f"{res['Rx_mean']:>12.4f} {res['u_Rx']:>10.6f} "
f"{res['u_r_Rx']*100:>7.2f}%")
print(line)
print("╚══════════════════════════════════════════════════════════════════════════════╝")
# --- 5. 灵敏度分析总结 ---
print("\n")
print("┌──────────────────────────────────────────────┐")
print("│ 灵 敏 度 分 析 总 结 │")
print("├──────────────────────────────────────────────┤")
for res in all_results:
S_str = f"{res['S']:.2f}" if res['S'] != Decimal("Infinity") else "∞"
print(f"│ 标定 {res['R_nominal']:>5}Ω 比例臂 {res['ratio_label']:>4} "
f"S = {S_str:>8} │")
print("├──────────────────────────────────────────────┤")
# 找灵敏度最大和最小
finite_results = [r for r in all_results if r['S'] != Decimal("Infinity")]
if finite_results:
best = max(finite_results, key=lambda r: r['S'])
worst = min(finite_results, key=lambda r: r['S'])
print(f"│ 最高灵敏度: 标定{best['R_nominal']:>5}Ω 比例臂{best['ratio_label']:>4} │")
print(f"│ S = {best['S']:.2f} │")
print(f"│ 最低灵敏度: 标定{worst['R_nominal']:>5}Ω 比例臂{worst['ratio_label']:>4} │")
print(f"│ S = {worst['S']:.2f} │")
print("├──────────────────────────────────────────────┤")
print("│ 分析: │")
print("│ · 灵敏度 S 越大,测量精度越高 │")
print("│ · S = Δn·R0/ΔR0 │")
print("│ · 比例臂比值影响灵敏度 │")
print("│ · 合理选择比例臂可优化测量精度 │")
print("└──────────────────────────────────────────────┘")
# --- 6. 最终修约结果汇总 ---
print("\n")
print("╔═══════════════════════════════════════════════════╗")
print("║ 最 终 结 果 (修约后) ║")
print("╠═══════════════════════════════════════════════════╣")
for res in all_results:
print(f"║ 标定 {res['R_nominal']:>5}Ω 比例臂 {res['ratio_label']:>4}: ║")
print(f"║ Rx = {res['Rx_final']} ± {res['u_Rx_final']} Ω ║")
print(f"║ (相对不确定度 {res['u_r_Rx']*100:.2f}%) ║")
print(f"╟───────────────────────────────────────────────────╢")
print("╚═══════════════════════════════════════════════════╝")
if __name__ == "__main__":
main()
+140
View File
@@ -0,0 +1,140 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
"""
Newton's Rings Curvature Radius Calculator (Successive Difference Method)
牛顿环曲率半径计算器 (逐差法)
参考 lenth.py 的高精度与不确定度修约逻辑。
"""
def get_decimal_places(data_strings):
"""获取输入数据中小数点后的保留位数,用于自适应展示"""
max_places = 0
for s in data_strings:
if '.' in s:
places = len(s.split('.')[1])
max_places = max(max_places, places)
return max_places
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 main():
# --- 1. 参数与常量初始化 ---
WAVELENGTH = Decimal("0.0005893") # 钠光波长默认 589.3 nm = 0.0005893 mm
M = 10 # 逐差法的差值项数 (30-20=10)
print("========================================")
print(" 牛顿环曲率半径计算 (逐差法) ")
print("========================================")
print(f"默认波长 λ = {WAVELENGTH} mm (钠光)")
print("参考环数: 第 11 环 到 第 30 环 (共 20 个数据)")
# --- 2. 数据输入 ---
d_squared_vals = []
data_strs = []
print("\n[第一步] 请输入暗环直径平方 D^2 (单位: mm^2)")
print("支持粘贴或逐个输入,精确到小数点后三位。")
for i in range(11, 31):
while True:
try:
user_input = input(f"D_{i:02d}^2 = ").strip()
if not user_input:
continue
val = Decimal(user_input)
d_squared_vals.append(val)
data_strs.append(user_input)
break
except Exception:
print("无效输入!请输入正确的直径平方值(如 12.345)。")
print("\n[第二步] 仪器参数输入")
res_input = input("请输入仪器分度值 (默认 0.01 mm): ").strip() or "0.01"
delta_inst_input = input("请输入仪器误差 Δ_inst (默认 0.005 mm): ").strip() or "0.005"
res = Decimal(res_input)
delta_inst = Decimal(delta_inst_input)
# --- 3. 逐差计算 ---
# Δ_i = D_{i+M}^2 - D_i^2 (i = 11...20)
deltas = []
sum_d_pairs = Decimal("0") # 用于 B 类不确定度传播: sum(D_low^2 + D_high^2)
print("\n--- 逐差过程 ---")
for i in range(10):
d_low_sq = d_squared_vals[i]
d_high_sq = d_squared_vals[i + 10]
diff = d_high_sq - d_low_sq
deltas.append(diff)
sum_d_pairs += (d_low_sq + d_high_sq)
print(f"Δ_{i+11:02d} = D_{i+21}^2 - D_{i+11}^2 = {diff} mm^2")
mean_delta = sum(deltas) / Decimal(str(M))
# --- 4. 曲率半径计算 ---
# R = Δ_avg / (4 * M * λ)
# M = 10, 所以分母是 40 * λ
denominator = Decimal("4") * Decimal(str(M)) * WAVELENGTH
r_val = mean_delta / denominator
# --- 5. 不确定度计算 ---
# (1) A 类不确定度 u_A (针对逐差后的 Δ)
variance_delta = sum((x - mean_delta)**2 for x in deltas) / Decimal(str(M - 1))
s_delta = Decimal(str(math.sqrt(float(variance_delta))))
u_a_delta = s_delta / Decimal(str(math.sqrt(M)))
# (2) B 类不确定度 u_B (传播自读数显微镜的仪器误差)
# 推导过程:
# u(x) = delta_inst / sqrt(3)
# u(D^2) = sqrt( (2D u_x)^2 + (2D u_x)^2 ) = 2 * sqrt(2) * D * u_x
# u(D^2)^2 = 8 * D^2 * u_x^2
# u(Δ)^2 = u(D_high^2)^2 + u(D_low^2)^2 = 8 * u_x^2 * (D_high^2 + D_low^2)
# u(Δ_avg)^2 = (1/M^2) * sum( u(Δ_i)^2 ) = (8 * u_x^2 / M^2) * sum_d_pairs
u_x = delta_inst / Decimal(str(math.sqrt(3)))
u_b_delta_sq = (Decimal("8") * (u_x**2) * sum_d_pairs) / (Decimal(str(M))**2)
u_b_delta = Decimal(str(math.sqrt(float(u_b_delta_sq))))
# (3) 合成不确定度 u(Δ) 并在 R 上传播
u_delta_combined = Decimal(str(math.sqrt(float(u_a_delta**2 + u_b_delta**2))))
u_r = u_delta_combined / denominator
# --- 6. 修约与展示 ---
r_final, u_final = scientific_round(r_val, u_r)
print("\n--- 中间统计结果 (高精度) ---")
print(f"平均差值 Δ_avg: {mean_delta:.6f} mm^2")
print(f"Δ 的标准差 s: {s_delta:.6f}")
print(f"Δ 的 A 类不确定度 u_A(Δ): {u_a_delta:.6f}")
print(f"Δ 的 B 类不确定度 u_B(Δ): {u_b_delta:.6f}")
print("\n--- 最终计算结果 (R) ---")
print(f"曲率半径 R (原始): {r_val:.4f} mm")
print(f"R 的合成不确定度 u(R): {u_r:.4f} mm")
print("\n========================================")
print(" 最终修约结果 (四舍六入五凑偶)")
print(f" R = {r_final} ± {u_final} mm")
print("========================================")
if __name__ == "__main__":
main()
BIN
View File
Binary file not shown.
+160
View File
@@ -0,0 +1,160 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
"""
Speed of Sound Calculator (Successive Difference Method)
声速测量计算器 (逐差法)
参考了 Newton's rings.py 的高精度与不确定度修约逻辑。
计算公式说明:
1. 理论声速公式:
v_t = 331.45 * sqrt(1 + t / 273.15)
其中 t 为摄氏温度。
2. 逐差法计算波长 λ:
本实验两组数据均为 12 个点,分成两组进行逐差:Δx_i = x_{i+6} - x_i (i=1..6)
- 干涉法 (驻波法) 找振幅最大处:相邻两次最大处间距为 λ/2
因此 Δx = 6 * (λ/2) = 3λ => λ = Δx_avg / 3
- 相位法 (李萨如图像) 变为相同方向直线:相邻两次相位改变 2π,间距为 λ
因此 Δx = 6 * λ => λ = Δx_avg / 6
3. 声速公式:
v = f * λ
4. 不确定度传递公式:
- Δx_avg 的 A 类不确定度: u_A(Δx_avg) = S_Δ / sqrt(M) (其中 S_Δ 为逐差后 Δx 的标准差, M=6)
- 坐标 x 的 B 类不确定度: u_B(x) = Δ_inst / sqrt(3) (假设均匀分布)
- 逐差平均值的 B 类不确定度传播: u_B(Δx_avg) = sqrt(2/M) * u_B(x)
- Δx_avg 的合成不确定度: u_c(Δx_avg) = sqrt(u_A^2 + u_B^2)
- 波长 λ 的不确定度:
干涉法 u(λ) = u_c(Δx_avg) / 3
相位法 u(λ) = u_c(Δx_avg) / 6
- 声速 v 的不确定度 (忽略 f 的极小不确定度): u(v) = f * u(λ)
"""
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_method(method_name, f, k, delta_inst):
print(f"\n========================================")
print(f" {method_name} ")
print(f"========================================")
print("请输入12个坐标数据 (单位: mm)。")
x_vals = []
for i in range(1, 13):
while True:
try:
val_str = input(f"x_{i:02d} = ").strip()
if not val_str:
continue
x_vals.append(Decimal(val_str))
break
except Exception:
print("无效输入!请输入正确的数值。")
# 1. 逐差计算
M = 6
deltas = []
print("\n--- 逐差过程 ---")
for i in range(M):
diff = x_vals[i + M] - x_vals[i]
deltas.append(diff)
print(f"Δx_{i+1} = x_{i+M+1} - x_{i+1} = {x_vals[i+M]} - {x_vals[i]} = {diff} mm")
mean_delta = sum(deltas) / Decimal(str(M))
# 2. 波长与声速计算
# 将毫米转换为米计算速度
wavelength_mm = mean_delta / Decimal(str(k))
wavelength_m = wavelength_mm / Decimal("1000")
velocity = Decimal(str(f)) * wavelength_m
# 3. 不确定度计算
# u_A
variance_delta = sum((d - mean_delta)**2 for d in deltas) / Decimal(str(M - 1))
s_delta = Decimal(str(math.sqrt(float(variance_delta))))
u_a_delta = s_delta / Decimal(str(math.sqrt(M)))
# u_B
u_x = delta_inst / Decimal(str(math.sqrt(3)))
u_b_delta = Decimal(str(math.sqrt(2.0 / M))) * u_x
# u_c(Δx_avg)
u_delta_combined = Decimal(str(math.sqrt(float(u_a_delta**2 + u_b_delta**2))))
# 传播到波长和声速
u_wavelength_mm = u_delta_combined / Decimal(str(k))
u_wavelength_m = u_wavelength_mm / Decimal("1000")
u_velocity = Decimal(str(f)) * u_wavelength_m
# 4. 修约与展示
v_final, uv_final = scientific_round(velocity, u_velocity)
print("\n--- 中间统计结果 (高精度) ---")
print(f"平均差值 Δx_avg: {mean_delta:.6f} mm")
print(f"Δx 的标准差 S_Δ: {s_delta:.6f} mm")
print(f"Δx_avg 的 A 类不确定度 u_A: {u_a_delta:.6f} mm")
print(f"Δx_avg 的 B 类不确定度 u_B: {u_b_delta:.6f} mm")
print(f"波长 λ: {wavelength_mm:.6f} mm")
print(f"波长的不确定度 u(λ): {u_wavelength_mm:.6f} mm")
print("\n========================================")
print(f" {method_name} 最终结果 (四舍六入五凑偶)")
print(f" v = {v_final} ± {uv_final} m/s")
print("========================================")
def main():
print("========================================")
print(" 声速测量计算器 ")
print("========================================")
t_input = input("请输入环境温度 t (℃) [默认 24]: ").strip() or "24"
f_input = input("请输入谐振波频率 f (Hz) [默认 37000]: ").strip() or "37000"
delta_inst_input = input("请输入游标卡尺/测微鼓轮分度值误差 Δ_inst (mm) [默认 0.02]: ").strip() or "0.02"
t = float(t_input)
f = float(f_input)
delta_inst = Decimal(delta_inst_input)
# 计算理论声速
v_t = 331.45 * math.sqrt(1 + t / 273.15)
print(f"\n理论声速 v_t = {v_t:.2f} m/s (温度 {t} ℃)")
while True:
print("\n请选择计算方法:")
print("1. 干涉法 (驻波法) - 振幅最大处")
print("2. 相位法 (李萨如法) - 相同方向直线")
print("3. 退出")
choice = input("请输入选项 (1/2/3): ").strip()
if choice == '1':
# 干涉法 k = 3 (Δx_avg = 3λ)
calculate_method("干涉法 (振幅最大处)", f, 3, delta_inst)
elif choice == '2':
# 相位法 k = 6 (Δx_avg = 6λ)
calculate_method("相位法 (相同方向直线)", f, 6, delta_inst)
elif choice == '3':
print("退出程序。")
break
else:
print("无效选项,请重新输入。")
if __name__ == "__main__":
main()
+257
View File
@@ -0,0 +1,257 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
"""
Surface Tension Coefficient Calculator (Pull-off Method)
拉脱法测液体表面张力系数计算器
参考了杨氏模量及粘滞系数代码的高精度与不确定度修约逻辑。
公式说明:
1. 表面张力系数计算公式:
α = F / [π * (d1 + d2)]
其中:
F : 拉脱力,通过传感器测得 F = U / K (K为传感器灵敏度)
d1 : 铁环内径
d2 : 铁环外径
2. 传感器灵敏度 K (通过砝码标定):
测得 2 组不同砝码个数 i (0~5) 下的电压 U1_i 与 U2_i (通常为增重与减重过程)。
取其平均值 U_avg_i = (U1_i + U2_i) / 2。
设单个砝码质量为 m,则受力 F_i = i * m * g。
使用最小二乘法对 (F_i, U_avg_i) 进行线性回归,斜率即为灵敏度 K (V/N)。
3. 不确定度传递公式 (相对不确定度):
假定 K 的不确定度 u_K 通过线性回归标准差求得。
拉脱力 F 的平均值: F_mean = U_pull_mean / K
拉脱力 F 的不确定度 (相对不确定度):
u_r(F) = sqrt( (u_U / U_pull_mean)^2 + (u_K / K)^2 )
内外径和(d1+d2)的不确定度:
u_d_sum = sqrt( u_d1^2 + u_d2^2 )
u_r(d_sum) = u_d_sum / (d1_mean + d2_mean)
总相对不确定度:
u_r(α) = u_α / α = sqrt( u_r(F)^2 + u_r(d_sum)^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 linear_regression(x_list, y_list):
"""
对 (x, y) 列表进行线性回归,返回斜率 k, 截距 b, 及斜率的标准不确定度 u_k
"""
n = len(x_list)
x_mean = sum(x_list) / Decimal(n)
y_mean = sum(y_list) / Decimal(n)
L_xx = sum((x - x_mean)**2 for x in x_list)
L_yy = sum((y - y_mean)**2 for y in y_list)
L_xy = sum((x_list[i] - x_mean) * (y_list[i] - y_mean) for i in range(n))
# 斜率
k = L_xy / L_xx
# 截距
b = y_mean - k * x_mean
# 相关系数 r
r = L_xy / Decimal(str(math.sqrt(float(L_xx * L_yy))))
# 斜率的标准不确定度 u_k
# u_k = k * sqrt( (1/r^2 - 1) / (n - 2) )
r_float = float(r)
if abs(r_float) < 1.0:
u_k_float = float(k) * math.sqrt( (1.0 / (r_float**2) - 1.0) / (n - 2) )
else:
u_k_float = 0.0
u_k = Decimal(str(abs(u_k_float)))
return k, b, r, u_k
def input_data_group(name, count, unit=""):
"""输入一组重复测量的数值"""
prompt_unit = f" (单位: {unit})" if unit else ""
print(f"\n请输入 {name} 的 {count} 次测量值{prompt_unit}:")
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
PI = Decimal(str(math.pi))
print(f"重力加速度 g = {G} m/s^2")
print(f"圆周率 π ≈ {PI:.5f}")
print("\n--- 砝码参数与标定 ---")
m_default = "0.5"
m_input = input(f"单个小砝码质量 m (g, 默认 {m_default}): ").strip() or m_default
m_mass = Decimal(m_input) / Decimal("1000") # 转为 kg
print("\n请输入力敏传感器标定电压 (共 2 组,0~5 个小砝码,例如:第 1 组为增重,第 2 组为减重):")
print("\n--- 输入第 1 组标定电压 (U1) ---")
U_calib_1 = []
for i in range(6):
while True:
try:
val = input(f"第1组 - 放 {i} 个砝码时的电压 U1 (V或mV, 请统一单位) = ").strip()
if not val: continue
U_calib_1.append(Decimal(val))
break
except Exception:
print("输入无效,请输入数字。")
print("\n--- 输入第 2 组标定电压 (U2) ---")
U_calib_2 = []
for i in range(6):
while True:
try:
val = input(f"第2组 - 放 {i} 个砝码时的电压 U2 (V或mV, 请统一单位) = ").strip()
if not val: continue
U_calib_2.append(Decimal(val))
break
except Exception:
print("输入无效,请输入数字。")
# 计算两组的平均电压并生成对应的受力
U_calib_avg = []
F_calib = []
for i in range(6):
avg_val = (U_calib_1[i] + U_calib_2[i]) / Decimal("2")
U_calib_avg.append(avg_val)
F_calib.append(Decimal(str(i)) * m_mass * G)
# 打印标定数据对照表
print("\n" + "-"*65)
print(f"{'砝码数':<6} | {'受力 F (N)':<12} | {'第1组 U1':<10} | {'第2组 U2':<10} | {'平均 U_avg':<10}")
print("-"*65)
for i in range(6):
print(f"{i:<8} | {F_calib[i]:<12.6f} | {U_calib_1[i]:<10.4f} | {U_calib_2[i]:<10.4f} | {U_calib_avg[i]:<10.4f}")
print("-"*65)
# 计算灵敏度 K
K, K_b, r, u_K = linear_regression(F_calib, U_calib_avg)
print(f"\n[标定结果] 传感器灵敏度 K = {K:.6f}, 截距 = {K_b:.6f}")
print(f"线性相关系数 r = {r:.6f}, 斜率不确定度 u_K = {u_K:.6e}")
# --- 2. 拉脱测量与仪器误差输入 ---
print("\n--- 输入仪器误差 Δ_inst ---")
delta_U = Decimal(input("电压 U 的仪器误差 (默认 0.001): ").strip() or "0.001")
delta_d = Decimal(input("游标卡尺测量内外径的仪器误差 (mm, 默认 0.02): ").strip() or "0.02")
# 输入拉脱电压 U_pull (6次)
U_pull_vals = input_data_group("拉脱时的电压差/峰值电压 U_pull", 6, "同标定电压单位")
U_pull_mean, U_pull_u = calculate_stats(U_pull_vals, delta_U)
# 输入内径 d1 (6次)
d1_vals = input_data_group("铁环内径 d1", 6, "mm")
d1_mean, d1_u = calculate_stats(d1_vals, delta_d)
# 输入外径 d2 (6次)
d2_vals = input_data_group("铁环外径 d2", 6, "mm")
d2_mean, d2_u = calculate_stats(d2_vals, delta_d)
# --- 3. 表面张力系数计算 ---
# F = U / K
F_pull_mean = U_pull_mean / K
# 统一转化内径、外径为国际标准单位 m
d1_m = d1_mean / Decimal("1000")
d2_m = d2_mean / Decimal("1000")
d1_u_m = d1_u / Decimal("1000")
d2_u_m = d2_u / Decimal("1000")
# α = F / [π * (d1 + d2)]
d_sum = d1_m + d2_m
alpha_val = F_pull_mean / (PI * d_sum)
# --- 4. 不确定度传播 ---
# u_r(F) = sqrt( (u_U / U_pull_mean)^2 + (u_K / K)^2 )
u_r_F_sq = (U_pull_u / U_pull_mean)**2 + (u_K / K)**2
u_r_F = Decimal(str(math.sqrt(float(u_r_F_sq))))
# u(d1 + d2)
u_d_sum = Decimal(str(math.sqrt(float(d1_u_m**2 + d2_u_m**2))))
u_r_d_sum = u_d_sum / d_sum
# u_r(α) = sqrt( u_r(F)^2 + u_r(d_sum)^2 )
u_r_alpha = Decimal(str(math.sqrt(float(u_r_F**2 + u_r_d_sum**2))))
# 绝对不确定度
alpha_u = alpha_val * u_r_alpha
# --- 5. 修约与输出 ---
alpha_final, u_final = scientific_round(alpha_val, alpha_u)
print("\n" + "="*40)
print(" 计算结果")
print("="*40)
print(f"拉脱电压 U_pull = {U_pull_mean:.4f} ± {U_pull_u:.4f}")
print(f"拉脱力 F = {F_pull_mean:.6f} N")
print(f"铁环内径 d1 = {d1_mean:.3f} ± {d1_u:.3f} mm")
print(f"铁环外径 d2 = {d2_mean:.3f} ± {d2_u:.3f} mm")
print("-" * 40)
print(f"相对不确定度 u_r = {u_r_alpha*100:.2f}%")
print(f"绝对不确定度 u_α = {alpha_u:.6f} N/m")
print("-" * 40)
print(f"最终表面张力系数: α = {alpha_final} ± {u_final} N/m")
print("="*40)
if __name__ == "__main__":
main()
+188
View File
@@ -0,0 +1,188 @@
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()
+201
View File
@@ -0,0 +1,201 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
"""
Young's Modulus Calculator (Optical Lever & Successive Difference Method)
杨氏模量计算器 (光杠杆 & 逐差法)
不确定度传递公式:
1. 杨氏模量公式:
E = (32 * m * g * L * D) / (π * d^2 * b * Δn_avg)
其中 Δn_avg 是 4 个砝码对应的平均刻度位移(由 8 个刻度值通过逐差法求得)。
2. 相对不确定度传递公式:
u_r(E) = u_E / E = sqrt( (u_L/L)^2 + (u_D/D)^2 + (2 * u_d/d)^2 + (u_b/b)^2 + (u_Δn/Δn_avg)^2 )
3. 合成不确定度:
u_E = E * u_r(E)
其中各物理量 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 保留一位有效数字(若首位是1或2,有时保留两位,此处统一保留一位)
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)
# A类不确定度
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")
# B类不确定度
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="mm"):
"""输入一组重复测量的数值"""
print(f"\n请输入 {name} 的 {count} 次测量值 (单位: {unit}):")
data = []
for i in range(count):
while True:
try:
val = input(f"{name}_{i+1} = ").strip()
if not val: continue
data.append(Decimal(val))
break
except Exception:
print("输入无效,请输入数字。")
return data
def main():
# --- 1. 常量设置 ---
M_WEIGHT = Decimal("0.350") # 单个砝码质量 350g = 0.350kg
G = Decimal("9.80") # 重力加速度
PI = Decimal(str(math.pi))
print("========================================")
print(" 杨氏模量计算 (光杠杆 & 逐差法) ")
print("========================================")
print(f"单个砝码质量 m = {M_WEIGHT} kg")
print(f"重力加速度 g = {G} m/s^2")
# --- 2. 几何长度输入 (各6次测量) ---
# L: 钢丝长度, D: 镜面到刻度尺距离, d: 钢丝直径, b: 光杠杆臂长
L_vals = input_data_group("钢丝长度 L", 6, "mm")
D_vals = input_data_group("镜面到尺距离 D", 6, "mm")
d_vals = input_data_group("钢丝直径 d", 6, "mm")
b_vals = input_data_group("光杠杆臂长 b", 6, "mm")
print("\n--- 输入仪器误差 Δ_inst ---")
delta_L = Decimal(input("L 的仪器误差 (mm, 默认 1.0): ").strip() or "1.0")
delta_D = Decimal(input("D 的仪器误差 (mm, 默认 1.0): ").strip() or "1.0")
delta_d = Decimal(input("d 的仪器误差 (mm, 默认 0.005): ").strip() or "0.005")
delta_b = Decimal(input("b 的仪器误差 (mm, 默认 0.02): ").strip() or "0.02")
L_mean, L_u = calculate_stats(L_vals, delta_L)
D_mean, D_u = calculate_stats(D_vals, delta_D)
d_mean, d_u = calculate_stats(d_vals, delta_d)
b_mean, b_u = calculate_stats(b_vals, delta_b)
# --- 3. 刻度值输入 (0-7个砝码, 加重+减重) ---
print("\n--- 输入刻度尺读数 n (单位: mm) ---")
n_up = []
n_down = []
for i in range(8):
while True:
try:
line = input(f"砝码数量 {i} (加重, 减重): ").replace(',', ' ').split()
if len(line) != 2:
print("请输入两个数值(空格或逗号隔开)")
continue
n_up.append(Decimal(line[0]))
n_down.append(Decimal(line[1]))
break
except Exception:
print("输入无效!")
delta_n_inst = Decimal(input("刻度尺仪器误差 (mm, 默认 0.5): ").strip() or "0.5")
# 计算平均读数 n_i
n_means = [(u + d) / 2 for u, d in zip(n_up, n_down)]
print("\n--- 中间量 (加重与减重的平均值 n_i) ---")
for i, val in enumerate(n_means):
print(f"n_{i} = {val} mm")
# 逐差法计算 Δn (隔 4 项相减)
# Δn_j = n_{j+4} - n_j, j = 0,1,2,3
dn_list = []
print("\n--- 逐差计算过程 ---")
for j in range(4):
diff = n_means[j+4] - n_means[j]
dn_list.append(diff)
print(f"Δn_{j} = n_{j+4} - n_{j} = {diff} mm")
# Δn 的平均值及不确定度
dn_mean = sum(dn_list) / Decimal("4")
# A类: 针对这 4 个差值
variance_dn = sum((x - dn_mean)**2 for x in dn_list) / Decimal("3")
s_dn = Decimal(str(math.sqrt(float(variance_dn))))
u_a_dn = s_dn / Decimal(str(math.sqrt(4)))
# B类: 刻度尺误差
# 因为 n_i = (n_up + n_down)/2, Δn = n_high - n_low
# 传播得 u_B(Δn) = Δ_inst / sqrt(3)
u_b_dn = delta_n_inst / Decimal(str(math.sqrt(3)))
dn_u = Decimal(str(math.sqrt(float(u_a_dn**2 + u_b_dn**2))))
# --- 4. 杨氏模量计算 ---
# 全部转为标准单位 (m)
L_m = L_mean / 1000
D_m = D_mean / 1000
d_m = d_mean / 1000
b_m = b_mean / 1000
dn_m = dn_mean / 1000
# E = (32 * m * g * L * D) / (pi * d^2 * b * Δn)
# 这里的 Δn 对应 4 个砝码的位移
numerator = Decimal("32") * M_WEIGHT * G * L_m * D_m
denominator = PI * (d_m**2) * b_m * dn_m
E_val = numerator / denominator
# --- 5. 不确定度传播 ---
# rel_u = sqrt( (uL/L)^2 + (uD/D)^2 + (2*ud/d)^2 + (ub/b)^2 + (udn/dn)^2 )
rel_u_sq = (L_u/L_mean)**2 + (D_u/D_mean)**2 + (Decimal("2")*d_u/d_mean)**2 + (b_u/b_mean)**2 + (dn_u/dn_mean)**2
rel_u = Decimal(str(math.sqrt(float(rel_u_sq))))
E_u = E_val * rel_u
# --- 6. 修约与输出 ---
# 通常用 10^11 Pa 表示
E_11 = E_val / Decimal("1e11")
E_u_11 = E_u / Decimal("1e11")
E_final, u_final = scientific_round(E_11, E_u_11)
print("\n" + "="*40)
print(" 计算结果")
print("="*40)
print(f"L = {L_mean:.2f} ± {L_u:.2f} mm")
print(f"D = {D_mean:.2f} ± {D_u:.2f} mm")
print(f"d = {d_mean:.4f} ± {d_u:.4f} mm")
print(f"b = {b_mean:.3f} ± {b_u:.3f} mm")
print(f"Δn = {dn_mean:.3f} ± {dn_u:.3f} mm (4个砝码位移)")
print("-" * 40)
print(f"杨氏模量 E (原始): {E_val:.4e} Pa")
print(f"相对不确定度 u_r: {rel_u*100:.2f}%")
print("-" * 40)
print(f"最终结果: E = {E_final} ± {u_final} × 10^11 Pa")
print("="*40)
if __name__ == "__main__":
main()
+130
View File
@@ -0,0 +1,130 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
def parse_angle_to_minutes(s):
"""
将输入解析为内部统一单位:分钟(Decimal)。
支持格式:
1. 'D.M' -> D度M分 (例如 '120.15' -> 120*60 + 15 = 7215分)
2. 'D' (纯数字无点) -> D度 (例如 '120' -> 120*60 = 7200分)
3. 'D.M.S' -> D度M分S秒 (例如 '120.15.30' -> 7215.5分)
"""
parts = s.split('.')
if len(parts) == 1:
# 视为度
return Decimal(parts[0]) * 60
elif len(parts) == 2:
# 度.分
return Decimal(parts[0]) * 60 + Decimal(parts[1])
else:
# 度.分.秒 或更多
res = Decimal(parts[0]) * 60 + Decimal(parts[1])
if len(parts) >= 3:
res += Decimal(parts[2]) / 60
return res
def format_minutes_as_angle(minutes, prec=None):
"""
将总分钟数转换为 D° M' 格式,支持保持对齐精度。
"""
neg = minutes < 0
minutes = abs(minutes)
d = int(minutes // 60)
m = minutes % 60
# 进位处理:如果 m 由于位宽限制进位到 60
if m >= 60:
d += 1
m -= 60
if prec is not None and prec < 1:
# 计算小数位数
places = abs(prec.as_tuple().exponent)
m_str = format(m, f'.{places}f')
else:
# 整数或自动小数位
if m == int(m):
m_str = str(int(m))
else:
m_str = format(m, 'f').rstrip('0').rstrip('.')
return f"{'-' if neg else ''}{d}°{m_str}'"
def calc_uncertainty(data_strs, res_str="1"):
# 转换为分钟进行高精度计算
data = [parse_angle_to_minutes(s) for s in data_strs]
res = Decimal(res_str) # 仪器误差,单位:分
n = len(data)
# 1. 计算平均值
sum_val = sum(data)
mean = sum_val / n
# 2. 计算标准差 s
if n > 1:
variance = sum((x - mean) ** 2 for x in data) / (n - 1)
s = Decimal(str(math.sqrt(float(variance))))
else:
s = Decimal('0')
# 3. A类不确定度 u_A
u_A = s / Decimal(str(math.sqrt(n)))
# 4. B类不确定度 u_B (仪器误差)
u_B = res / Decimal(str(math.sqrt(3)))
# 5. 合成不确定度 u
u = Decimal(str(math.sqrt(float(u_A**2 + u_B**2))))
return mean, s, u_A, u_B, u
def format_final_result(mean_minutes, u_minutes):
"""
按照“四舍六入五凑偶”修约:
1. 不确定度 u 保留一位有效数字
2. 平均值末位与 u 对齐
"""
u_float = float(u_minutes)
if u_float == 0:
return f"θ = {format_minutes_as_angle(mean_minutes)} ± 0'"
# 找到第一位非零数字的位置
first_digit_pos = math.floor(math.log10(u_float))
prec = Decimal('1e' + str(first_digit_pos))
# 修约
u_final = u_minutes.quantize(prec, rounding=ROUND_HALF_EVEN)
mean_final_val = mean_minutes.quantize(prec, rounding=ROUND_HALF_EVEN)
# 转换为角度字符串输出
mean_str = format_minutes_as_angle(mean_final_val, prec)
u_str = f"{u_final}'"
return f"θ = {mean_str} ± {u_str}"
if __name__ == "__main__":
print("=== 角度不确定度计算器 ===")
print("输入格式: '度.分' (如 120.15 表示 120°15'),多个数据用空格隔开。")
try:
user_input = input("请输入数据:").split()
if not user_input:
print("未输入数据!")
else:
res_input = input("请输入仪器分度值 (单位: 分,默认 1):").strip() or "1"
mean_v, s, u_A, u_B, u = calc_uncertainty(user_input, res_input)
print("\n--- 中间计算过程 ---")
print(f"平均值: {format_minutes_as_angle(mean_v)} ({mean_v:.4f}')")
print(f"标准差 s: {s:.6f}'")
print(f"A类不确定度 u_A: {u_A:.6f}'")
print(f"B类不确定度 u_B: {u_B:.6f}'")
print(f"合成不确定度 u: {u:.6f}'")
print("\n--- 最终修约结果 (四舍六入五凑偶) ---")
print(format_final_result(mean_v, u))
except Exception as e:
print(f"错误: {e}")
+78
View File
@@ -0,0 +1,78 @@
import math
from decimal import Decimal, ROUND_HALF_EVEN
def get_decimal_places(data_strings):
"""获取输入数据中小数点后的位数"""
max_places = 0
for s in data_strings:
if '.' in s:
places = len(s.split('.')[1])
max_places = max(max_places, places)
return max_places
def calc_uncertainty(data_strs, res_str="0.05"):
# 转换为 Decimal 进行高精度计算
data = [Decimal(s) for s in data_strs]
res = Decimal(res_str)
n = len(data)
# 1. 计算平均值
places = get_decimal_places(data_strs)
sum_val = sum(data)
mean = sum_val / n
# 修改:平均值修约使用“四舍六入五凑偶”
mean_final = mean.quantize(Decimal('1.' + '0' * places), rounding=ROUND_HALF_EVEN)
# 2. 计算标准差 s
variance = sum((x - mean) ** 2 for x in data) / (n - 1)
s = Decimal(str(math.sqrt(float(variance))))
# 3. A类不确定度 u_A
u_A = s / Decimal(str(math.sqrt(n)))
# 4. B类不确定度 u_B (仪器误差)
u_B = res / Decimal(str(math.sqrt(3)))
# 5. 合成不确定度 u
u = Decimal(str(math.sqrt(float(u_A**2 + u_B**2))))
return mean_final, s, u_A, u_B, u
def format_final_result(mean, u):
"""
按照“四舍六入五凑偶”修约:
1. 不确定度 u 保留一位有效数字
2. 平均值末位与 u 对齐
"""
u_float = float(u)
# 找到第一位非零数字的位置
first_digit_pos = math.floor(math.log10(u_float))
prec = Decimal('1e' + str(first_digit_pos))
# 修改:不确定度 u 的修约改为 ROUND_HALF_EVEN
u_final = u.quantize(prec, rounding=ROUND_HALF_EVEN)
# 修改:平均值修约保持一致
mean_final = mean.quantize(prec, rounding=ROUND_HALF_EVEN)
return f"f = {mean_final} ± {u_final}"
if __name__ == "__main__":
# ... (后续输入输出逻辑保持不变)
print("请输入数据,用空格分隔:")
raw_input = input().split()
print("请输入仪器分度值(默认 0.05):")
res_input = input().strip() or "0.05"
mean_f, s, u_A, u_B, u = calc_uncertainty(raw_input, res_input)
print("\n--- 中间计算过程 (高精度展示) ---")
print(f"平均值 (原始精度): {mean_f}")
print(f"标准差 s: {s:.6f}")
print(f"A类不确定度 u_A: {u_A:.6f}")
print(f"B类不确定度 u_B: {u_B:.6f}")
print(f"合成不确定度 u: {u:.6f}")
print("\n--- 最终修约结果 (四舍六入五凑偶) ---")
print(format_final_result(mean_f, u))