Spaces:
Sleeping
Sleeping
Update nutri_call.html
Browse files- nutri_call.html +34 -192
nutri_call.html
CHANGED
|
@@ -1071,6 +1071,8 @@ document.getElementById('calculate-btn').addEventListener('click', function () {
|
|
| 1071 |
|
| 1072 |
calculateMicroElements();
|
| 1073 |
|
|
|
|
|
|
|
| 1074 |
// Рассчитываем EC
|
| 1075 |
const temperature = parseFloat(document.getElementById('profile_temp').value) || 25;
|
| 1076 |
const ecValue = calculateEC(call_data, temperature);
|
|
@@ -1257,8 +1259,8 @@ function calculateCationsAndAnions() {
|
|
| 1257 |
// 9. Обновление UI
|
| 1258 |
document.getElementById("n1-value").textContent =
|
| 1259 |
`Катионы: ${totalCations.toFixed(2)} mEq/L | Анионы: ${totalAnions.toFixed(2)} mEq/L`;
|
| 1260 |
-
|
| 1261 |
-
|
| 1262 |
document.getElementById("anion-indicator").style.width = `${anionPercent}%`;
|
| 1263 |
}
|
| 1264 |
|
|
@@ -1375,6 +1377,35 @@ function calculateMicroElements() {
|
|
| 1375 |
|
| 1376 |
console.log("=== РАСЧЕТ PPM ===", ppm);
|
| 1377 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1378 |
|
| 1379 |
</script>
|
| 1380 |
|
|
@@ -1405,199 +1436,10 @@ function showCalculationStatus(response) {
|
|
| 1405 |
}
|
| 1406 |
}
|
| 1407 |
</script>
|
| 1408 |
-
<script>
|
| 1409 |
-
const INPUT_DATA = {
|
| 1410 |
-
fertilizerConstants: {
|
| 1411 |
-
"Кальциевая селитра": { "N (NO3-)": 0.11863, "Ca": 0.16972 },
|
| 1412 |
-
"Калий азотнокислый": { "N (NO3-)": 0.13854, "K": 0.36672 },
|
| 1413 |
-
"Аммоний азотнокислый": { "N (NO3-)": 0.17499, "N (NH4+)": 0.17499 },
|
| 1414 |
-
"Сульфат магния": { "Mg": 0.10220, "S": 0.13483 },
|
| 1415 |
-
"Монофосфат калия": { "P": 0.22761, "K": 0.28731 },
|
| 1416 |
-
"Калий сернокислый": { "K": 0.44874, "S": 0.18401 },
|
| 1417 |
-
"Кальций хлорид": { "Ca": 0.272, "Cl": 0.483 } // Хлор теперь учитывается
|
| 1418 |
-
},
|
| 1419 |
-
profileSettings: {
|
| 1420 |
-
"P": 60, "K": 194, "Mg": 48.5, "Ca": 89.25, "S": 79.445, "CaCl": 38.5, // Добавлен Cl
|
| 1421 |
-
"NO3_RAT": 1.5, "TOTAL_NITROG": 138.57, "liters": 100
|
| 1422 |
-
}
|
| 1423 |
-
};
|
| 1424 |
|
| 1425 |
-
class NutrientCalculator {
|
| 1426 |
-
constructor(inputData) {
|
| 1427 |
-
this.fertilizers = inputData.fertilizerConstants;
|
| 1428 |
-
this.profile = inputData.profileSettings;
|
| 1429 |
-
this.volume = this.profile.liters;
|
| 1430 |
-
|
| 1431 |
-
const totalParts = this.profile.NO3_RAT + 1;
|
| 1432 |
-
this.target = {
|
| 1433 |
-
'P': this.profile.P,
|
| 1434 |
-
'K': this.profile.K,
|
| 1435 |
-
'Mg': this.profile.Mg,
|
| 1436 |
-
'Ca': this.profile.Ca, // Общий кальций
|
| 1437 |
-
'S': this.profile.S,
|
| 1438 |
-
'N (NO3-)': this.profile.TOTAL_NITROG * (this.profile.NO3_RAT / totalParts),
|
| 1439 |
-
'N (NH4+)': this.profile.TOTAL_NITROG * (1 / totalParts)
|
| 1440 |
-
};
|
| 1441 |
-
|
| 1442 |
-
this.actual = Object.fromEntries(Object.keys(this.target).map(k => [k, 0.0])); // CaCl не учитываем в фактическом балансе
|
| 1443 |
-
this.results = Object.fromEntries(Object.keys(this.fertilizers).map(fert => [fert, { граммы: 0.0 }]));
|
| 1444 |
-
}
|
| 1445 |
-
|
| 1446 |
-
calculate() {
|
| 1447 |
-
// 1. Вносим аммонийный азот
|
| 1448 |
-
this._applyFertilizer("Аммоний азотнокислый", "N (NH4+)", this.target["N (NH4+)"]);
|
| 1449 |
-
|
| 1450 |
-
// 2. Вносим фосфор
|
| 1451 |
-
this._applyFertilizer("Монофосфат калия", "P", this.target.P);
|
| 1452 |
-
|
| 1453 |
-
// 3. Вносим магний
|
| 1454 |
-
this._applyFertilizer("Сульфат магния", "Mg", this.target.Mg);
|
| 1455 |
-
|
| 1456 |
-
// 4. Балансируем калий и серу
|
| 1457 |
-
this._balanceKS();
|
| 1458 |
-
|
| 1459 |
-
// 5. Распределяем кальций между селитрой и хлоридом
|
| 1460 |
-
this._distributeCalcium();
|
| 1461 |
-
|
| 1462 |
-
// 6. Компенсируем NO3 калийной селитрой
|
| 1463 |
-
const no3Needed = this.target["N (NO3-)"] - this.actual["N (NO3-)"];
|
| 1464 |
-
if (no3Needed > 0) {
|
| 1465 |
-
this._applyFertilizer("Калий азотнокислый", "N (NO3-)", no3Needed);
|
| 1466 |
-
}
|
| 1467 |
-
|
| 1468 |
-
return this._verifyResults();
|
| 1469 |
-
}
|
| 1470 |
-
|
| 1471 |
-
_applyFertilizer(name, element, targetPPM) {
|
| 1472 |
-
if (!this.fertilizers[name]) {
|
| 1473 |
-
throw new Error(`Удобрение '${name}' не найдено в fertilizerConstants!`);
|
| 1474 |
-
}
|
| 1475 |
-
|
| 1476 |
-
const content = this.fertilizers[name][element] || 0; // Получаем содержание элемента
|
| 1477 |
-
if (content === 0) {
|
| 1478 |
-
console.warn(`ПРЕДУПРЕЖДЕНИЕ: Удобрение '${name}' не содержит элемент '${element}'`);
|
| 1479 |
-
return;
|
| 1480 |
-
}
|
| 1481 |
-
|
| 1482 |
-
const grams = (targetPPM * this.volume) / (content * 1000);
|
| 1483 |
-
this.results[name].граммы += grams;
|
| 1484 |
-
|
| 1485 |
-
for (const [el, val] of Object.entries(this.fertilizers[name])) {
|
| 1486 |
-
const addedPPM = (grams * val * 1000) / this.volume;
|
| 1487 |
-
if (el in this.actual) {
|
| 1488 |
-
this.actual[el] += addedPPM;
|
| 1489 |
-
}
|
| 1490 |
-
}
|
| 1491 |
-
}
|
| 1492 |
|
| 1493 |
-
|
| 1494 |
-
const kNeeded = this.target.K - this.actual.K;
|
| 1495 |
-
const sNeeded = this.target.S - this.actual.S;
|
| 1496 |
-
|
| 1497 |
-
if (kNeeded > 0 && sNeeded > 0) {
|
| 1498 |
-
const kFromK2SO4 = Math.min(kNeeded, sNeeded * 0.44874 / 0.18401);
|
| 1499 |
-
this._applyFertilizer("Калий сернокислый", "K", kFromK2SO4);
|
| 1500 |
-
}
|
| 1501 |
-
|
| 1502 |
-
const remainingK = this.target.K - this.actual.K;
|
| 1503 |
-
if (remainingK > 0) {
|
| 1504 |
-
this._applyFertilizer("Калий азотнокислый", "K", remainingK);
|
| 1505 |
-
}
|
| 1506 |
-
}
|
| 1507 |
-
|
| 1508 |
-
_distributeCalcium() {
|
| 1509 |
-
const caTarget = this.target.Ca; // Общий кальций
|
| 1510 |
-
|
| 1511 |
-
// Проверка соотношения NO3/NH4
|
| 1512 |
-
const no3Ratio = this.profile.NO3_RAT;
|
| 1513 |
-
if (no3Ratio >= 8) { // Если соотношение NO3/NH4 >= 8, кальций хлористый не добавляется
|
| 1514 |
-
console.log("Соотношение NO3/NH4 >= 8. Кальций хлористый не добавляется.");
|
| 1515 |
-
var remainingCa = caTarget;
|
| 1516 |
-
} else {
|
| 1517 |
-
// 1. Определяем, сколько кальция взять из хлористого кальция
|
| 1518 |
-
const caclRatio = 0.3; // Например, 50% кальция берем из хлористого кальция
|
| 1519 |
-
const caclTarget = caTarget * caclRatio;
|
| 1520 |
-
|
| 1521 |
-
// 2. Вносим кальций из хлористого кальция
|
| 1522 |
-
if (caclTarget > 0) {
|
| 1523 |
-
this._applyFertilizer("Кальций хлорид", "Ca", caclTarget); // Исправлено на "Кальций хлорид"
|
| 1524 |
-
}
|
| 1525 |
-
|
| 1526 |
-
// 3. Оставшийся кальций берем из кальциевой селитры
|
| 1527 |
-
remainingCa = caTarget - caclTarget;
|
| 1528 |
-
}
|
| 1529 |
-
|
| 1530 |
-
// Добавляем оставшийся кальций из кальциевой селитры
|
| 1531 |
-
if (remainingCa > 0) {
|
| 1532 |
-
this._applyFertilizer("Кальциевая селитра", "Ca", remainingCa);
|
| 1533 |
-
}
|
| 1534 |
-
}
|
| 1535 |
-
|
| 1536 |
-
_verifyResults() {
|
| 1537 |
-
const deficits = {};
|
| 1538 |
-
for (const el in this.target) {
|
| 1539 |
-
const diff = this.target[el] - this.actual[el];
|
| 1540 |
-
if (Math.abs(diff) > 0.1) {
|
| 1541 |
-
deficits[el] = parseFloat(diff.toFixed(3));
|
| 1542 |
-
}
|
| 1543 |
-
}
|
| 1544 |
-
|
| 1545 |
-
return {
|
| 1546 |
-
fertilizers: Object.fromEntries(Object.entries(this.results).map(([k, v]) => [k, parseFloat(v.граммы.toFixed(3))])),
|
| 1547 |
-
actualProfile: Object.fromEntries(Object.entries(this.actual).map(([k, v]) => [k, parseFloat(v.toFixed(3))])),
|
| 1548 |
-
deficits: deficits,
|
| 1549 |
-
totalPPM: parseFloat(Object.values(this.actual).reduce((sum, val) => sum + val, 0).toFixed(3))
|
| 1550 |
-
};
|
| 1551 |
-
}
|
| 1552 |
-
|
| 1553 |
-
generateReport(results) {
|
| 1554 |
-
let fertTable = [];
|
| 1555 |
-
for (const [name, data] of Object.entries(results.fertilizers)) {
|
| 1556 |
-
fertTable.push([name, `${data} г`]);
|
| 1557 |
-
}
|
| 1558 |
-
|
| 1559 |
-
let elementTable = [];
|
| 1560 |
-
for (const el of Object.keys(this.target).sort()) {
|
| 1561 |
-
if (el === "CaCl") continue; // Пропускаем CaCl в отчете
|
| 1562 |
-
elementTable.push([
|
| 1563 |
-
el,
|
| 1564 |
-
`${this.target[el]} ppm`,
|
| 1565 |
-
`${results.actualProfile[el]} ppm`,
|
| 1566 |
-
`${parseFloat((results.actualProfile[el] - this.target[el]).toFixed(2))} ppm`
|
| 1567 |
-
]);
|
| 1568 |
-
}
|
| 1569 |
-
|
| 1570 |
-
let report = "РЕКОМЕНДУЕМЫЕ УДОБРЕНИЯ:\n";
|
| 1571 |
-
report += this._formatTable(fertTable, ["Удобрение", "Количество"]);
|
| 1572 |
-
|
| 1573 |
-
report += "\n\nБАЛАНС ЭЛЕМЕНТОВ:\n";
|
| 1574 |
-
report += this._formatTable(elementTable, ["Элемент", "Цель", "Факт", "Отклонение"]);
|
| 1575 |
-
|
| 1576 |
-
report += `\n\nОбщая концентрация: ${results.totalPPM} ppm`;
|
| 1577 |
-
|
| 1578 |
-
if (Object.keys(results.deficits).length > 0) {
|
| 1579 |
-
report += "\n\nВНИМАНИЕ: Обнаружены небольшие отклонения:";
|
| 1580 |
-
for (const [el, diff] of Object.entries(results.deficits)) {
|
| 1581 |
-
report += `\n- ${el}: не хватает ${Math.abs(diff)} ppm`;
|
| 1582 |
-
}
|
| 1583 |
-
}
|
| 1584 |
-
|
| 1585 |
-
return report;
|
| 1586 |
-
}
|
| 1587 |
-
|
| 1588 |
-
_formatTable(data, headers) {
|
| 1589 |
-
const table = [headers, ...data];
|
| 1590 |
-
const columnWidths = headers.map((_, i) => Math.max(...table.map(row => row[i].toString().length)));
|
| 1591 |
-
const formatRow = row => row.map((cell, i) => cell.padEnd(columnWidths[i])).join(" | ");
|
| 1592 |
-
return table.map(formatRow).join("\n");
|
| 1593 |
-
}
|
| 1594 |
-
}
|
| 1595 |
|
| 1596 |
-
// Запуск расчета
|
| 1597 |
-
const calculator = new NutrientCalculator(INPUT_DATA);
|
| 1598 |
-
const results = calculator.calculate();
|
| 1599 |
-
console.log(calculator.generateReport(results));
|
| 1600 |
-
</script>
|
| 1601 |
|
| 1602 |
|
| 1603 |
<script src="https://unpkg.com/tippy.js@6"></script>
|
|
|
|
| 1071 |
|
| 1072 |
calculateMicroElements();
|
| 1073 |
|
| 1074 |
+
calculateN1Ratio(call_data);
|
| 1075 |
+
|
| 1076 |
// Рассчитываем EC
|
| 1077 |
const temperature = parseFloat(document.getElementById('profile_temp').value) || 25;
|
| 1078 |
const ecValue = calculateEC(call_data, temperature);
|
|
|
|
| 1259 |
// 9. Обновление UI
|
| 1260 |
document.getElementById("n1-value").textContent =
|
| 1261 |
`Катионы: ${totalCations.toFixed(2)} mEq/L | Анионы: ${totalAnions.toFixed(2)} mEq/L`;
|
| 1262 |
+
|
| 1263 |
+
|
| 1264 |
document.getElementById("anion-indicator").style.width = `${anionPercent}%`;
|
| 1265 |
}
|
| 1266 |
|
|
|
|
| 1377 |
|
| 1378 |
console.log("=== РАСЧЕТ PPM ===", ppm);
|
| 1379 |
}
|
| 1380 |
+
|
| 1381 |
+
|
| 1382 |
+
|
| 1383 |
+
|
| 1384 |
+
// Функция для расчета соотношений и формирования строки
|
| 1385 |
+
function calculateN1Ratio(data) {
|
| 1386 |
+
// Получаем значения элементов из ответа сервера
|
| 1387 |
+
const { actual_profile, total_ppm } = response;
|
| 1388 |
+
const { P, K, Ca, Mg, S } = actual_profile;
|
| 1389 |
+
|
| 1390 |
+
// Общий азот (N_total) = N (NH4+) + N (NO3-)
|
| 1391 |
+
const N_total = actual_profile["N (NH4+)"] + actual_profile["N (NO3-)"];
|
| 1392 |
+
|
| 1393 |
+
// Вычисляем соотношения относительно общего азота (принимаем его за единицу)
|
| 1394 |
+
const P_ratio = (P / N_total).toFixed(2);
|
| 1395 |
+
const K_ratio = (K / N_total).toFixed(2);
|
| 1396 |
+
const CaO_ratio = (Ca / N_total).toFixed(2); // Предполагается, что Ca - это оксид кальция
|
| 1397 |
+
const MgO_ratio = (Mg / N_total).toFixed(2); // Предполагается, что Mg - это оксид магния
|
| 1398 |
+
const SO_ratio = (S / N_total).toFixed(2); // Предполагается, что S - это оксид серы
|
| 1399 |
+
|
| 1400 |
+
// Формируем строку в требуемом формате
|
| 1401 |
+
const n1String = `${P_ratio}:${K_ratio}:${CaO_ratio}:${MgO_ratio}:${SO_ratio} PPM=${total_ppm.toFixed(2)}`;
|
| 1402 |
+
|
| 1403 |
+
// Вставляем строку в HTML
|
| 1404 |
+
document.getElementById("n1-value").textContent = n1String;
|
| 1405 |
+
}
|
| 1406 |
+
|
| 1407 |
+
|
| 1408 |
+
|
| 1409 |
|
| 1410 |
</script>
|
| 1411 |
|
|
|
|
| 1436 |
}
|
| 1437 |
}
|
| 1438 |
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1439 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1440 |
|
| 1441 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1442 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1443 |
|
| 1444 |
|
| 1445 |
<script src="https://unpkg.com/tippy.js@6"></script>
|