fork download
  1. import numpy as np
  2. import matplotlib.pyplot as plt
  3. from scipy import stats
  4. from scipy.interpolate import UnivariateSpline
  5. import warnings
  6. warnings.filterwarnings('ignore')
  7.  
  8. plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
  9. plt.rcParams['axes.unicode_minus'] = False
  10.  
  11. class SulfosalicylateIronExperiment:
  12. def __init__(self):
  13. self.fe_concentration = 0.001
  14. self.ligand_concentration = 0.001
  15. self.hclo4_concentration = 0.01
  16. self.hclo4_volume = 10.0
  17. self.total_mixing_volume = 10.0
  18. self.total_volume = self.hclo4_volume + self.total_mixing_volume
  19. self.mole_fractions = np.array([0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
  20. self.absorbances = None
  21. self.absorbances_all = None
  22.  
  23. def input_data(self):
  24. print("=== 磺基水杨酸铁配位数和稳定常数测定实验数据处理 ===")
  25. print("\n请输入11个数据点的吸光度值 (平行实验):")
  26. print("格式: 点1实验1 点1实验2 点2实验1 点2实验2 ... 点11实验1 点11实验2")
  27.  
  28. data_str = input("请输入22个吸光度值: ")
  29. data = list(map(float, data_str.split()))
  30.  
  31. if len(data) != 22:
  32. raise ValueError("必须输入22个吸光度值!")
  33.  
  34. self.absorbances_all = np.array(data).reshape(11, 2)
  35. self.absorbances = np.mean(self.absorbances_all, axis=1)
  36. self.absorbances_std = np.std(self.absorbances_all, axis=1, ddof=1)
  37.  
  38. print("\n数据输入完成!")
  39. print(f"摩尔分数: {self.mole_fractions}")
  40. print(f"平均吸光度: {self.absorbances}")
  41.  
  42. return self.mole_fractions, self.absorbances
  43.  
  44. def linear_fit(self, x_data, y_data):
  45. A = np.vstack([x_data, np.ones(len(x_data))]).T
  46. m, c = np.linalg.lstsq(A, y_data, rcond=None)[0]
  47. return m, c
  48.  
  49. def calculate_intersection(self, m1, c1, m2, c2):
  50. x_intersect = (c2 - c1) / (m1 - m2)
  51. y_intersect = m1 * x_intersect + c1
  52. return x_intersect, y_intersect
  53.  
  54. def find_curve_intersection(self, x_intersect):
  55. for i in range(len(self.mole_fractions)-1):
  56. if self.mole_fractions[i] <= x_intersect <= self.mole_fractions[i+1]:
  57. x1, x2 = self.mole_fractions[i], self.mole_fractions[i+1]
  58. y1, y2 = self.absorbances[i], self.absorbances[i+1]
  59. y_curve = y1 + (y2 - y1) * (x_intersect - x1) / (x2 - x1)
  60. return y_curve
  61. return self.absorbances[np.argmax(self.absorbances)]
  62.  
  63. def calculate_acid_effect(self, pH=2.5):
  64. H_plus = 10**(-pH)
  65. K2 = 10**(-2.6)
  66. K3 = 10**(-11.7)
  67.  
  68. alpha = 1 + H_plus/K3 + H_plus**2/(K2*K3)
  69. lg_alpha = np.log10(alpha)
  70.  
  71. return lg_alpha
  72.  
  73. def analyze_data(self):
  74. if self.absorbances is None:
  75. raise ValueError("请先输入数据!")
  76.  
  77. left_indices = [0, 1, 2]
  78. right_indices = [8, 9, 10]
  79.  
  80. m_left, c_left = self.linear_fit(
  81. self.mole_fractions[left_indices],
  82. self.absorbances[left_indices]
  83. )
  84.  
  85. m_right, c_right = self.linear_fit(
  86. self.mole_fractions[right_indices],
  87. self.absorbances[right_indices]
  88. )
  89.  
  90. x_intersect, D1 = self.calculate_intersection(m_left, c_left, m_right, c_right)
  91.  
  92. D2 = self.find_curve_intersection(x_intersect)
  93.  
  94. coordination_number = x_intersect / (1 - x_intersect)
  95.  
  96. if D1 > 0:
  97. dissociation_degree = (D1 - D2) / D1
  98. else:
  99. dissociation_degree = 0
  100.  
  101. fe_initial_moles = self.fe_concentration * (1 - x_intersect) * (self.total_mixing_volume / 2) / 1000
  102. complex_concentration = fe_initial_moles / (self.total_volume / 1000)
  103.  
  104. if dissociation_degree > 0 and dissociation_degree < 1:
  105. apparent_constant = (1 - dissociation_degree) / (complex_concentration * dissociation_degree**2)
  106.  
  107. lg_alpha = self.calculate_acid_effect()
  108. stability_constant = apparent_constant * (10**lg_alpha)
  109. else:
  110. stability_constant = float('inf')
  111. apparent_constant = 0
  112.  
  113. results = {
  114. 'D1': D1,
  115. 'D2': D2,
  116. 'x_intersect': x_intersect,
  117. 'coordination_number': coordination_number,
  118. 'dissociation_degree': dissociation_degree,
  119. 'stability_constant': stability_constant,
  120. 'apparent_constant': apparent_constant,
  121. 'lg_alpha': lg_alpha,
  122. 'left_fit': (m_left, c_left),
  123. 'right_fit': (m_right, c_right),
  124. 'complex_concentration': complex_concentration
  125. }
  126.  
  127. return results
  128.  
  129. def plot_results(self, results):
  130. if self.absorbances is None:
  131. raise ValueError("请先输入数据!")
  132.  
  133. plt.figure(figsize=(12, 8))
  134.  
  135. confidence_sizes = 100 + 200 * (1 / (self.absorbances_std + 0.001) / np.max(1 / (self.absorbances_std + 0.001)))
  136. plt.scatter(self.mole_fractions, self.absorbances, s=confidence_sizes, alpha=0.7, color='blue', label='实验数据点')
  137.  
  138. for i, (x, y) in enumerate(zip(self.mole_fractions, self.absorbances)):
  139. plt.annotate(f'{y:.3f}', (x, y), textcoords="offset points", xytext=(0,10), ha='center', fontsize=9)
  140.  
  141. if len(self.mole_fractions) > 3:
  142. spline = UnivariateSpline(self.mole_fractions, self.absorbances, s=0.001)
  143. x_smooth = np.linspace(0, 1, 200)
  144. y_smooth = spline(x_smooth)
  145. plt.plot(x_smooth, y_smooth, 'b-', alpha=0.7, linewidth=2, label='实验曲线')
  146.  
  147. x_left = np.array([0.0, results['x_intersect']])
  148. x_right = np.array([results['x_intersect'], 1.0])
  149.  
  150. m_left, c_left = results['left_fit']
  151. m_right, c_right = results['right_fit']
  152.  
  153. x_fit_left = np.linspace(0.0, results['x_intersect'], 50)
  154. y_fit_left = m_left * x_fit_left + c_left
  155.  
  156. x_fit_right = np.linspace(results['x_intersect'], 1.0, 50)
  157. y_fit_right = m_right * x_fit_right + c_right
  158.  
  159. plt.plot(x_fit_left, y_fit_left, 'r--', linewidth=2, label='左侧拟合直线')
  160. plt.plot(x_fit_right, y_fit_right, 'g--', linewidth=2, label='右侧拟合直线')
  161.  
  162. plt.text(0.1, 0.1, f'左侧: y = {m_left:.3f}x + {c_left:.3f}', transform=plt.gca().transAxes, fontsize=10, color='red')
  163. plt.text(0.1, 0.05, f'右侧: y = {m_right:.3f}x + {c_right:.3f}', transform=plt.gca().transAxes, fontsize=10, color='green')
  164.  
  165. plt.axvline(x=results['x_intersect'], color='gray', linestyle=':', alpha=0.7, label=f'交点X坐标: {results["x_intersect"]:.3f}')
  166.  
  167. plt.scatter([results['x_intersect']], [results['D1']], color='red', s=100, label='理论交点')
  168. plt.scatter([results['x_intersect']], [results['D2']], color='green', s=100, label='实际交点')
  169.  
  170. plt.annotate(f'理论: {results["D1"]:.3f}',
  171. (results['x_intersect'], results['D1']),
  172. textcoords="offset points", xytext=(10,10), ha='left', fontsize=9, color='red')
  173.  
  174. plt.annotate(f'实际: {results["D2"]:.3f}',
  175. (results['x_intersect'], results['D2']),
  176. textcoords="offset points", xytext=(10,-15), ha='left', fontsize=9, color='green')
  177.  
  178. plt.xlabel('磺基水杨酸的摩尔分数')
  179. plt.ylabel('吸光度 (A)')
  180.  
  181. plt.title('磺基水杨酸铁(Ⅲ)配合物组成与稳定常数测定结果图', fontsize=20, pad=20)
  182.  
  183. plt.text(0.98, 0.98, "由何同学与D老师联合制作",
  184. transform=plt.gca().transAxes,
  185. fontsize=6, color='gray',
  186. ha='right', va='top',
  187. bbox=dict(boxstyle="round,pad=0.2", facecolor="white", alpha=0.8))
  188.  
  189. textstr = '\n'.join([
  190. f'配合物组成: ML{results["coordination_number"]:.1f}',
  191. f'交点X坐标: {results["x_intersect"]:.3f}',
  192. f'解离度: {results["dissociation_degree"]:.4f}',
  193. f'稳定常数: {results["stability_constant"]:.2e} L/mol'
  194. ])
  195. props = dict(boxstyle='round', facecolor='wheat', alpha=0.8)
  196. plt.text(0.65, 0.25, textstr, transform=plt.gca().transAxes, fontsize=12,
  197. verticalalignment='top', bbox=props)
  198.  
  199. plt.grid(True, alpha=0.3)
  200. plt.legend(loc='upper left')
  201. plt.tight_layout()
  202. plt.show()
  203.  
  204. return plt.gcf()
  205.  
  206. def run_analysis(self):
  207. try:
  208. self.input_data()
  209. results = self.analyze_data()
  210.  
  211. print("\n" + "="*60)
  212. print("实验结果分析")
  213. print("="*60)
  214. print(f"配合物组成: ML{results['coordination_number']:.1f}")
  215. print(f"交点X坐标: {results['x_intersect']:.3f}")
  216. print(f"解离度: {results['dissociation_degree']:.4f}")
  217. print(f"表观稳定常数: {results['apparent_constant']:.2e} L/mol")
  218. print(f"酸效应系数 lgα: {results['lg_alpha']:.3f}")
  219. print(f"热力学稳定常数: {results['stability_constant']:.2e} L/mol")
  220.  
  221. print("\n生成图表中...")
  222. self.plot_results(results)
  223. print("图表已显示,请查看弹出窗口。")
  224.  
  225. except Exception as e:
  226. print(f"错误: {e}")
  227. print("请检查输入数据格式是否正确。")
  228.  
  229. if __name__ == "__main__":
  230. experiment = SulfosalicylateIronExperiment()
  231. experiment.run_analysis()
Success #stdin #stdout 1.25s 69580KB
stdin
Standard input is empty
stdout
=== 磺基水杨酸铁配位数和稳定常数测定实验数据处理 ===

请输入11个数据点的吸光度值 (平行实验):
格式: 点1实验1 点1实验2 点2实验1 点2实验2 ... 点11实验1 点11实验2
请输入22个吸光度值: 错误: EOF when reading a line
请检查输入数据格式是否正确。