| 
									
										
										
										
											2017-04-27 20:24:53 +02:00
										 |  |  |  | // SPDX-License-Identifier: GPL-2.0
 | 
					
						
							| 
									
										
										
										
											2016-03-02 13:49:59 -08:00
										 |  |  |  | /* gas-model.c */ | 
					
						
							|  |  |  |  | /* gas compressibility model */ | 
					
						
							|  |  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  |  | #include "dive.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | /* "Virial minus one" - the virial cubic form without the initial 1.0 */ | 
					
						
							|  |  |  |  | #define virial_m1(C, x1, x2, x3) (C[0]*x1+C[1]*x2+C[2]*x3)
 | 
					
						
							| 
									
										
										
										
											2016-03-02 16:30:24 -08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2017-05-12 15:36:24 +02:00
										 |  |  |  |  * Z = pV/nRT | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  |  * Cubic virial least-square coefficients for O2/N2/He based on data from | 
					
						
							| 
									
										
										
										
											2016-03-02 14:11:53 -08:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-03-03 13:57:54 -08:00
										 |  |  |  |  *    PERRY’S CHEMICAL ENGINEERS’ HANDBOOK SEVENTH EDITION | 
					
						
							| 
									
										
										
										
											2016-03-02 16:30:24 -08:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-03-03 13:57:54 -08:00
										 |  |  |  |  * with the lookup and curve fitting by Lubomir. | 
					
						
							| 
									
										
										
										
											2016-03-02 16:30:24 -08:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08: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 13:57:54 -08: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-02 16:30:24 -08:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2016-03-02 14:11:53 -08:00
										 |  |  |  | double gas_compressibility_factor(struct gasmix *gas, double bar) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	static const double o2_coefficients[3] = { | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 		-7.18092073703e-04, | 
					
						
							|  |  |  |  | 		+2.81852572808e-06, | 
					
						
							|  |  |  |  | 		-1.50290620492e-09 | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	}; | 
					
						
							|  |  |  |  | 	static const double n2_coefficients[3] = { | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 		-2.19260353292e-04, | 
					
						
							|  |  |  |  | 		+2.92844845532e-06, | 
					
						
							|  |  |  |  | 		-2.07613482075e-09 | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	}; | 
					
						
							|  |  |  |  | 	static const double he_coefficients[3] = { | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 		+4.87320026468e-04, | 
					
						
							|  |  |  |  | 		-8.83632921053e-08, | 
					
						
							|  |  |  |  | 		+5.33304543646e-11 | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	}; | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 	int o2, he; | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	double x1, x2, x3; | 
					
						
							|  |  |  |  | 	double Z; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 	o2 = get_o2(gas); | 
					
						
							|  |  |  |  | 	he = get_he(gas); | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	x1 = bar; x2 = x1*x1; x3 = x2*x1; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	Z = virial_m1(o2_coefficients, x1, x2, x3) * o2 + | 
					
						
							|  |  |  |  | 	    virial_m1(he_coefficients, x1, x2, x3) * he + | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 	    virial_m1(n2_coefficients, x1, x2, x3) * (1000 - o2 - he); | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08: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 12:23:16 -07:00
										 |  |  |  | 	 * | 
					
						
							|  |  |  |  | 	 * The * 0.001 is because we did the linear mixing using the | 
					
						
							|  |  |  |  | 	 * raw permille gas values. | 
					
						
							| 
									
										
										
										
											2016-03-03 21:30:28 -08:00
										 |  |  |  | 	 */ | 
					
						
							| 
									
										
										
										
											2016-03-13 12:23:16 -07:00
										 |  |  |  | 	return Z * 0.001 + 1.0; | 
					
						
							| 
									
										
										
										
											2016-03-02 14:11:53 -08:00
										 |  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-01-12 21:19:40 +01: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) */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | double isothermal_pressure(struct gasmix *gas, double p1, int volume1, int volume2) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  | 	double p_ideal = p1 * volume1 / volume2 / gas_compressibility_factor(gas, p1); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return p_ideal * gas_compressibility_factor(gas, p_ideal); | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2017-05-12 15:36:24 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | inline double gas_density(struct gasmix *gas, int pressure) { | 
					
						
							|  |  |  |  | 	int density =  gas->he.permille * HE_DENSITY + gas->o2.permille * O2_DENSITY + (1000 - gas->he.permille - gas->o2.permille) * N2_DENSITY; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return density * (double) pressure / gas_compressibility_factor(gas, pressure / 1000.0) / SURFACE_PRESSURE / 1000000.0; | 
					
						
							|  |  |  |  | } |