2017-04-27 18:24:53 +00:00
|
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
2016-03-02 21:49:59 +00:00
|
|
|
|
/* gas-model.c */
|
|
|
|
|
/* gas compressibility model */
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include "dive.h"
|
|
|
|
|
|
2016-03-04 05:30:28 +00:00
|
|
|
|
/* "Virial minus one" - the virial cubic form without the initial 1.0 */
|
2019-08-07 20:28:31 +00:00
|
|
|
|
static double virial_m1(const double coeff[], double x)
|
|
|
|
|
{
|
|
|
|
|
return x*coeff[0] + x*x*coeff[1] + x*x*x*coeff[2];
|
|
|
|
|
}
|
2016-03-03 00:30:24 +00:00
|
|
|
|
|
|
|
|
|
/*
|
2017-05-12 13:36:24 +00:00
|
|
|
|
* Z = pV/nRT
|
|
|
|
|
*
|
2016-03-04 05:30:28 +00:00
|
|
|
|
* Cubic virial least-square coefficients for O2/N2/He based on data from
|
2016-03-02 22:11:53 +00:00
|
|
|
|
*
|
2016-03-03 21:57:54 +00:00
|
|
|
|
* PERRY’S CHEMICAL ENGINEERS’ HANDBOOK SEVENTH EDITION
|
2016-03-03 00:30:24 +00:00
|
|
|
|
*
|
2016-03-03 21:57:54 +00:00
|
|
|
|
* with the lookup and curve fitting by Lubomir.
|
2016-03-03 00:30:24 +00:00
|
|
|
|
*
|
2016-03-04 05:30:28 +00:00
|
|
|
|
* The "virial" form of the compression factor polynomial is
|
|
|
|
|
*
|
|
|
|
|
* Z = 1.0 + C[0]*P + C[1]*P^2 + C[2]*P^3 ...
|
|
|
|
|
*
|
|
|
|
|
* and these tables do not contain the initial 1.0 term.
|
|
|
|
|
*
|
2016-03-03 21:57:54 +00:00
|
|
|
|
* NOTE! Helium coefficients are a linear mix operation between the
|
|
|
|
|
* 323K and one for 273K isotherms, to make everything be at 300K.
|
2016-03-03 00:30:24 +00:00
|
|
|
|
*/
|
2018-08-16 17:10:10 +00:00
|
|
|
|
double gas_compressibility_factor(struct gasmix gas, double bar)
|
2016-03-02 22:11:53 +00:00
|
|
|
|
{
|
2016-03-04 05:30:28 +00:00
|
|
|
|
static const double o2_coefficients[3] = {
|
2016-03-13 19:23:16 +00:00
|
|
|
|
-7.18092073703e-04,
|
|
|
|
|
+2.81852572808e-06,
|
|
|
|
|
-1.50290620492e-09
|
2016-03-04 05:30:28 +00:00
|
|
|
|
};
|
|
|
|
|
static const double n2_coefficients[3] = {
|
2016-03-13 19:23:16 +00:00
|
|
|
|
-2.19260353292e-04,
|
|
|
|
|
+2.92844845532e-06,
|
|
|
|
|
-2.07613482075e-09
|
2016-03-04 05:30:28 +00:00
|
|
|
|
};
|
|
|
|
|
static const double he_coefficients[3] = {
|
2016-03-13 19:23:16 +00:00
|
|
|
|
+4.87320026468e-04,
|
|
|
|
|
-8.83632921053e-08,
|
|
|
|
|
+5.33304543646e-11
|
2016-03-04 05:30:28 +00:00
|
|
|
|
};
|
2016-03-13 19:23:16 +00:00
|
|
|
|
int o2, he;
|
2016-03-04 05:30:28 +00:00
|
|
|
|
double Z;
|
|
|
|
|
|
2019-08-07 18:12:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* The curve fitting range is only [0,500] bar.
|
|
|
|
|
* Anything else is way out of range for cylinder
|
|
|
|
|
* pressures.
|
|
|
|
|
*/
|
|
|
|
|
if (bar < 0) bar = 0;
|
|
|
|
|
if (bar > 500) bar = 500;
|
|
|
|
|
|
2016-03-13 19:23:16 +00:00
|
|
|
|
o2 = get_o2(gas);
|
|
|
|
|
he = get_he(gas);
|
2016-03-04 05:30:28 +00:00
|
|
|
|
|
2019-08-07 20:28:31 +00:00
|
|
|
|
Z = virial_m1(o2_coefficients, bar) * o2 +
|
|
|
|
|
virial_m1(he_coefficients, bar) * he +
|
|
|
|
|
virial_m1(n2_coefficients, bar) * (1000 - o2 - he);
|
2016-03-04 05:30:28 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* We add the 1.0 at the very end - the linear mixing of the
|
|
|
|
|
* three 1.0 terms is still 1.0 regardless of the gas mix.
|
2016-03-13 19:23:16 +00:00
|
|
|
|
*
|
|
|
|
|
* The * 0.001 is because we did the linear mixing using the
|
|
|
|
|
* raw permille gas values.
|
2016-03-04 05:30:28 +00:00
|
|
|
|
*/
|
2016-03-13 19:23:16 +00:00
|
|
|
|
return Z * 0.001 + 1.0;
|
2016-03-02 22:11:53 +00:00
|
|
|
|
}
|
2017-01-12 20:19:40 +00:00
|
|
|
|
|
|
|
|
|
/* Compute the new pressure when compressing (expanding) volome v1 at pressure p1 bar to volume v2
|
|
|
|
|
* taking into account the compressebility (to first order) */
|
|
|
|
|
|
2018-08-16 17:10:10 +00:00
|
|
|
|
double isothermal_pressure(struct gasmix gas, double p1, int volume1, int volume2)
|
2017-01-12 20:19:40 +00:00
|
|
|
|
{
|
|
|
|
|
double p_ideal = p1 * volume1 / volume2 / gas_compressibility_factor(gas, p1);
|
|
|
|
|
|
|
|
|
|
return p_ideal * gas_compressibility_factor(gas, p_ideal);
|
|
|
|
|
}
|
2017-05-12 13:36:24 +00:00
|
|
|
|
|
2019-06-04 07:06:13 +00:00
|
|
|
|
double gas_density(struct gasmix gas, int pressure)
|
|
|
|
|
{
|
2021-10-01 13:50:21 +00:00
|
|
|
|
int fo2 = get_o2(gas);
|
|
|
|
|
int fhe = get_he(gas);
|
|
|
|
|
int density = fhe * HE_DENSITY + fo2 * O2_DENSITY + (1000 - fhe - fo2) * N2_DENSITY;
|
2017-05-12 13:36:24 +00:00
|
|
|
|
|
|
|
|
|
return density * (double) pressure / gas_compressibility_factor(gas, pressure / 1000.0) / SURFACE_PRESSURE / 1000000.0;
|
|
|
|
|
}
|