Combined-Sensor-Uncertainty/code/inputs/Fluid_Lookup.py
SchrodingerError 3c59598d38 Initial Commit
2024-08-14 14:40:12 -05:00

134 lines
5.8 KiB
Python

import random
import CoolProp.CoolProp as CP
from inputs.Inputs import Input, AveragingInput
from inputs.Pressure_Sensors import PressureSensor
from inputs.Temperature_Sensors import TemperatureSensor
def psi_to_pascals(psi: float) -> float:
'''Convert PSIA to Pascals'''
return psi*6894.7572932
def F_to_K(f: float) -> float:
'''Convert Fahrenheit to Kelvin'''
return (f- 32) * 5/9 + 273.15
def kg_m3_to_lbm_ft3(kg_m3: float) -> float:
'''Concerts kg/m^3 to lbm/ft^3'''
return kg_m3 * 0.0624279606
class FluidLookup(Input):
def __init__(self, sensor1: 'Input', sensor2: 'Input', fluid: str = 'Water', name: str = None):
super().__init__(true_value=0.0, name=name)
self.sensor1 = sensor1 # Pressure sensor
self.sensor2 = sensor2 # Temperature sensor
self.fluid = fluid
self.uncertainties = { # In percent of table value
0: 0.0001, # Liquid phase
1: 0.05, # Vapor
2: 0.05, # Supercritical
3: 0.05, # Supercritical gas
4: 0.05, # Supercritical liquid
5: 0.05, # Two-phase
6: 0.1, # Near critical point
8: 0.05 # Solid
}
def get_input_errors(self) -> str:
string = ""
if isinstance(self.sensor1, Input):
string += f"{self.sensor1.get_input_errors()}\n"
if isinstance(self.sensor2, Input):
string += f"{self.sensor2.get_input_errors()}\n"
return string
def get_arithmetic(self) -> str:
lookup_type = type(self).__name__
return f"{lookup_type}({self.sensor1.get_arithmetic()}, {self.sensor2.get_arithmetic()})"
class DensityLookup(FluidLookup):
def __init__(self, pressure_sensor: 'PressureSensor', temperature_sensor: 'TemperatureSensor', fluid: str = 'Water', name: str = None):
if not isinstance(pressure_sensor, PressureSensor):
if isinstance(pressure_sensor, AveragingInput):
if not isinstance(pressure_sensor.get_first(), PressureSensor):
raise ValueError(f"Sensor 1 for {self.name} must be a PressureSensor or an AveragingInput of a PressureSensor")
else:
raise ValueError(f"Sensor 1 for {self.name} must be a PressureSensor or an AveragingInput of a PressureSensor")
if not isinstance(temperature_sensor, TemperatureSensor):
if isinstance(temperature_sensor, AveragingInput):
if not isinstance(temperature_sensor.get_first(), TemperatureSensor):
raise ValueError(f"Sensor 1 for {self.name} must be a TemperatureSensor or an AveragingInput of a TemperatureSensor")
else:
raise ValueError(f"Sensor 1 for {self.name} must be a TemperatureSensor or an AveragingInput of a TemperatureSensor")
super().__init__(pressure_sensor, temperature_sensor, fluid, name=name)
def calc_error(self, pressure: float, temperature: float, density: float) -> float:
# Check the phase of the fluid to determine the uncertainty according to NIST
phase_index = int(CP.PropsSI('Phase', 'T', temperature, 'P', pressure, self.fluid))
uncertainty_percentage = self.uncertainties[phase_index]
std_dev = density * (uncertainty_percentage / 100)
return random.gauss(0, std_dev)
def get_reading(self) -> float:
pressure = psi_to_pascals(self.sensor1.get_reading()) # Convert from psi to Pa
if pressure < 0:
pressure = 0.01
temperature = F_to_K(self.sensor2.get_reading()) # Convert from F to K
if temperature < 0:
temperature = 0.01
density = CP.PropsSI('D', 'P', pressure, 'T', temperature, self.fluid)
density = kg_m3_to_lbm_ft3(density)
error = self.calc_error(pressure, temperature, density)
density += error
# Append the final value to self.all_readings for final calculations at the end
self.all_readings.append(density)
return density
def get_reading_isolating_input(self, input_to_isolate: 'Input'):
'''Gets true value from input except from the input to isolate'''
pressure = psi_to_pascals(self.sensor1.get_reading_isolating_input(input_to_isolate)) # Convert from psi to Pa
if pressure < 0:
pressure = 0.01
temperature = F_to_K(self.sensor2.get_reading_isolating_input(input_to_isolate)) # Convert from F to K
if temperature < 0:
temperature = 0.01
density = CP.PropsSI('D', 'P', pressure, 'T', temperature, self.fluid)
density = kg_m3_to_lbm_ft3(density)
# Append the final value to self.all_readings for final calculations at the end
self.all_readings.append(density)
return density
def get_true(self) -> float:
pressure = psi_to_pascals(self.sensor1.get_true()) # Convert from psi to Pa
if pressure < 0:
pressure = 0.01
temperature = F_to_K(self.sensor2.get_true()) # Convert from F to K
if temperature < 0:
temperature = 0.01
density = CP.PropsSI('D', 'P', pressure, 'T', temperature, self.fluid)
density = kg_m3_to_lbm_ft3(density)
error = self.calc_error(pressure, temperature, density)
density += error
# Append the final value to self.all_readings for final calculations at the end
self.all_readings.append(density)
return density
def reset_error_gain(self) -> None:
self.sensor1.reset_error_gain()
self.sensor2.reset_error_gain()