repair air manual collection module calculation
This commit is contained in:
parent
1b1b869a1d
commit
f7fefd3f45
@ -49,6 +49,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
final _pm10TimeResultController = TextEditingController();
|
||||
final _pm10PressureController = TextEditingController();
|
||||
final _pm10PressureResultController = TextEditingController();
|
||||
final _pm10TavgController = TextEditingController();
|
||||
final _pm10QstdController = TextEditingController();
|
||||
final _pm10VstdController = TextEditingController();
|
||||
|
||||
// PM2.5 Controllers
|
||||
@ -58,6 +60,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
final _pm25TimeResultController = TextEditingController();
|
||||
final _pm25PressureController = TextEditingController();
|
||||
final _pm25PressureResultController = TextEditingController();
|
||||
final _pm25TavgController = TextEditingController();
|
||||
final _pm25QstdController = TextEditingController();
|
||||
final _pm25VstdController = TextEditingController();
|
||||
|
||||
@override
|
||||
@ -88,6 +92,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
_pm10TimeResultController.dispose();
|
||||
_pm10PressureController.dispose();
|
||||
_pm10PressureResultController.dispose();
|
||||
_pm10TavgController.dispose();
|
||||
_pm10QstdController.dispose();
|
||||
_pm10VstdController.dispose();
|
||||
_pm25FlowRateController.dispose();
|
||||
_pm25FlowRateResultController.dispose();
|
||||
@ -95,6 +101,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
_pm25TimeResultController.dispose();
|
||||
_pm25PressureController.dispose();
|
||||
_pm25PressureResultController.dispose();
|
||||
_pm25TavgController.dispose();
|
||||
_pm25QstdController.dispose();
|
||||
_pm25VstdController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
@ -153,35 +161,58 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
void _calculateVstd(int type) {
|
||||
setState(() {
|
||||
try {
|
||||
// Get the correct controllers for either PM10 or PM2.5
|
||||
final flowRateCtrl = type == 1 ? _pm10FlowRateController : _pm25FlowRateController;
|
||||
final pressureCtrl = type == 1 ? _pm10PressureController : _pm25PressureController;
|
||||
final flowResultCtrl = type == 1 ? _pm10FlowRateResultController : _pm25FlowRateResultController;
|
||||
final timeResultCtrl = type == 1 ? _pm10TimeResultController : _pm25TimeResultController;
|
||||
final vstdCtrl = type == 1 ? _pm10VstdController : _pm25VstdController;
|
||||
final pressureResultCtrl = type == 1 ? _pm10PressureResultController : _pm25PressureResultController;
|
||||
final tAvgCtrl = type == 1 ? _pm10TavgController : _pm25TavgController;
|
||||
final qStdCtrl = type == 1 ? _pm10QstdController : _pm25QstdController;
|
||||
final vstdCtrl = type == 1 ? _pm10VstdController : _pm25VstdController;
|
||||
|
||||
if (pressureCtrl.text.isEmpty || _finalTempController.text.isEmpty || flowResultCtrl.text.isEmpty || timeResultCtrl.text.isEmpty) {
|
||||
if (flowRateCtrl.text.isEmpty ||
|
||||
pressureCtrl.text.isEmpty ||
|
||||
_finalTempController.text.isEmpty ||
|
||||
timeResultCtrl.text.isEmpty) {
|
||||
tAvgCtrl.text = "";
|
||||
qStdCtrl.text = "";
|
||||
vstdCtrl.text = "0.000";
|
||||
return;
|
||||
}
|
||||
|
||||
const double hpaToinHg = 0.0295;
|
||||
const double inHgToMmHg = 25.4;
|
||||
|
||||
// 1. Get time and user-input flowrate (cfm)
|
||||
double totalTime_min = double.parse(timeResultCtrl.text);
|
||||
// **CRITICAL FIX**: Use the actual flowrate keyed in by the user (in cfm)
|
||||
double qa_cfm_actual = double.parse(flowRateCtrl.text);
|
||||
|
||||
// 2. Calculate actual pressure
|
||||
double pressureHpa = double.parse(pressureCtrl.text);
|
||||
double pressureInHg = pressureHpa * 0.02953;
|
||||
double pressureInHg = pressureHpa * hpaToinHg;
|
||||
double p_actual_mmHg = pressureInHg * inHgToMmHg; // result pressure
|
||||
pressureResultCtrl.text = pressureInHg.toStringAsFixed(2);
|
||||
|
||||
double qa_m3min = double.parse(flowResultCtrl.text);
|
||||
double totalTime_min = double.parse(timeResultCtrl.text);
|
||||
double pa_mmHg = pressureInHg * 25.4;
|
||||
double t_avg_celsius = (widget.initialTemp + double.parse(_finalTempController.text)) / 2.0;
|
||||
// 3. Calculate average temperature in Celsius
|
||||
double t_avg_celsius = (widget.initialTemp + double.parse(_finalTempController.text)) / 2.0; // ambient temperature
|
||||
tAvgCtrl.text = t_avg_celsius.toStringAsFixed(2);
|
||||
|
||||
double numerator = qa_m3min * pa_mmHg * 298.15;
|
||||
double denominator = 760 * (273.15 + t_avg_celsius);
|
||||
double q_std = numerator / denominator;
|
||||
// 4. Calculate Standard Flowrate (QSTD) using your exact formula
|
||||
// Formula: (flowrate * result pressure * 298) / (760 * (273 * ambient temperature))
|
||||
double q_std_numerator = qa_cfm_actual * pressureInHg * 298;
|
||||
double q_std_denominator = (760 * (273 + t_avg_celsius));
|
||||
double q_std = (q_std_denominator == 0) ? 0 : q_std_numerator / q_std_denominator;
|
||||
qStdCtrl.text = q_std.toStringAsFixed(5);
|
||||
|
||||
// 5. Final VSTD
|
||||
// Formula: QSTD * Total time
|
||||
double v_std = q_std * totalTime_min;
|
||||
|
||||
if (type == 1) {
|
||||
if (type == 1) { // PM10
|
||||
_pm10VstdController.text = v_std.toStringAsFixed(3);
|
||||
widget.data.pm10Vstd = v_std;
|
||||
} else {
|
||||
} else { // PM2.5
|
||||
_pm25VstdController.text = v_std.toStringAsFixed(3);
|
||||
widget.data.pm25Vstd = v_std;
|
||||
}
|
||||
@ -192,13 +223,10 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
});
|
||||
}
|
||||
|
||||
// **CRITICAL FIX IS HERE**
|
||||
void _onSubmitPressed() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
_formKey.currentState!.save(); // Saves data from fields with an onSaved function
|
||||
_formKey.currentState!.save();
|
||||
|
||||
// **THE FIX**: Manually save the values from the read-only result controllers
|
||||
// into the data model before submitting, as they don't have onSaved functions.
|
||||
widget.data.pm10FlowrateResult = _pm10FlowRateResultController.text;
|
||||
widget.data.pm10TotalTimeResult = _pm10TimeResultController.text;
|
||||
widget.data.pm10PressureResult = _pm10PressureResultController.text;
|
||||
@ -206,13 +234,11 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
widget.data.pm25TotalTimeResult = _pm25TimeResultController.text;
|
||||
widget.data.pm25PressureResult = _pm25PressureResultController.text;
|
||||
|
||||
// Save optional remarks
|
||||
widget.data.optionalRemark1 = _optionalRemark1Controller.text;
|
||||
widget.data.optionalRemark2 = _optionalRemark2Controller.text;
|
||||
widget.data.optionalRemark3 = _optionalRemark3Controller.text;
|
||||
widget.data.optionalRemark4 = _optionalRemark4Controller.text;
|
||||
|
||||
// Now, call the submission function with the fully populated data model
|
||||
widget.onSubmit();
|
||||
}
|
||||
}
|
||||
@ -261,17 +287,62 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
||||
validator: (v) => v == null ? 'Required' : null,
|
||||
onSaved: (v) => widget.data.powerFailure = v,
|
||||
),
|
||||
|
||||
const Padding(padding: EdgeInsets.symmetric(vertical: 20), child: Text("PM10 Data", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
|
||||
_buildResultRow(_pm10FlowRateController, "Flow Rate (cfm)", _pm10FlowRateResultController, "Result (m³/min)", (v) => setState(() => _pm10FlowRateResultController.text = ((double.tryParse(v) ?? 0) * 0.0283).toStringAsFixed(4)), (v) => widget.data.pm10Flowrate = double.tryParse(v!)),
|
||||
_buildResultRow(_pm10TimeController, "Total Time (hours)", _pm10TimeResultController, "Result (mins)", (v) => setState(() => _pm10TimeResultController.text = ((double.tryParse(v) ?? 0) * 60).toStringAsFixed(2)), (v) => widget.data.pm10TotalTime = v),
|
||||
_buildResultRow(_pm10PressureController, "Pressure (hPa)", _pm10PressureResultController, "Result (inHg)", (v) => _calculateVstd(1), (v) => widget.data.pm10Pressure = double.tryParse(v!)),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _pm10TavgController,
|
||||
readOnly: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Ambient Temperature [Tavg=(T1+T2)/2] (°C)',
|
||||
border: OutlineInputBorder(),
|
||||
filled: true,
|
||||
fillColor: Colors.black12),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _pm10QstdController,
|
||||
readOnly: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Flowrate (Standard Air), QSTD (m³/min)',
|
||||
border: OutlineInputBorder(),
|
||||
filled: true,
|
||||
fillColor: Colors.black12),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
TextFormField(controller: _pm10VstdController, readOnly: true, decoration: const InputDecoration(labelText: 'VSTD PM10 (m³)', border: OutlineInputBorder(), filled: true, fillColor: Colors.black12)),
|
||||
|
||||
const Padding(padding: EdgeInsets.symmetric(vertical: 20), child: Text("PM2.5 Data", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
|
||||
_buildResultRow(_pm25FlowRateController, "Flow Rate (cfm)", _pm25FlowRateResultController, "Result (m³/min)", (v) => setState(() => _pm25FlowRateResultController.text = ((double.tryParse(v) ?? 0) * 0.0283).toStringAsFixed(4)), (v) => widget.data.pm25Flowrate = double.tryParse(v!)),
|
||||
_buildResultRow(_pm25TimeController, "Total Time (hours)", _pm25TimeResultController, "Result (mins)", (v) => setState(() => _pm25TimeResultController.text = ((double.tryParse(v) ?? 0) * 60).toStringAsFixed(2)), (v) => widget.data.pm25TotalTime = v),
|
||||
_buildResultRow(_pm25PressureController, "Pressure (hPa)", _pm25PressureResultController, "Result (inHg)", (v) => _calculateVstd(2), (v) => widget.data.pm25Pressure = double.tryParse(v!)),
|
||||
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _pm25TavgController,
|
||||
readOnly: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Ambient Temperature [Tavg=(T1+T2)/2] (°C)',
|
||||
border: OutlineInputBorder(),
|
||||
filled: true,
|
||||
fillColor: Colors.black12),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
TextFormField(
|
||||
controller: _pm25QstdController,
|
||||
readOnly: true,
|
||||
decoration: const InputDecoration(
|
||||
labelText: 'Flowrate (Standard Air), QSTD (m³/min)',
|
||||
border: OutlineInputBorder(),
|
||||
filled: true,
|
||||
fillColor: Colors.black12),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
|
||||
TextFormField(controller: _pm25VstdController, readOnly: true, decoration: const InputDecoration(labelText: 'VSTD PM2.5 (m³)', border: OutlineInputBorder(), filled: true, fillColor: Colors.black12)),
|
||||
|
||||
const SizedBox(height: 16),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user