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 _pm10TimeResultController = TextEditingController();
|
||||||
final _pm10PressureController = TextEditingController();
|
final _pm10PressureController = TextEditingController();
|
||||||
final _pm10PressureResultController = TextEditingController();
|
final _pm10PressureResultController = TextEditingController();
|
||||||
|
final _pm10TavgController = TextEditingController();
|
||||||
|
final _pm10QstdController = TextEditingController();
|
||||||
final _pm10VstdController = TextEditingController();
|
final _pm10VstdController = TextEditingController();
|
||||||
|
|
||||||
// PM2.5 Controllers
|
// PM2.5 Controllers
|
||||||
@ -58,6 +60,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
final _pm25TimeResultController = TextEditingController();
|
final _pm25TimeResultController = TextEditingController();
|
||||||
final _pm25PressureController = TextEditingController();
|
final _pm25PressureController = TextEditingController();
|
||||||
final _pm25PressureResultController = TextEditingController();
|
final _pm25PressureResultController = TextEditingController();
|
||||||
|
final _pm25TavgController = TextEditingController();
|
||||||
|
final _pm25QstdController = TextEditingController();
|
||||||
final _pm25VstdController = TextEditingController();
|
final _pm25VstdController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -88,6 +92,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
_pm10TimeResultController.dispose();
|
_pm10TimeResultController.dispose();
|
||||||
_pm10PressureController.dispose();
|
_pm10PressureController.dispose();
|
||||||
_pm10PressureResultController.dispose();
|
_pm10PressureResultController.dispose();
|
||||||
|
_pm10TavgController.dispose();
|
||||||
|
_pm10QstdController.dispose();
|
||||||
_pm10VstdController.dispose();
|
_pm10VstdController.dispose();
|
||||||
_pm25FlowRateController.dispose();
|
_pm25FlowRateController.dispose();
|
||||||
_pm25FlowRateResultController.dispose();
|
_pm25FlowRateResultController.dispose();
|
||||||
@ -95,6 +101,8 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
_pm25TimeResultController.dispose();
|
_pm25TimeResultController.dispose();
|
||||||
_pm25PressureController.dispose();
|
_pm25PressureController.dispose();
|
||||||
_pm25PressureResultController.dispose();
|
_pm25PressureResultController.dispose();
|
||||||
|
_pm25TavgController.dispose();
|
||||||
|
_pm25QstdController.dispose();
|
||||||
_pm25VstdController.dispose();
|
_pm25VstdController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@ -153,35 +161,58 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
void _calculateVstd(int type) {
|
void _calculateVstd(int type) {
|
||||||
setState(() {
|
setState(() {
|
||||||
try {
|
try {
|
||||||
|
// Get the correct controllers for either PM10 or PM2.5
|
||||||
|
final flowRateCtrl = type == 1 ? _pm10FlowRateController : _pm25FlowRateController;
|
||||||
final pressureCtrl = type == 1 ? _pm10PressureController : _pm25PressureController;
|
final pressureCtrl = type == 1 ? _pm10PressureController : _pm25PressureController;
|
||||||
final flowResultCtrl = type == 1 ? _pm10FlowRateResultController : _pm25FlowRateResultController;
|
|
||||||
final timeResultCtrl = type == 1 ? _pm10TimeResultController : _pm25TimeResultController;
|
final timeResultCtrl = type == 1 ? _pm10TimeResultController : _pm25TimeResultController;
|
||||||
final vstdCtrl = type == 1 ? _pm10VstdController : _pm25VstdController;
|
|
||||||
final pressureResultCtrl = type == 1 ? _pm10PressureResultController : _pm25PressureResultController;
|
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";
|
vstdCtrl.text = "0.000";
|
||||||
return;
|
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 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);
|
pressureResultCtrl.text = pressureInHg.toStringAsFixed(2);
|
||||||
|
|
||||||
double qa_m3min = double.parse(flowResultCtrl.text);
|
// 3. Calculate average temperature in Celsius
|
||||||
double totalTime_min = double.parse(timeResultCtrl.text);
|
double t_avg_celsius = (widget.initialTemp + double.parse(_finalTempController.text)) / 2.0; // ambient temperature
|
||||||
double pa_mmHg = pressureInHg * 25.4;
|
tAvgCtrl.text = t_avg_celsius.toStringAsFixed(2);
|
||||||
double t_avg_celsius = (widget.initialTemp + double.parse(_finalTempController.text)) / 2.0;
|
|
||||||
|
|
||||||
double numerator = qa_m3min * pa_mmHg * 298.15;
|
// 4. Calculate Standard Flowrate (QSTD) using your exact formula
|
||||||
double denominator = 760 * (273.15 + t_avg_celsius);
|
// Formula: (flowrate * result pressure * 298) / (760 * (273 * ambient temperature))
|
||||||
double q_std = numerator / denominator;
|
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;
|
double v_std = q_std * totalTime_min;
|
||||||
|
|
||||||
if (type == 1) {
|
if (type == 1) { // PM10
|
||||||
_pm10VstdController.text = v_std.toStringAsFixed(3);
|
_pm10VstdController.text = v_std.toStringAsFixed(3);
|
||||||
widget.data.pm10Vstd = v_std;
|
widget.data.pm10Vstd = v_std;
|
||||||
} else {
|
} else { // PM2.5
|
||||||
_pm25VstdController.text = v_std.toStringAsFixed(3);
|
_pm25VstdController.text = v_std.toStringAsFixed(3);
|
||||||
widget.data.pm25Vstd = v_std;
|
widget.data.pm25Vstd = v_std;
|
||||||
}
|
}
|
||||||
@ -192,13 +223,10 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// **CRITICAL FIX IS HERE**
|
|
||||||
void _onSubmitPressed() {
|
void _onSubmitPressed() {
|
||||||
if (_formKey.currentState!.validate()) {
|
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.pm10FlowrateResult = _pm10FlowRateResultController.text;
|
||||||
widget.data.pm10TotalTimeResult = _pm10TimeResultController.text;
|
widget.data.pm10TotalTimeResult = _pm10TimeResultController.text;
|
||||||
widget.data.pm10PressureResult = _pm10PressureResultController.text;
|
widget.data.pm10PressureResult = _pm10PressureResultController.text;
|
||||||
@ -206,13 +234,11 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
widget.data.pm25TotalTimeResult = _pm25TimeResultController.text;
|
widget.data.pm25TotalTimeResult = _pm25TimeResultController.text;
|
||||||
widget.data.pm25PressureResult = _pm25PressureResultController.text;
|
widget.data.pm25PressureResult = _pm25PressureResultController.text;
|
||||||
|
|
||||||
// Save optional remarks
|
|
||||||
widget.data.optionalRemark1 = _optionalRemark1Controller.text;
|
widget.data.optionalRemark1 = _optionalRemark1Controller.text;
|
||||||
widget.data.optionalRemark2 = _optionalRemark2Controller.text;
|
widget.data.optionalRemark2 = _optionalRemark2Controller.text;
|
||||||
widget.data.optionalRemark3 = _optionalRemark3Controller.text;
|
widget.data.optionalRemark3 = _optionalRemark3Controller.text;
|
||||||
widget.data.optionalRemark4 = _optionalRemark4Controller.text;
|
widget.data.optionalRemark4 = _optionalRemark4Controller.text;
|
||||||
|
|
||||||
// Now, call the submission function with the fully populated data model
|
|
||||||
widget.onSubmit();
|
widget.onSubmit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -261,17 +287,62 @@ class _AirManualCollectionWidgetState extends State<AirManualCollectionWidget> {
|
|||||||
validator: (v) => v == null ? 'Required' : null,
|
validator: (v) => v == null ? 'Required' : null,
|
||||||
onSaved: (v) => widget.data.powerFailure = v,
|
onSaved: (v) => widget.data.powerFailure = v,
|
||||||
),
|
),
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.symmetric(vertical: 20), child: Text("PM10 Data", style: TextStyle(fontWeight: FontWeight.bold, fontSize: 16))),
|
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(_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(_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!)),
|
_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)),
|
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))),
|
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(_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(_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!)),
|
_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)),
|
TextFormField(controller: _pm25VstdController, readOnly: true, decoration: const InputDecoration(labelText: 'VSTD PM2.5 (m³)', border: OutlineInputBorder(), filled: true, fillColor: Colors.black12)),
|
||||||
|
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user