Skip to content

Commit 3ee5521

Browse files
committed
v2.0 аптечный 0.9% раствор NaCl
1 parent 1cb8e76 commit 3ee5521

11 files changed

+232
-63
lines changed

.vscode/launch.json

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,6 @@
44
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7-
{
8-
"type": "node",
9-
"request": "launch",
10-
"name": "Jest run current file",
11-
"program": "${workspaceRoot}/node_modules/jest-cli/bin/jest.js",
12-
"args": [
13-
"${fileBasename}",
14-
"--verbose",
15-
"-i",
16-
"--no-cache"
17-
],
18-
"console": "integratedTerminal",
19-
"internalConsoleOptions": "neverOpen"
20-
},
217
{
228
"type": "node",
239
"request": "launch",
@@ -28,7 +14,7 @@
2814
"-i",
2915
"--no-cache"
3016
],
31-
"console": "integratedTerminal",
17+
// "console": "integratedTerminal",
3218
"internalConsoleOptions": "neverOpen"
3319
},
3420
{

NaClSolutions.pdf

159 KB
Binary file not shown.

cfg.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
/** @type {import('./src/Cfg.js').Cfg} */
22
module.exports = {
3-
version: 0.11,
3+
version: "0.20",
44
ensureMonotonicSteps: 100, // 10000 works, but slow, its just warranty thats all is ok.
55
saltScalesDivisionValue: 0.01,
6-
waterScalesDivisionValue: 1
6+
waterScalesDivisionValue: 1,
7+
salt09SolutionScalesDivisionValue: 0.01,
78
}

doc.md

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ script:
44
- url: src/mathjax/tex-mml-chtml.js
55
---
66

7-
# Изготовление калибровочных растворов для измерителей EC подручными средствами
7+
# Изготовление калибровочных растворов для измерителей EC подручными средствами с использованием чистого NaCl или аптечного раствора 0.9%
88

99
## О версиях
1010

@@ -18,21 +18,58 @@ script:
1818

1919
## Введение
2020

21-
Известна формула[1] для вычисления EC раствора по его $\rho$ (массовой концентрации NaCl), где $\rho$ - масса соли на литр **раствора**.
22-
Основной проблемой домашнего изготовления раствора с заданной массовой концентрацией $\rho$ является точное измерение **объёма**. Так, для изготовления раствора требуется растворить определённое количество соли в **литре раствора, не воды, а именно раствора**. Т.е. при приготовлении такого раствора неизвестно сколько воды нужно взять, и нужно доливать воду точно измеряя объём, что существенно осложняет процесс.
21+
Известна формула[1][2] для вычисления EC раствора по его $\rho$ (массовой концентрации NaCl), где $\rho$ - масса соли на литр **раствора**.
22+
Основной проблемой домашнего изготовления раствора с заданной массовой концентрацией $\rho$ является точное измерение **объёма**. Так, для изготовления раствора требуется растворить определённое количество соли(или раствора-концентрата) в **литре раствора, не воды, а именно раствора**. Т.е. при приготовлении такого раствора неизвестно сколько воды нужно взять, и нужно доливать воду точно измеряя объём, что существенно осложняет процесс.
2323

24-
В этом документе даны таблицы для изготовления типовых калибровочных растворов при помощи бытовых и ювелирных весов, с учётом погрешности, описана методика получения результатов, приведены таблицы для других поверочных значений.
24+
В этом документе даны таблицы для изготовления типовых калибровочных растворов при помощи бытовых и ювелирных весов, с учётом погрешности, описана методика получения результатов, приведены таблицы для других поверочных значений. Значения получены путём численного моделирования для минимизации погрешности с учётом цены деления весов.
2525

2626
## Требуемый инвентарь и условия
2727

28-
Для изготовления потребуются электронные ювелирные весы с ценой деления js: cfg.saltScalesDivisionValue\jsг для измерения массы соли, и электронны бытовые кухонные весы с ценой деления js: cfg.waterScalesDivisionValue\jsг для измерения массы воды. Для удобства таблицы даны под разную тару. При возможности выбирайте больший объём тары, так раствор получится точнее. Рассчёт выполнен для воды температурой 20°С, требуется применять дистиллированную воду, или воду из обратного осмоса без реминерализации, соль "Экстра" не йодированную.
28+
Для изготовления потребуются электронные ювелирные весы с ценой деления js: cfg.saltScalesDivisionValue\jsг для измерения массы до 100 или 200г, и электронны бытовые кухонные весы с ценой деления js: cfg.waterScalesDivisionValue\jsг для измерения больших масс. Для удобства приготовления даны таблицы под разную тару. При возможности выбирайте больший объём тары, так раствор получится точнее. Рассчёт выполнен для воды температурой 20°С, требуется применять дистиллированную воду, или воду из обратного осмоса без реминерализации, соль "Экстра" не йодированную. Для таблиц где указано применять аптечный 0.9% раствор NaCl применять его. Применение аптечного 0.9% раствора NaCl приводит к снижению погрешности примерно на порядок. Чистый 0.9% раствор NaCl имеет EC = 16.35 мСм/см.
2929

3030
## Погрешность
3131

3232
В лучшем случае, даже если ваши весы идеальны(а электронные, даже дешёвые весьма неплохи), имеют цену деления 1г показывают например 100г, на самом деле возможно на весах как 99,5 так и 100,5, т.е. разброс составляет по половине деления вверх и вниз. При рассчётах выполнено дополнительно две оценки, раствор минимальной концентрации, полученный как рассчетное количество соли минус половина цены деления весов для соли, и воды, как рассчетное количество воды плюс цена деления весов для воды. Аналогично вычислена максимальная величина EC, они и составляют **Диапазон EC**. Т.е. изготовив раствор точно по заданным цифрам вы получите что-то в этом диапазоне, что конктрено сказать нельзя.
33+
34+
<div class="page-break"></div>
35+
36+
## Легенда таблицы
37+
38+
**EC** - целевой EC, который мы хотим получить
39+
**H2O(г)** - масса воды в граммах, которую необходимо отмерить для приготовления раствора
40+
**NaCl(г)** - масса соли(NaCl) в граммах, которую необходимо отмерить для приготовления раствора
41+
**NaCl 0.9%(г)** - масса аптечного 0.9% NaCL в граммах, которую необходимо отмерить для приготовления раствора
42+
**Рассчетный EC** - результат рассчёта EC который получится если смешать идеально точно указанное количество компонент, без учёта погрешности
43+
**Диапазон EC** - рассчётный минимальный и максимальный EC, с учётом погрешности весов, подробнее см. раздел [Погрешность](#погрешность) выше.
44+
**Диапазон EC%** - отношение ширина диапазона EC к целевому EC.
45+
**$\rho$(г/л)** - массовая концентрация NaCL в полученно растворе. Измеряется в граммах соли на литр раствора.
46+
**Отклонение EC** - модуль разности целевого и рассчётного EC
47+
**Объём раствора(мл)** - объём полученного раствора в миллилитрах.
48+
49+
## Растворы на базе аптечного раствора NaCl 0.9%
50+
<div>
51+
52+
### 0.5 литра для разбавления аптечным раствором NaCl 0.9%
53+
js: getTableSolution09([1], 200, 400, undefined, undefined, 2);\js
54+
js: getTableSolution09([1.413], 200, 450, undefined, undefined, 0, true);\js
55+
js: getTableSolution09([2, 3], 200, 400, 1, 1, 2, true);\js
56+
js: getTableSolution09([4, 5], 200, 350, 1, 1, 2, true);\js
57+
js: getTableSolution09([10], 50, 200, 1, 1, 2, true);\js
58+
js: getTableSolution09([12.88], 50, 100, 1, 1, 0, true);\js
59+
</div>
60+
61+
### 1 литр для разбавления аптечным раствором NaCl 0.9%
62+
js: getTableSolution09([1], 500, 800, undefined, undefined, 2);\js
63+
js: getTableSolution09([1.413], 500, 900, undefined, undefined, 0, true);\js
64+
js: getTableSolution09([2, 3], 500, 800, 1, 1, 2, true);\js
65+
js: getTableSolution09([4, 5], 500, 700, 1, 1, 2, true);\js
66+
js: getTableSolution09([10], 100, 400, 1, 1, 2, true);\js
67+
js: getTableSolution09([12.88], 100, 200, 1, 1, 0, true);\js
68+
</div>
69+
3370
<div class="page-break"></div>
3471

35-
## Типовые калибровочные коэффициенты
72+
## Типовые калибровочные коэффициенты для соли
3673

3774
EC равные 1.413, 12.88, 111.8 мСм/СМ являются типовыми для калибровки, изготовить их можно смешав указанную ниже массу воды и соли. Для удобства таблицы даны под разную тару.
3875

@@ -68,9 +105,23 @@ js: getTable([1.413, 12.88, 111.8], 1000, 2000);\js
68105
js: getTable([1.413, 12.88, 111.8], 1000, 4000);\js
69106
</div>
70107

108+
<div class="page-break"></div>
109+
110+
## Источники
111+
1. https://t.me/ponics_ru/1/157994 формула EC от грамм соли на литр раствора
112+
2. https://t.me/ponics_doc/47 "Conductance Data For Commonly Used Chemicals, December 2010" - источник формулы
113+
3. https://files.stroyinf.ru/Data2/1/4293783/4293783232.htm плотность воды ГСССД 2-77
114+
4. https://russsam.ru/certificates/246-Tablitsa_plotnosti_rastvorov_khlorida_natriya плотность соляного раствора "Краткий химический справочник" 1978
115+
116+
117+
## Release Notes
118+
**2024-05-11 v0.20** добавлен расчёт по масее аптечного 0.9% раствора хлорида натрия, добавлена легенда, ссылка на формулу, release notes.
119+
**2024-05-04 v0.11** расчёт перенесён в код, вместо google sheets, выполнен расчёт погрешностей.
120+
71121
<div class="page-break"></div>
72122
<div>
73123

124+
# Приложение 1
74125
## Иные точки для проверки для тары в 1 литр
75126
js: getTable(getArray(1,30), 100, 1000, 2);\js
76127
</div>
@@ -86,10 +137,3 @@ js: getTable(getArray(61,90), 100, 1000, 2);\js
86137

87138
js: getTable(getArray(91,120), 100, 1000, 2);\js
88139
</div>
89-
<div class="page-break"></div>
90-
91-
92-
## Источники
93-
1. https://t.me/ponics_ru/1/157994 формула EC от грамм соли на литр раствора
94-
2. https://files.stroyinf.ru/Data2/1/4293783/4293783232.htm плотность воды ГСССД 2-77
95-
3. https://russsam.ru/certificates/246-Tablitsa_plotnosti_rastvorov_khlorida_natriya плотность соляного раствора "Краткий химический справочник" 1978

src/Cfg.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
export class Cfg {
2-
version:number;
2+
version:string;
33
ensureMonotonicSteps?: number;
44
saltScalesDivisionValue: number;
5+
salt09SolutionScalesDivisionValue: number;
56
waterScalesDivisionValue: number;
67
}

src/calculateSolution09MassesByEC.ts

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { getECbyRho } from "./getECbyRho";
2+
import { getDencityByRho } from "./getDencityByRho";
3+
import { getRhoByEC } from "./getRhoByEC";
4+
import { bruteForceMonotonic } from "./bruteForceMonotonic";
5+
import { getRhoByDencitySaltAndWaterGrams } from "./getRhoByDencitySaltAndWaterGrams";
6+
import { getSaltGramsByRho } from "./getSaltGramsByRho";
7+
8+
export class Solution09CalculationResult {
9+
public rho: number;
10+
public targetEC: number;
11+
public realEC: number;
12+
public ECError: number;
13+
public ECAccuracy: number;
14+
public solution09Grams: number;
15+
public waterGrams: number;
16+
public minEC: number;
17+
public maxEC: number;
18+
public score: number;
19+
public volume: number;
20+
}
21+
22+
export function calculateSolution09MassesByEC(EC: number, minWaterGrams: number, maxWatergrams: number, waterStep: number, solution09step: number): Solution09CalculationResult {
23+
let rho = getRhoByEC(EC);
24+
let solution09Rho = 9;
25+
let dencity = getDencityByRho(rho);
26+
let bestCandidate: Solution09CalculationResult = {
27+
rho: 0,
28+
targetEC: EC,
29+
realEC: 0,
30+
ECError: Number.POSITIVE_INFINITY,
31+
ECAccuracy: Number.POSITIVE_INFINITY,
32+
solution09Grams: 0,
33+
waterGrams: 0,
34+
minEC: 0,
35+
maxEC: 0,
36+
score: Number.POSITIVE_INFINITY,
37+
volume: 0
38+
};
39+
for (let waterGrams = minWaterGrams; waterGrams <= maxWatergrams; waterGrams += waterStep) {
40+
waterGrams = Math.round(waterGrams / waterStep) * waterStep;
41+
let calculatedSolution09grams = bruteForceMonotonic((solution09grams: number) => {
42+
let saltInSolution09Grams = getSaltGramsByRho(solution09grams, solution09Rho);
43+
let waterInSolution09Grams = solution09grams - saltInSolution09Grams;
44+
let realRho = getRhoByDencitySaltAndWaterGrams(dencity, saltInSolution09Grams, waterGrams + waterInSolution09Grams);
45+
return realRho;
46+
}, rho, solution09step, 10000, 0.000001);
47+
let solution09GramsRounded = Math.round(calculatedSolution09grams / solution09step) * solution09step;
48+
let solution09GramsFrom = solution09GramsRounded - 2 * solution09step;
49+
let solution09GramsTo = solution09GramsRounded + 2 * solution09step;
50+
for (let solution09Grams = solution09GramsFrom; solution09Grams <= solution09GramsTo; solution09Grams += solution09step) {
51+
let solution09SaltGrams = getSaltGramsByRho(solution09Grams, solution09Rho);
52+
let solution09WaterGrams = solution09Grams - solution09SaltGrams;
53+
54+
let realEC = getECbyRho(getRhoByDencitySaltAndWaterGrams(dencity, solution09SaltGrams, waterGrams + solution09WaterGrams));
55+
56+
let minSolution09grams = solution09Grams - solution09step / 2;
57+
let minSolution09SaltGrams = getSaltGramsByRho(minSolution09grams, solution09Rho);
58+
let minSolution09WaterGrams = minSolution09grams - minSolution09SaltGrams;
59+
60+
let maxSolution09Grams = solution09Grams + solution09step / 2;
61+
let maxSolution09SaltGrams = getSaltGramsByRho(maxSolution09Grams, solution09Rho);
62+
let maxSolution09WaterGrams = maxSolution09Grams - maxSolution09SaltGrams;
63+
64+
let minWater = waterGrams - waterStep / 2;
65+
let maxWater = waterGrams + waterStep / 2;
66+
let minEC = getECbyRho(getRhoByDencitySaltAndWaterGrams(dencity, minSolution09SaltGrams, maxWater + minSolution09WaterGrams));
67+
let maxEC = getECbyRho(getRhoByDencitySaltAndWaterGrams(dencity, maxSolution09SaltGrams, minWater + maxSolution09WaterGrams));
68+
let ECError = Math.abs(EC - realEC);
69+
let ECAccuracy = maxEC - minEC;
70+
let score = ECError + ECAccuracy / 2;
71+
if (ECAccuracy < 0) {
72+
debugger;
73+
}
74+
if (score < bestCandidate.score) {
75+
bestCandidate = {
76+
rho,
77+
targetEC: EC,
78+
realEC,
79+
ECError,
80+
ECAccuracy,
81+
solution09Grams,
82+
waterGrams,
83+
minEC,
84+
maxEC,
85+
score,
86+
volume: ((solution09SaltGrams + waterGrams + solution09WaterGrams) / dencity) * 1000
87+
};
88+
}
89+
}
90+
// console.log('waterGrams:', waterGrams, 'saltGrams:', saltGrams, 'rhoError:', rhoError);
91+
}
92+
return bestCandidate;
93+
}

src/calculateSolutionMassesByEC.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,11 @@ export function calculateSolutionMassesByEC(EC: number, minWaterGrams: number, m
3636
};
3737
for (let waterGrams = minWaterGrams; waterGrams <= maxWatergrams; waterGrams += waterStep) {
3838
waterGrams = Math.round(waterGrams / waterStep) * waterStep;
39-
let saltGrams = bruteForceMonotonic((saltGrams: number) => {
39+
let calculatedSaltGrams = bruteForceMonotonic((saltGrams: number) => {
4040
let realRho = getRhoByDencitySaltAndWaterGrams(dencity, saltGrams, waterGrams);
4141
return realRho;
4242
}, rho, saltStep, 1000, 0.000001);
43-
let saltGramsRounded = Math.round(saltGrams / saltStep) * saltStep;
43+
let saltGramsRounded = Math.round(calculatedSaltGrams / saltStep) * saltStep;
4444
let saltFrom = saltGramsRounded - 2 * saltStep;
4545
let saltTo = saltGramsRounded + 2 * saltStep;
4646
for (let saltGrams = saltFrom; saltGrams <= saltTo; saltGrams += saltStep) {

src/getDencityByRho.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ let rhoToDencity: Array<[number, number]> = [
2222

2323
/**
2424
*
25-
* @param rho
26-
* @returns грамм раствора на литр раствора
25+
* @param rho грам соли на литр раствора
26+
* @returns Плотность: грамм раствора на литр раствора
2727
*/
2828
export function getDencityByRho(rho: number): number {
2929
let less: [number, number];

src/getSaltGramsByRho.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { getDencityByRho } from "./getDencityByRho";
2+
3+
/**
4+
*
5+
* @param solutionGrams
6+
* @param rho Rho, грам соли на литр раствора
7+
* @returns grams of salt
8+
*/
9+
export function getSaltGramsByRho(solutionGrams: number, rho:number): number {
10+
let dencity = getDencityByRho(rho);
11+
let liters = solutionGrams / dencity;
12+
let saltGrams = rho * liters;
13+
return saltGrams;
14+
}

0 commit comments

Comments
 (0)