error.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // error.js - 示值误差测试相关功能
  2. // 图表相关变量
  3. let errorCtx = null;
  4. let errorChartInstance = null;
  5. // 初始化示值误差图表
  6. function initErrorChart() {
  7. errorCtx = document.getElementById('errorChart').getContext('2d');
  8. }
  9. // 在页面加载完成后初始化图表
  10. document.addEventListener('DOMContentLoaded', function() {
  11. initErrorChart();
  12. });
  13. // 示值误差测试函数
  14. function updateErrorPoint(input) {
  15. const pointContainer = input.closest('.error-point-container');
  16. const originalValue = input.getAttribute('data-original');
  17. const newValue = input.value;
  18. // 如果测试点值发生变化,更新所有相关元素的data-point属性
  19. if (originalValue !== newValue) {
  20. input.setAttribute('data-original', newValue);
  21. pointContainer.querySelectorAll('.error-input').forEach(input => {
  22. input.setAttribute('data-point', newValue);
  23. });
  24. pointContainer.querySelector('.error-avg').setAttribute('data-point', newValue);
  25. pointContainer.querySelector('.error-value').setAttribute('data-point', newValue);
  26. }
  27. calculateError();
  28. }
  29. function createErrorPointContainer(pointValue = '') {
  30. const container = document.createElement('div');
  31. container.className = 'error-point-container';
  32. container.style.marginBottom = '1rem';
  33. container.style.padding = '1rem';
  34. container.style.border = '1px solid #eee';
  35. container.style.borderRadius = '4px';
  36. // 测试点输入
  37. const pointRow = document.createElement('div');
  38. pointRow.style.display = 'flex';
  39. pointRow.style.alignItems = 'center';
  40. pointRow.style.marginBottom = '0.5rem';
  41. const pointLabel = document.createElement('label');
  42. pointLabel.textContent = '测试点:';
  43. pointLabel.style.marginRight = '0.5rem';
  44. pointLabel.style.fontWeight = 'bold';
  45. const pointInput = document.createElement('input');
  46. pointInput.type = 'number';
  47. pointInput.className = 'error-point-input';
  48. pointInput.placeholder = '输入测试点值';
  49. pointInput.value = pointValue;
  50. pointInput.setAttribute('data-original', pointValue);
  51. pointInput.style.flex = '1';
  52. pointInput.style.marginRight = '0.5rem';
  53. pointInput.oninput = function () {
  54. updateErrorPoint(this);
  55. // 保存示值误差数据到cookies
  56. saveErrorData();
  57. };
  58. const deleteBtn = document.createElement('span');
  59. deleteBtn.className = 'delete-btn';
  60. deleteBtn.innerHTML = '×';
  61. deleteBtn.onclick = function () {
  62. container.parentNode.removeChild(container);
  63. // 如果删除后没有测试点,添加一个新的空白测试点
  64. if (document.querySelectorAll('.error-point-container').length === 0) {
  65. addErrorPoint();
  66. }
  67. calculateError();
  68. // 保存误差数据到cookies
  69. saveErrorData();
  70. };
  71. pointRow.appendChild(pointLabel);
  72. pointRow.appendChild(pointInput);
  73. pointRow.appendChild(deleteBtn);
  74. // 输入值部分
  75. const inputsContainer = document.createElement('div');
  76. inputsContainer.className = 'error-inputs';
  77. inputsContainer.style.display = 'flex';
  78. inputsContainer.style.flexWrap = 'wrap';
  79. inputsContainer.style.gap = '0.5rem';
  80. inputsContainer.style.marginBottom = '0.5rem';
  81. // 添加3个默认输入框
  82. for (let i = 0; i < 3; i++) {
  83. const input = document.createElement('input');
  84. input.type = 'number';
  85. input.className = 'error-input';
  86. input.placeholder = `输入值 ${i + 1}`;
  87. input.setAttribute('data-point', pointValue);
  88. input.style.flex = '1';
  89. input.style.minWidth = '100px';
  90. input.oninput = function () {
  91. calculateError();
  92. // 保存误差数据到cookies
  93. saveErrorData();
  94. };
  95. inputsContainer.appendChild(input);
  96. }
  97. // 结果显示部分
  98. const resultsRow = document.createElement('div');
  99. resultsRow.style.display = 'flex';
  100. resultsRow.style.gap = '1rem';
  101. const avgContainer = document.createElement('div');
  102. avgContainer.style.flex = '1';
  103. const avgLabel = document.createElement('span');
  104. avgLabel.textContent = '平均值:';
  105. avgLabel.style.fontWeight = 'bold';
  106. const avgSpan = document.createElement('span');
  107. avgSpan.className = 'error-avg';
  108. avgSpan.setAttribute('data-point', pointValue);
  109. avgSpan.textContent = '-';
  110. avgContainer.appendChild(avgLabel);
  111. avgContainer.appendChild(avgSpan);
  112. const errorContainer = document.createElement('div');
  113. errorContainer.style.flex = '1';
  114. const errorLabel = document.createElement('span');
  115. errorLabel.textContent = '示值误差:';
  116. errorLabel.style.fontWeight = 'bold';
  117. const errorSpan = document.createElement('span');
  118. errorSpan.className = 'error-value';
  119. errorSpan.setAttribute('data-point', pointValue);
  120. errorSpan.textContent = '-';
  121. errorContainer.appendChild(errorLabel);
  122. errorContainer.appendChild(errorSpan);
  123. resultsRow.appendChild(avgContainer);
  124. resultsRow.appendChild(errorContainer);
  125. container.appendChild(pointRow);
  126. container.appendChild(inputsContainer);
  127. container.appendChild(resultsRow);
  128. return container;
  129. }
  130. function addErrorPoint() {
  131. const container = document.getElementById('error-inputs');
  132. const pointContainer = createErrorPointContainer();
  133. container.appendChild(pointContainer);
  134. updateErrorPoints();
  135. }
  136. function calculateError() {
  137. const pointContainers = document.querySelectorAll('.error-point-container');
  138. const errorData = [];
  139. pointContainers.forEach(container => {
  140. const pointInput = container.querySelector('.error-point-input');
  141. const inputs = container.querySelectorAll('.error-input');
  142. const avgSpan = container.querySelector('.error-avg');
  143. const errorSpan = container.querySelector('.error-value');
  144. const pointValue = parseFloat(pointInput.value);
  145. const values = Array.from(inputs)
  146. .map(input => parseFloat(input.value))
  147. .filter(value => !isNaN(value));
  148. if (!isNaN(pointValue) && values.length > 0) {
  149. // 计算平均值
  150. const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
  151. // 计算示值误差
  152. const error = avg - pointValue;
  153. // 更新显示
  154. avgSpan.textContent = avg.toFixed(6);
  155. errorSpan.textContent = error.toFixed(6);
  156. // 收集数据用于图表和不确定度计算
  157. errorData.push({
  158. point: pointValue,
  159. avg: avg,
  160. error: error
  161. });
  162. } else {
  163. avgSpan.textContent = '-';
  164. errorSpan.textContent = '-';
  165. }
  166. });
  167. // 更新图表
  168. updateErrorChart(errorData);
  169. // 计算不确定度
  170. calculateUncertainty(errorData);
  171. return errorData;
  172. }
  173. function calculateUncertainty(errorData) {
  174. if (errorData.length === 0) {
  175. // 清空不确定度显示
  176. document.getElementById('uncertainty-a').textContent = '-';
  177. document.getElementById('uncertainty-b').textContent = '-';
  178. document.getElementById('uncertainty-c').textContent = '-';
  179. document.getElementById('uncertainty-u').textContent = '-';
  180. return;
  181. }
  182. // 计算A类不确定度(重复测量的标准偏差)
  183. let sumSquaredDeviations = 0;
  184. let totalMeasurements = 0;
  185. document.querySelectorAll('.error-point-container').forEach(container => {
  186. const inputs = container.querySelectorAll('.error-input');
  187. const values = Array.from(inputs)
  188. .map(input => parseFloat(input.value))
  189. .filter(value => !isNaN(value));
  190. if (values.length > 0) {
  191. const avg = values.reduce((sum, val) => sum + val, 0) / values.length;
  192. values.forEach(value => {
  193. sumSquaredDeviations += Math.pow(value - avg, 2);
  194. });
  195. totalMeasurements += values.length;
  196. }
  197. });
  198. // 计算A类不确定度
  199. const uA = totalMeasurements > 1 ? Math.sqrt(sumSquaredDeviations / (totalMeasurements * (totalMeasurements - 1))) : 0;
  200. // 假设B类不确定度(仪器分辨率引起的不确定度)
  201. // 这里假设分辨率为0.001,则B类不确定度为0.001/√3
  202. const resolution = 0.001;
  203. const uB = resolution / Math.sqrt(3);
  204. // 合成不确定度
  205. const uC = Math.sqrt(Math.pow(uA, 2) + Math.pow(uB, 2));
  206. // 扩展不确定度(k=2,约95%置信水平)
  207. const U = 2 * uC;
  208. // 更新显示
  209. document.getElementById('uncertainty-a').textContent = uA.toExponential(3);
  210. document.getElementById('uncertainty-b').textContent = uB.toExponential(3);
  211. document.getElementById('uncertainty-c').textContent = uC.toExponential(3);
  212. document.getElementById('uncertainty-u').textContent = U.toExponential(3);
  213. }
  214. function updateErrorChart(data) {
  215. if (data.length === 0) {
  216. if (errorChartInstance) {
  217. errorChartInstance.data.labels = [];
  218. errorChartInstance.data.datasets[0].data = [];
  219. errorChartInstance.update();
  220. }
  221. return;
  222. }
  223. // 按测试点值排序
  224. data.sort((a, b) => a.point - b.point);
  225. // 提取标签和误差值
  226. const labels = data.map(item => item.point);
  227. const errorValues = data.map(item => item.error);
  228. // 使用通用图表创建函数
  229. errorChartInstance = createOrUpdateChart(errorChartInstance, errorCtx, labels, errorValues, '示值误差');
  230. }
  231. function saveErrorData() {
  232. const errorData = Array.from(document.querySelectorAll('.error-point-container')).map(container => {
  233. const pointInput = container.querySelector('.error-point-input');
  234. const inputs = container.querySelectorAll('.error-input');
  235. const avgSpan = container.querySelector('.error-avg');
  236. const errorSpan = container.querySelector('.error-value');
  237. return {
  238. point: pointInput.value,
  239. inputs: Array.from(inputs).map(input => input.value),
  240. avg: avgSpan.innerText,
  241. error: errorSpan.innerText
  242. };
  243. });
  244. setCookie('errorData', JSON.stringify(errorData), 365);
  245. }