134 lines
5.8 KiB
Python
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() |