| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
- <title>RT Table Import</title>
- <link rel="stylesheet" href="./styles.css">
- </head>
- <body>
- <header>
- <h1>RT Table Generator</h1>
- <ul class="nav-tabs">
- <li><a href="./RT_Table_NTC.html">NTC</a></li>
- <li><a href="./RT_Table_PT100.html">PT100</a></li>
- <li><a href="./RT_Table_PT1000.html">PT1000</a></li>
- <li><a href="./VT_Table_TJ.html">Thermocouple</a></li>
- <li><a href="./RT_Table_Import.html" class="active">Import Data</a></li>
- </ul>
- </header>
- <div class="container">
- <section>
- <h2 class="section-title">RT/VT Data Import Tool</h2>
- <div class="formula">
- <p>This tool allows you to import and analyze temperature-resistance (RT) or temperature-voltage (VT) data from various sources.</p>
- <p>Paste your data in the text area below. The tool supports the following formats:</p>
- <ul style="text-align: left; margin: 10px auto; display: inline-block;">
- <li>CSV format (comma, tab, or space separated)</li>
- <li>Excel data (copied directly from spreadsheet)</li>
- <li>Plain text with temperature and resistance/voltage values</li>
- </ul>
- <p>The first column should be temperature values, and the second column should be resistance or voltage values.</p>
- </div>
- </section>
- <section>
- <h2 class="section-title">Import Data</h2>
- <!-- 数据导入区域 -->
- <div>
- <textarea id="importData" placeholder="Paste your temperature and resistance/voltage data here..."></textarea>
- <div style="margin: 10px 0;">
- <label for="data-type">Data Type:</label>
- <select id="data-type" class="tableInput" style="width: auto; margin-right: 20px;">
- <option value="RT">RT Data (Temperature-Resistance)</option>
- <option value="VT">VT Data (Temperature-Voltage)</option>
- </select>
- <label for="delimiter">Delimiter:</label>
- <select id="delimiter" class="tableInput" style="width: auto;">
- <option value="auto">Auto Detect</option>
- <option value="tab">Tab</option>
- <option value="comma">Comma</option>
- <option value="space">Space</option>
- <option value="semicolon">Semicolon</option>
- </select>
- </div>
- <button onclick="processImportedData()">Process Data</button>
- </div>
- </section>
- <section>
- <h2 class="section-title">Parameters</h2>
- <!-- 参数设置 -->
- <div>
- <table class="params-table">
- <tr>
- <td>
- <label for="param_name">Name Prefix:</label>
- </td>
- <td>
- <input type="text" id="param_name" name="param_name" value="Custom" class="tableInput">
- </td>
- </tr>
- <tr>
- <td>
- <label for="param_T_min">Data Temperature Min (°C):</label>
- </td>
- <td>
- <input type="number" id="param_T_min" name="param_T_min" value="0" class="tableInput" readonly>
- </td>
- </tr>
- <tr>
- <td>
- <label for="param_T_max">Data Temperature Max (°C):</label>
- </td>
- <td>
- <input type="number" id="param_T_max" name="param_T_max" value="0" class="tableInput" readonly>
- </td>
- </tr>
- <tr>
- <td>
- <label for="param_step">Data Temperature Step (°C):</label>
- </td>
- <td>
- <input type="number" id="param_step" name="param_step" value="0" class="tableInput" readonly>
- </td>
- </tr>
- <tr>
- <td>
- <label for="output_T_min">Output Temperature Min (°C):</label>
- </td>
- <td>
- <input type="number" id="output_T_min" name="output_T_min" value="0" class="tableInput">
- </td>
- </tr>
- <tr>
- <td>
- <label for="output_T_max">Output Temperature Max (°C):</label>
- </td>
- <td>
- <input type="number" id="output_T_max" name="output_T_max" value="0" class="tableInput">
- </td>
- </tr>
- <tr>
- <td>
- <label for="interpolation">Interpolation Method:</label>
- </td>
- <td>
- <select id="interpolation" class="tableInput">
- <option value="linear">Linear</option>
- <option value="polynomial">Polynomial</option>
- </select>
- </td>
- </tr>
- <tr id="polynomial-degree-row" style="display: none;">
- <td>
- <label for="polynomial-degree">Polynomial Degree:</label>
- </td>
- <td>
- <input type="number" id="polynomial-degree" name="polynomial-degree" value="3" min="2" max="10" class="tableInput">
- </td>
- </tr>
- <tr>
- <td>
- <label for="output-step">Output Step (°C):</label>
- </td>
- <td>
- <input type="number" id="output-step" name="output-step" value="1" min="0.1" step="0.1" class="tableInput">
- </td>
- </tr>
- <tr>
- <td>
- <label for="result-coefficient">Result Coefficient:</label>
- </td>
- <td>
- <input type="number" id="result-coefficient" name="result-coefficient" value="1" min="0.001" step="0.001" class="tableInput">
- </td>
- </tr>
- <tr>
- <td colspan="2">
- <button onclick="generateOutputTable()">Generate Output Table</button>
- </td>
- </tr>
- </table>
- </div>
- </section>
- <section>
- <h2 class="section-title">Results</h2>
- <!-- 动态生成的表格 -->
- <div style="max-height: 400px; overflow-y: auto; margin-bottom: 20px;">
- <table id="rtTable">
- <thead>
- <tr>
- <th>Temperature (°C)</th>
- <th id="value-header">Resistance (Ω)</th>
- </tr>
- </thead>
- <tbody>
- <!-- 数据将通过JavaScript动态插入 -->
- </tbody>
- </table>
- </div>
- <!-- JSON 数据文本框 -->
- <h3>JSON Data</h3>
- <textarea id="jsonData" readonly></textarea>
- <!-- C语言数组文本框 -->
- <h3>C Language Arrays</h3>
- <textarea id="cArrayData" readonly></textarea>
- </section>
- </div>
- <script>
- // 全局变量
- let importedData = [];
- let processedData = [];
- // 页面加载时初始化
- document.addEventListener('DOMContentLoaded', function() {
- // 设置默认数据类型为RT
- document.getElementById('data-type').value = 'RT';
- // 初始化输出温度范围
- document.getElementById('output_T_min').value = 0;
- document.getElementById('output_T_max').value = 0;
- });
- // 检测分隔符
- function detectDelimiter(text) {
- const lines = text.trim().split(/\r?\n/);
- if (lines.length === 0) return 'tab';
- const firstLine = lines[0];
- // 检查各种分隔符的出现次数
- const delimiters = {
- 'tab': (firstLine.match(/\t/g) || []).length,
- 'comma': (firstLine.match(/,/g) || []).length,
- 'semicolon': (firstLine.match(/;/g) || []).length,
- 'space': (firstLine.match(/ /g) || []).length
- };
- // 找出出现次数最多的分隔符
- let maxCount = 0;
- let detectedDelimiter = 'tab';
- for (const [delimiter, count] of Object.entries(delimiters)) {
- if (count > maxCount) {
- maxCount = count;
- detectedDelimiter = delimiter;
- }
- }
- return detectedDelimiter;
- }
- // 处理导入的数据
- function processImportedData() {
- const importText = document.getElementById("importData").value.trim();
- if (!importText) {
- alert("Please paste data first!");
- return;
- }
- // 获取用户选择的分隔符或自动检测
- let delimiterChoice = document.getElementById("delimiter").value;
- let delimiterChar;
- if (delimiterChoice === 'auto') {
- delimiterChoice = detectDelimiter(importText);
- }
- // 设置实际的分隔符字符
- switch (delimiterChoice) {
- case 'tab': delimiterChar = '\t'; break;
- case 'comma': delimiterChar = ','; break;
- case 'space': delimiterChar = ' '; break;
- case 'semicolon': delimiterChar = ';'; break;
- default: delimiterChar = '\t';
- }
- // 分割文本为行
- const lines = importText.split(/\r?\n/);
- importedData = [];
- // 处理每一行
- for (const line of lines) {
- if (!line.trim()) continue; // 跳过空行
- // 分割行为列
- let columns;
- if (delimiterChoice === 'space') {
- // 对于空格分隔,处理多个连续空格的情况
- columns = line.trim().split(/\s+/);
- } else {
- columns = line.split(delimiterChar);
- }
- // 确保至少有两列
- if (columns.length >= 2) {
- const temp = parseFloat(columns[0]);
- const value = parseFloat(columns[1]);
- // 确保两个值都是有效的数字
- if (!isNaN(temp) && !isNaN(value)) {
- importedData.push({ temperature: temp, value: value });
- }
- }
- }
- // 按温度排序
- importedData.sort((a, b) => a.temperature - b.temperature);
- // 更新数据类型标题
- const dataType = document.getElementById("data-type").value;
- const valueHeader = document.getElementById("value-header");
- if (dataType === "RT") {
- valueHeader.textContent = "Resistance (Ω)";
- } else {
- valueHeader.textContent = "Voltage (mV)";
- }
- // 显示导入的数据
- displayTable(importedData);
- // 更新参数
- if (importedData.length > 0) {
- // 设置温度范围
- const minTemp = importedData[0].temperature;
- const maxTemp = importedData[importedData.length - 1].temperature;
- document.getElementById("param_T_min").value = minTemp;
- document.getElementById("param_T_max").value = maxTemp;
- // 同时更新输出温度范围
- document.getElementById("output_T_min").value = minTemp;
- document.getElementById("output_T_max").value = maxTemp;
- // 计算平均步长
- if (importedData.length > 1) {
- let totalSteps = 0;
- let stepCount = 0;
- for (let i = 1; i < importedData.length; i++) {
- const step = importedData[i].temperature - importedData[i-1].temperature;
- if (step > 0) {
- totalSteps += step;
- stepCount++;
- }
- }
- const avgStep = stepCount > 0 ? (totalSteps / stepCount) : 1;
- document.getElementById("param_step").value = avgStep.toFixed(2);
- document.getElementById("output-step").value = avgStep.toFixed(2);
- }
- }
- // 显示JSON数据
- displayJsonData(importedData);
- }
- // 线性插值函数
- function linearInterpolate(x, x0, y0, x1, y1) {
- return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
- }
- // 多项式拟合函数
- function polynomialFit(data, degree) {
- // 简单实现,实际应用中可能需要更复杂的算法
- // 这里使用最小二乘法拟合多项式
- const n = data.length;
- const x = data.map(d => d.temperature);
- const y = data.map(d => d.value);
- // 创建矩阵
- const X = [];
- for (let i = 0; i < n; i++) {
- X[i] = [];
- for (let j = 0; j <= degree; j++) {
- X[i][j] = Math.pow(x[i], j);
- }
- }
- // 转置矩阵
- const Xt = [];
- for (let j = 0; j <= degree; j++) {
- Xt[j] = [];
- for (let i = 0; i < n; i++) {
- Xt[j][i] = X[i][j];
- }
- }
- // 计算 Xt * X
- const XtX = [];
- for (let i = 0; i <= degree; i++) {
- XtX[i] = [];
- for (let j = 0; j <= degree; j++) {
- XtX[i][j] = 0;
- for (let k = 0; k < n; k++) {
- XtX[i][j] += Xt[i][k] * X[k][j];
- }
- }
- }
- // 计算 Xt * y
- const Xty = [];
- for (let i = 0; i <= degree; i++) {
- Xty[i] = 0;
- for (let j = 0; j < n; j++) {
- Xty[i] += Xt[i][j] * y[j];
- }
- }
- // 解线性方程组 XtX * coeffs = Xty
- // 使用高斯消元法
- const coeffs = solveLinearSystem(XtX, Xty);
- // 返回多项式函数
- return function(x) {
- let result = 0;
- for (let i = 0; i <= degree; i++) {
- result += coeffs[i] * Math.pow(x, i);
- }
- return result;
- };
- }
- // 解线性方程组
- function solveLinearSystem(A, b) {
- const n = b.length;
- const x = new Array(n).fill(0);
- // 高斯消元法
- for (let i = 0; i < n; i++) {
- // 寻找主元
- let maxEl = Math.abs(A[i][i]);
- let maxRow = i;
- for (let k = i + 1; k < n; k++) {
- if (Math.abs(A[k][i]) > maxEl) {
- maxEl = Math.abs(A[k][i]);
- maxRow = k;
- }
- }
- // 交换行
- if (maxRow !== i) {
- [A[i], A[maxRow]] = [A[maxRow], A[i]];
- [b[i], b[maxRow]] = [b[maxRow], b[i]];
- }
- // 消元
- for (let k = i + 1; k < n; k++) {
- const c = -A[k][i] / A[i][i];
- for (let j = i; j < n; j++) {
- if (i === j) {
- A[k][j] = 0;
- } else {
- A[k][j] += c * A[i][j];
- }
- }
- b[k] += c * b[i];
- }
- }
- // 回代
- for (let i = n - 1; i >= 0; i--) {
- x[i] = b[i] / A[i][i];
- for (let k = i - 1; k >= 0; k--) {
- b[k] -= A[k][i] * x[i];
- }
- }
- return x;
- }
- // 生成输出表格
- function generateOutputTable() {
- if (importedData.length === 0) {
- alert("Please import and process data first!");
- return;
- }
- // 使用用户设置的输出温度范围,如果未设置则使用数据的温度范围
- let Tmin = parseFloat(document.getElementById("output_T_min").value);
- let Tmax = parseFloat(document.getElementById("output_T_max").value);
- const dataTmin = parseFloat(document.getElementById("param_T_min").value);
- const dataTmax = parseFloat(document.getElementById("param_T_max").value);
- // 验证输出温度范围
- if (isNaN(Tmin) || Tmin < dataTmin) {
- Tmin = dataTmin;
- document.getElementById("output_T_min").value = dataTmin;
- }
- if (isNaN(Tmax) || Tmax > dataTmax) {
- Tmax = dataTmax;
- document.getElementById("output_T_max").value = dataTmax;
- }
- if (Tmin > Tmax) {
- Tmin = dataTmin;
- Tmax = dataTmax;
- document.getElementById("output_T_min").value = dataTmin;
- document.getElementById("output_T_max").value = dataTmax;
- alert("Output temperature min cannot be greater than max. Using data range instead.");
- }
- const step = parseFloat(document.getElementById("output-step").value);
- const resultCoefficient = parseFloat(document.getElementById("result-coefficient").value);
- const interpolationMethod = document.getElementById("interpolation").value;
- processedData = [];
- if (interpolationMethod === "linear") {
- // 线性插值
- for (let T = Tmin; T <= Tmax; T += step) {
- // 找到T所在的区间
- let value;
- // 如果T小于第一个点或大于最后一个点,使用外推
- if (T <= importedData[0].temperature) {
- value = importedData[0].value;
- } else if (T >= importedData[importedData.length - 1].temperature) {
- value = importedData[importedData.length - 1].value;
- } else {
- // 找到T所在的区间
- for (let i = 0; i < importedData.length - 1; i++) {
- if (T >= importedData[i].temperature && T <= importedData[i + 1].temperature) {
- value = linearInterpolate(
- T,
- importedData[i].temperature,
- importedData[i].value,
- importedData[i + 1].temperature,
- importedData[i + 1].value
- );
- break;
- }
- }
- }
- // 应用系数并限制小数位数为6位,并去除末尾的0
- const roundedT = Number(T.toFixed(6));
- const roundedValue = Number((value * resultCoefficient).toFixed(6));
- processedData.push({ temperature: roundedT, value: roundedValue });
- }
- } else if (interpolationMethod === "polynomial") {
- // 多项式拟合
- const degree = parseInt(document.getElementById("polynomial-degree").value);
- const polyFunc = polynomialFit(importedData, degree);
- for (let T = Tmin; T <= Tmax; T += step) {
- // 应用系数并限制小数位数为6位,并去除末尾的0
- const roundedT = Number(T.toFixed(6));
- const value = Number((polyFunc(T) * resultCoefficient).toFixed(6));
- processedData.push({ temperature: roundedT, value: value });
- }
- }
- // 显示处理后的数据
- displayTable(processedData);
- displayJsonData(processedData);
- displayCArrayData(processedData);
- }
- // 显示表格数据
- function displayTable(data) {
- const tbody = document.getElementById("rtTable").querySelector("tbody");
- tbody.innerHTML = ""; // 清空表格内容
- const dataType = document.getElementById("data-type").value;
- data.forEach(row => {
- const tr = document.createElement("tr");
- // 限制小数位数为6位,并去除末尾的0
- const displayValue = Number(row.value.toFixed(6));
- const tempValue = Number(row.temperature.toFixed(6));
- if (dataType === "RT") {
- tr.innerHTML = `<td>${tempValue}</td><td>${displayValue}</td>`;
- } else {
- tr.innerHTML = `<td>${tempValue}</td><td>${displayValue}</td>`;
- }
- tbody.appendChild(tr);
- });
- }
- // 显示 JSON 数据到文本框
- function displayJsonData(data) {
- // 应用小数位数限制,并去除末尾的0
- const dataWithLimitedDecimals = data.map(item => ({
- temperature: Number(item.temperature.toFixed(6)), // 限制温度小数位数为6位并去除末尾的0
- value: Number(item.value.toFixed(6)) // 限制值小数位数为6位并去除末尾的0
- }));
- const jsonData = JSON.stringify(dataWithLimitedDecimals, null, 4); // 格式化JSON
- const textarea = document.getElementById("jsonData");
- textarea.value = jsonData;
- }
- // 显示 C 语言数组到文本框
- function displayCArrayData(data) {
- if (data.length === 0) return;
- // 提取温度值和值,并限制小数位数为6位,去除末尾的0
- const temperatures = data.map(row => Number(row.temperature.toFixed(6))); // 限制温度小数位数为6位并去除末尾的0
- const values = data.map(row => Number(row.value.toFixed(6))); // 限制值小数位数为6位并去除末尾的0
- const dataType = document.getElementById("data-type").value;
- const namePrefix = document.getElementById("param_name").value;
- const Tmin = Number(data[0].temperature.toFixed(6));
- const Tmax = Number(data[data.length - 1].temperature.toFixed(6));
- const step = Number(parseFloat(document.getElementById("output-step").value).toFixed(6));
- const prefix = (Tmin < 0 ? 'N' : 'P') + Math.abs(Tmin).toString() + 'to' + (Tmax < 0 ? 'N' : 'P') + Math.abs(Tmax).toString() + '_' + step.toString();
- let arrayPrefix, valueArrayName;
- if (dataType === "RT") {
- arrayPrefix = `RT_table_${namePrefix}_${prefix}`;
- valueArrayName = "R";
- } else {
- arrayPrefix = `VT_table_${namePrefix}_${prefix}`;
- valueArrayName = "V";
- }
- // 格式化数组元素,确保使用6位小数,并去除末尾的0
- const formattedTemperatures = temperatures.map(t => Number(t.toFixed(6)).toString());
- const formattedValues = values.map(v => Number(v.toFixed(6)).toString());
- const cArrayTempSize = `const uint16_t ${arrayPrefix}_size = ${temperatures.length};`;
- const cArrayTemp = `const double ${arrayPrefix}_T[${temperatures.length}] = { ${formattedTemperatures.join(", ")} };`;
- const cArrayValue = `const double ${arrayPrefix}_${valueArrayName}[${values.length}] = { ${formattedValues.join(", ")} };`;
- const textarea = document.getElementById("cArrayData");
- textarea.value = `${cArrayTempSize}\n\n${cArrayTemp}\n\n${cArrayValue}`;
- }
- // 监听插值方法选择变化
- document.getElementById("interpolation").addEventListener("change", function() {
- const polynomialRow = document.getElementById("polynomial-degree-row");
- if (this.value === "polynomial") {
- polynomialRow.style.display = "";
- } else {
- polynomialRow.style.display = "none";
- }
- });
- </script>
- </body>
- </html>
|