提取工具函数
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
import math
|
import math
|
||||||
from decimal import Decimal, ROUND_HALF_EVEN
|
from decimal import Decimal, ROUND_HALF_EVEN
|
||||||
|
from utils import (
|
||||||
|
scientific_round,
|
||||||
|
calculate_stats,
|
||||||
|
input_decimal,
|
||||||
|
input_int
|
||||||
|
)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Wheatstone Bridge Resistance Measurement Calculator
|
Wheatstone Bridge Resistance Measurement Calculator
|
||||||
@@ -56,71 +62,6 @@ Wheatstone Bridge Resistance Measurement Calculator
|
|||||||
Rx 末位与不确定度对齐
|
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):
|
def measure_one_ratio(ratio_label, C_value, R_nominal, n_measurements):
|
||||||
"""
|
"""
|
||||||
@@ -174,7 +115,7 @@ def measure_one_ratio(ratio_label, C_value, R_nominal, n_measurements):
|
|||||||
delta_inst = R0_mean / S
|
delta_inst = R0_mean / S
|
||||||
|
|
||||||
# --- 不确定度分析 ---
|
# --- 不确定度分析 ---
|
||||||
R0_mean_final, u_a_R0, u_b_R0, u_R0 = calculate_stats(R0_data, str(delta_inst))
|
R0_mean_final, u_R0, u_a_R0, u_b_R0, _ = calculate_stats(R0_data, str(delta_inst))
|
||||||
|
|
||||||
# Rx = C * R0
|
# Rx = C * R0
|
||||||
Rx_mean = C * R0_mean_final
|
Rx_mean = C * R0_mean_final
|
||||||
|
|||||||
+8
-65
@@ -83,68 +83,11 @@ Hall Effect Experiment Data Processor
|
|||||||
# 通用工具函数
|
# 通用工具函数
|
||||||
# ═══════════════════════════════════════════════════════
|
# ═══════════════════════════════════════════════════════
|
||||||
|
|
||||||
def scientific_round(value, uncertainty):
|
from utils import (
|
||||||
"""
|
scientific_round,
|
||||||
按照"四舍六入五凑偶"修约:
|
linear_regression,
|
||||||
1. 不确定度 u 保留一位有效数字
|
input_float
|
||||||
2. 结果末位与 u 对齐
|
)
|
||||||
"""
|
|
||||||
if uncertainty <= 0:
|
|
||||||
return str(value), "0"
|
|
||||||
|
|
||||||
d_val = Decimal(str(value))
|
|
||||||
d_unc = Decimal(str(uncertainty))
|
|
||||||
|
|
||||||
first_digit_pos = math.floor(math.log10(float(d_unc)))
|
|
||||||
prec = Decimal('1e' + str(first_digit_pos))
|
|
||||||
|
|
||||||
u_final = d_unc.quantize(prec, rounding=ROUND_HALF_EVEN)
|
|
||||||
val_final = d_val.quantize(prec, rounding=ROUND_HALF_EVEN)
|
|
||||||
|
|
||||||
return val_final, u_final
|
|
||||||
|
|
||||||
|
|
||||||
def linear_regression(x_list, y_list):
|
|
||||||
"""
|
|
||||||
最小二乘法线性回归: y = k·x + b
|
|
||||||
返回: 斜率 k, 截距 b, 相关系数 r, 斜率不确定度 u_k
|
|
||||||
u_k = |k| · √[(1/r² − 1) / (n − 2)]
|
|
||||||
"""
|
|
||||||
n = len(x_list)
|
|
||||||
x_mean = sum(x_list) / n
|
|
||||||
y_mean = sum(y_list) / n
|
|
||||||
|
|
||||||
Lxx = sum((xi - x_mean) ** 2 for xi in x_list)
|
|
||||||
Lyy = sum((yi - y_mean) ** 2 for yi in y_list)
|
|
||||||
Lxy = sum((x_list[i] - x_mean) * (y_list[i] - y_mean) for i in range(n))
|
|
||||||
|
|
||||||
k = Lxy / Lxx if Lxx != 0 else 0.0
|
|
||||||
b = y_mean - k * x_mean
|
|
||||||
|
|
||||||
denom = math.sqrt(Lxx * Lyy) if Lxx * Lyy > 0 else 1.0
|
|
||||||
r = Lxy / denom
|
|
||||||
|
|
||||||
if abs(r) < 1.0 and n > 2:
|
|
||||||
u_k = abs(k) * math.sqrt((1.0 / r ** 2 - 1.0) / (n - 2))
|
|
||||||
else:
|
|
||||||
u_k = 0.0
|
|
||||||
|
|
||||||
return k, b, r, u_k
|
|
||||||
|
|
||||||
|
|
||||||
def input_float(prompt, default=None):
|
|
||||||
"""输入一个浮点数值,支持默认值"""
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
suffix = f" (默认 {default})" if default is not None else ""
|
|
||||||
val = input(f"{prompt}{suffix}: ").strip()
|
|
||||||
if not val and default is not None:
|
|
||||||
return float(default)
|
|
||||||
if not val:
|
|
||||||
continue
|
|
||||||
return float(val)
|
|
||||||
except Exception:
|
|
||||||
print(" 输入无效,请输入数字。")
|
|
||||||
|
|
||||||
|
|
||||||
def print_regression(label, k, b, r, u_k, x_unit, y_unit):
|
def print_regression(label, k, b, r, u_k, x_unit, y_unit):
|
||||||
@@ -259,7 +202,7 @@ def main():
|
|||||||
print(f"{'─' * 46}")
|
print(f"{'─' * 46}")
|
||||||
|
|
||||||
# 线性回归: VH(mV) vs Is(mA) —— 使用绝对值 VH
|
# 线性回归: VH(mV) vs Is(mA) —— 使用绝对值 VH
|
||||||
slope_1, intercept_1, r_1, u_slope_1 = linear_regression(Is_1, VH_abs_1)
|
slope_1, intercept_1, r_1, u_slope_1 = map(float, linear_regression(Is_1, VH_abs_1))
|
||||||
print_regression("VH-Is", slope_1, intercept_1, r_1, u_slope_1, "mA", "mV")
|
print_regression("VH-Is", slope_1, intercept_1, r_1, u_slope_1, "mA", "mV")
|
||||||
|
|
||||||
# 注: 斜率单位 mV/mA = V/A
|
# 注: 斜率单位 mV/mA = V/A
|
||||||
@@ -321,7 +264,7 @@ def main():
|
|||||||
print(f"{'─' * 46}")
|
print(f"{'─' * 46}")
|
||||||
|
|
||||||
# 线性回归: VH(mV) vs Im(mA)
|
# 线性回归: VH(mV) vs Im(mA)
|
||||||
slope_2, intercept_2, r_2, u_slope_2 = linear_regression(Im_2, VH_abs_2)
|
slope_2, intercept_2, r_2, u_slope_2 = map(float, linear_regression(Im_2, VH_abs_2))
|
||||||
print_regression("VH-Im", slope_2, intercept_2, r_2, u_slope_2, "mA", "mV")
|
print_regression("VH-Im", slope_2, intercept_2, r_2, u_slope_2, "mA", "mV")
|
||||||
|
|
||||||
input("\n 按回车继续...")
|
input("\n 按回车继续...")
|
||||||
@@ -355,7 +298,7 @@ def main():
|
|||||||
print(f"{'─' * 36}")
|
print(f"{'─' * 36}")
|
||||||
|
|
||||||
# 线性回归: Vσ(mV) vs Is(mA)
|
# 线性回归: Vσ(mV) vs Is(mA)
|
||||||
slope_3, intercept_3, r_3, u_slope_3 = linear_regression(Is_3, Vsigma)
|
slope_3, intercept_3, r_3, u_slope_3 = map(float, linear_regression(Is_3, Vsigma))
|
||||||
print_regression("Vσ-Is", slope_3, intercept_3, r_3, u_slope_3, "mA", "mV")
|
print_regression("Vσ-Is", slope_3, intercept_3, r_3, u_slope_3, "mA", "mV")
|
||||||
print(f" 注: 斜率 = Vσ/Is, 单位 mV/mA = V/A = Ω (样品电阻)")
|
print(f" 注: 斜率 = Vσ/Is, 单位 mV/mA = V/A = Ω (样品电阻)")
|
||||||
|
|
||||||
|
|||||||
+1
-29
@@ -8,35 +8,7 @@ Newton's Rings Curvature Radius Calculator (Successive Difference Method)
|
|||||||
参考 lenth.py 的高精度与不确定度修约逻辑。
|
参考 lenth.py 的高精度与不确定度修约逻辑。
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_decimal_places(data_strings):
|
from utils import get_decimal_places, scientific_round
|
||||||
"""获取输入数据中小数点后的保留位数,用于自适应展示"""
|
|
||||||
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():
|
def main():
|
||||||
# --- 1. 参数与常量初始化 ---
|
# --- 1. 参数与常量初始化 ---
|
||||||
|
|||||||
+1
-17
@@ -33,23 +33,7 @@ Speed of Sound Calculator (Successive Difference Method)
|
|||||||
- 声速 v 的不确定度 (忽略 f 的极小不确定度): u(v) = f * u(λ)
|
- 声速 v 的不确定度 (忽略 f 的极小不确定度): u(v) = f * u(λ)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def scientific_round(value, uncertainty):
|
from utils import scientific_round
|
||||||
"""
|
|
||||||
按照“四舍六入五凑偶”修约:
|
|
||||||
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):
|
def calculate_method(method_name, f, k, delta_inst):
|
||||||
print(f"\n========================================")
|
print(f"\n========================================")
|
||||||
|
|||||||
@@ -44,87 +44,12 @@ Surface Tension Coefficient Calculator (Pull-off Method)
|
|||||||
u_B,X = Δ_inst / sqrt(3)
|
u_B,X = Δ_inst / sqrt(3)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def scientific_round(value, uncertainty):
|
from utils import (
|
||||||
"""
|
scientific_round,
|
||||||
按照“四舍六入五凑偶”修约:
|
calculate_stats,
|
||||||
1. 不确定度 u 保留一位有效数字
|
linear_regression,
|
||||||
2. 平均值末位与 u 对齐
|
input_data_group
|
||||||
"""
|
)
|
||||||
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():
|
def main():
|
||||||
print("========================================")
|
print("========================================")
|
||||||
@@ -196,15 +121,15 @@ def main():
|
|||||||
|
|
||||||
# 输入拉脱电压 U_pull (6次)
|
# 输入拉脱电压 U_pull (6次)
|
||||||
U_pull_vals = input_data_group("拉脱时的电压差/峰值电压 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)
|
U_pull_mean, U_pull_u = calculate_stats(U_pull_vals, delta_U)[:2]
|
||||||
|
|
||||||
# 输入内径 d1 (6次)
|
# 输入内径 d1 (6次)
|
||||||
d1_vals = input_data_group("铁环内径 d1", 6, "mm")
|
d1_vals = input_data_group("铁环内径 d1", 6, "mm")
|
||||||
d1_mean, d1_u = calculate_stats(d1_vals, delta_d)
|
d1_mean, d1_u = calculate_stats(d1_vals, delta_d)[:2]
|
||||||
|
|
||||||
# 输入外径 d2 (6次)
|
# 输入外径 d2 (6次)
|
||||||
d2_vals = input_data_group("铁环外径 d2", 6, "mm")
|
d2_vals = input_data_group("铁环外径 d2", 6, "mm")
|
||||||
d2_mean, d2_u = calculate_stats(d2_vals, delta_d)
|
d2_mean, d2_u = calculate_stats(d2_vals, delta_d)[:2]
|
||||||
|
|
||||||
# --- 3. 表面张力系数计算 ---
|
# --- 3. 表面张力系数计算 ---
|
||||||
# F = U / K
|
# F = U / K
|
||||||
|
|||||||
@@ -38,55 +38,11 @@ Viscosity Coefficient Calculator (Stokes' Law)
|
|||||||
u_B,X = Δ_inst / sqrt(3)
|
u_B,X = Δ_inst / sqrt(3)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def scientific_round(value, uncertainty):
|
from utils import (
|
||||||
"""
|
scientific_round,
|
||||||
按照“四舍六入五凑偶”修约:
|
calculate_stats,
|
||||||
1. 不确定度 u 保留一位有效数字
|
input_data_group
|
||||||
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():
|
def main():
|
||||||
print("========================================")
|
print("========================================")
|
||||||
@@ -129,7 +85,7 @@ def main():
|
|||||||
|
|
||||||
# 输入5个时间数据
|
# 输入5个时间数据
|
||||||
t_vals = input_data_group("小球下落时间 t", 5, "s")
|
t_vals = input_data_group("小球下落时间 t", 5, "s")
|
||||||
t_mean, t_u = calculate_stats(t_vals, delta_t)
|
t_mean, t_u = calculate_stats(t_vals, delta_t)[:2]
|
||||||
|
|
||||||
# --- 3. 粘滞系数计算 ---
|
# --- 3. 粘滞系数计算 ---
|
||||||
# 统一转化为国际标准单位 (m, kg, s)
|
# 统一转化为国际标准单位 (m, kg, s)
|
||||||
|
|||||||
+9
-60
@@ -20,62 +20,11 @@ Young's Modulus Calculator (Optical Lever & Successive Difference Method)
|
|||||||
u_B,X = Δ_inst / sqrt(3)
|
u_B,X = Δ_inst / sqrt(3)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def scientific_round(value, uncertainty):
|
from utils import (
|
||||||
"""
|
scientific_round,
|
||||||
按照“四舍六入五凑偶”修约:
|
calculate_stats,
|
||||||
1. 不确定度 u 保留一位有效数字(若首位是1或2,有时保留两位,此处统一保留一位)
|
input_data_group
|
||||||
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():
|
def main():
|
||||||
# --- 1. 常量设置 ---
|
# --- 1. 常量设置 ---
|
||||||
@@ -102,10 +51,10 @@ def main():
|
|||||||
delta_d = Decimal(input("d 的仪器误差 (mm, 默认 0.005): ").strip() or "0.005")
|
delta_d = Decimal(input("d 的仪器误差 (mm, 默认 0.005): ").strip() or "0.005")
|
||||||
delta_b = Decimal(input("b 的仪器误差 (mm, 默认 0.02): ").strip() or "0.02")
|
delta_b = Decimal(input("b 的仪器误差 (mm, 默认 0.02): ").strip() or "0.02")
|
||||||
|
|
||||||
L_mean, L_u = calculate_stats(L_vals, delta_L)
|
L_mean, L_u = calculate_stats(L_vals, delta_L)[:2]
|
||||||
D_mean, D_u = calculate_stats(D_vals, delta_D)
|
D_mean, D_u = calculate_stats(D_vals, delta_D)[:2]
|
||||||
d_mean, d_u = calculate_stats(d_vals, delta_d)
|
d_mean, d_u = calculate_stats(d_vals, delta_d)[:2]
|
||||||
b_mean, b_u = calculate_stats(b_vals, delta_b)
|
b_mean, b_u = calculate_stats(b_vals, delta_b)[:2]
|
||||||
|
|
||||||
# --- 3. 刻度值输入 (0-7个砝码, 加重+减重) ---
|
# --- 3. 刻度值输入 (0-7个砝码, 加重+减重) ---
|
||||||
print("\n--- 输入刻度尺读数 n (单位: mm) ---")
|
print("\n--- 输入刻度尺读数 n (单位: mm) ---")
|
||||||
|
|||||||
@@ -1,55 +1,11 @@
|
|||||||
import math
|
import math
|
||||||
from decimal import Decimal, ROUND_HALF_EVEN
|
from decimal import Decimal, ROUND_HALF_EVEN
|
||||||
|
|
||||||
def parse_angle_to_minutes(s):
|
from utils import (
|
||||||
"""
|
parse_angle_to_minutes,
|
||||||
将输入解析为内部统一单位:分钟(Decimal)。
|
format_minutes_as_angle,
|
||||||
支持格式:
|
scientific_round
|
||||||
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"):
|
def calc_uncertainty(data_strs, res_str="1"):
|
||||||
# 转换为分钟进行高精度计算
|
# 转换为分钟进行高精度计算
|
||||||
@@ -89,15 +45,11 @@ def format_final_result(mean_minutes, u_minutes):
|
|||||||
if u_float == 0:
|
if u_float == 0:
|
||||||
return f"θ = {format_minutes_as_angle(mean_minutes)} ± 0'"
|
return f"θ = {format_minutes_as_angle(mean_minutes)} ± 0'"
|
||||||
|
|
||||||
# 找到第一位非零数字的位置
|
|
||||||
first_digit_pos = math.floor(math.log10(u_float))
|
first_digit_pos = math.floor(math.log10(u_float))
|
||||||
prec = Decimal('1e' + str(first_digit_pos))
|
prec = Decimal('1e' + str(first_digit_pos))
|
||||||
|
|
||||||
# 修约
|
mean_final_val, u_final = scientific_round(mean_minutes, u_minutes)
|
||||||
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)
|
mean_str = format_minutes_as_angle(mean_final_val, prec)
|
||||||
u_str = f"{u_final}'"
|
u_str = f"{u_final}'"
|
||||||
|
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import math
|
import math
|
||||||
from decimal import Decimal, ROUND_HALF_EVEN
|
from decimal import Decimal, ROUND_HALF_EVEN
|
||||||
|
|
||||||
def get_decimal_places(data_strings):
|
from utils import get_decimal_places, scientific_round
|
||||||
"""获取输入数据中小数点后的位数"""
|
|
||||||
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"):
|
def calc_uncertainty(data_strs, res_str="0.05"):
|
||||||
# 转换为 Decimal 进行高精度计算
|
# 转换为 Decimal 进行高精度计算
|
||||||
@@ -44,17 +37,7 @@ def format_final_result(mean, u):
|
|||||||
1. 不确定度 u 保留一位有效数字
|
1. 不确定度 u 保留一位有效数字
|
||||||
2. 平均值末位与 u 对齐
|
2. 平均值末位与 u 对齐
|
||||||
"""
|
"""
|
||||||
u_float = float(u)
|
mean_final, u_final = scientific_round(mean, 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}"
|
return f"f = {mean_final} ± {u_final}"
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
from utils.formatting import (
|
||||||
|
get_decimal_places,
|
||||||
|
scientific_round,
|
||||||
|
parse_angle_to_minutes,
|
||||||
|
format_minutes_as_angle
|
||||||
|
)
|
||||||
|
from utils.stats import (
|
||||||
|
calculate_stats,
|
||||||
|
linear_regression
|
||||||
|
)
|
||||||
|
from utils.io import (
|
||||||
|
input_float,
|
||||||
|
input_decimal,
|
||||||
|
input_int,
|
||||||
|
input_data_group
|
||||||
|
)
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
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 scientific_round(value, uncertainty):
|
||||||
|
"""
|
||||||
|
按照“四舍六入五凑偶”修约:
|
||||||
|
1. 不确定度 u 保留一位有效数字
|
||||||
|
2. 平均值/结果末位与 u 对齐
|
||||||
|
"""
|
||||||
|
if uncertainty <= 0:
|
||||||
|
return str(value), "0"
|
||||||
|
|
||||||
|
d_val = Decimal(str(value))
|
||||||
|
d_unc = Decimal(str(uncertainty))
|
||||||
|
|
||||||
|
u_float = float(d_unc)
|
||||||
|
first_digit_pos = math.floor(math.log10(u_float))
|
||||||
|
prec = Decimal('1e' + str(first_digit_pos))
|
||||||
|
|
||||||
|
u_final = d_unc.quantize(prec, rounding=ROUND_HALF_EVEN)
|
||||||
|
val_final = d_val.quantize(prec, rounding=ROUND_HALF_EVEN)
|
||||||
|
|
||||||
|
return val_final, u_final
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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}'"
|
||||||
+59
@@ -0,0 +1,59 @@
|
|||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
def input_float(prompt, default=None):
|
||||||
|
"""输入一个浮点数值,支持默认值"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
suffix = f" (默认 {default})" if default is not None else ""
|
||||||
|
val = input(f"{prompt}{suffix}: ").strip()
|
||||||
|
if not val and default is not None:
|
||||||
|
return float(default)
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
return float(val)
|
||||||
|
except Exception:
|
||||||
|
print(" 输入无效,请输入数字。")
|
||||||
|
|
||||||
|
def input_decimal(prompt, default=None):
|
||||||
|
"""输入一个 Decimal 值,支持默认值"""
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
suffix = f" (默认 {default})" if default is not None 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 is not None else ""
|
||||||
|
val = input(f"{prompt}{suffix}: ").strip()
|
||||||
|
if not val and default is not None:
|
||||||
|
return default
|
||||||
|
if not val:
|
||||||
|
continue
|
||||||
|
return int(val)
|
||||||
|
except Exception:
|
||||||
|
print(" 输入无效,请输入整数。")
|
||||||
|
|
||||||
|
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
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import math
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
def calculate_stats(data_list, delta_inst):
|
||||||
|
"""
|
||||||
|
计算一组数据的平均值、A类、B类及合成不确定度。
|
||||||
|
支持输入 list of Decimal 或 list of float/str/int。
|
||||||
|
|
||||||
|
返回: (mean, u_combined, u_a, u_b, s)
|
||||||
|
"""
|
||||||
|
n = len(data_list)
|
||||||
|
decimal_data = [Decimal(str(x)) for x in data_list]
|
||||||
|
mean = sum(decimal_data) / Decimal(n)
|
||||||
|
|
||||||
|
if n > 1:
|
||||||
|
variance = sum((x - mean)**2 for x in decimal_data) / Decimal(n - 1)
|
||||||
|
s = Decimal(str(math.sqrt(float(variance))))
|
||||||
|
u_a = s / Decimal(str(math.sqrt(n)))
|
||||||
|
else:
|
||||||
|
s = Decimal("0")
|
||||||
|
u_a = Decimal("0")
|
||||||
|
|
||||||
|
u_b = Decimal(str(delta_inst)) / Decimal(str(math.sqrt(3)))
|
||||||
|
u_combined = Decimal(str(math.sqrt(float(u_a**2 + u_b**2))))
|
||||||
|
|
||||||
|
return mean, u_combined, u_a, u_b, s
|
||||||
|
|
||||||
|
def linear_regression(x_list, y_list):
|
||||||
|
"""
|
||||||
|
最小二乘法线性回归: y = k·x + b
|
||||||
|
返回: (k, b, r, u_k)
|
||||||
|
u_k = |k| · √[(1/r² − 1) / (n − 2)]
|
||||||
|
支持 input numbers as Decimal or float.
|
||||||
|
"""
|
||||||
|
n = len(x_list)
|
||||||
|
x_dec = [Decimal(str(x)) for x in x_list]
|
||||||
|
y_dec = [Decimal(str(y)) for y in y_list]
|
||||||
|
|
||||||
|
x_mean = sum(x_dec) / Decimal(n)
|
||||||
|
y_mean = sum(y_dec) / Decimal(n)
|
||||||
|
|
||||||
|
L_xx = sum((x - x_mean)**2 for x in x_dec)
|
||||||
|
L_yy = sum((y - y_mean)**2 for y in y_dec)
|
||||||
|
L_xy = sum((x_dec[i] - x_mean) * (y_dec[i] - y_mean) for i in range(n))
|
||||||
|
|
||||||
|
k = L_xy / L_xx if L_xx != 0 else Decimal("0")
|
||||||
|
b = y_mean - k * x_mean
|
||||||
|
|
||||||
|
denom = Decimal(str(math.sqrt(float(L_xx * L_yy)))) if L_xx * L_yy > 0 else Decimal("1")
|
||||||
|
r = L_xy / denom
|
||||||
|
|
||||||
|
r_float = float(r)
|
||||||
|
if abs(r_float) < 1.0 and n > 2:
|
||||||
|
u_k_float = float(abs(k)) * math.sqrt((1.0 / (r_float**2) - 1.0) / (n - 2))
|
||||||
|
else:
|
||||||
|
u_k_float = 0.0
|
||||||
|
u_k = Decimal(str(u_k_float))
|
||||||
|
|
||||||
|
return k, b, r, u_k
|
||||||
Reference in New Issue
Block a user