|
10 | 10 | use crate::config::processing::{NodeConfig, ProcessingGraphConfig}; |
11 | 11 | use crate::preprocessing::differential::SimpleDifferential; |
12 | 12 | use crate::preprocessing::filters::{BandpassFilter, HighpassFilter, LowpassFilter}; |
13 | | -use crate::processing::computing_nodes::{PeakFinderNode, SharedComputingState}; |
| 13 | +use crate::processing::computing_nodes::{ConcentrationNode, PeakFinderNode, SharedComputingState}; |
14 | 14 | use crate::processing::nodes::{ |
15 | 15 | ChannelMixerNode, ChannelSelectorNode, ChannelTarget, DifferentialNode, FilterNode, GainNode, |
16 | 16 | InputNode, MixStrategy, NodeId, PhotoacousticOutputNode, ProcessingData, ProcessingNode, |
@@ -1220,6 +1220,90 @@ impl ProcessingGraph { |
1220 | 1220 |
|
1221 | 1221 | Ok(Box::new(peak_finder)) |
1222 | 1222 | } |
| 1223 | + "computing_concentration" => { |
| 1224 | + // Extract concentration calculator parameters |
| 1225 | + let params = config |
| 1226 | + .parameters |
| 1227 | + .as_object() |
| 1228 | + .ok_or_else(|| anyhow::anyhow!("Concentration node requires parameters"))?; |
| 1229 | + |
| 1230 | + // Create concentration node with shared state |
| 1231 | + let mut concentration_node = ConcentrationNode::new_with_shared_state( |
| 1232 | + config.id.clone(), |
| 1233 | + computing_state.clone(), |
| 1234 | + ); |
| 1235 | + |
| 1236 | + // Extract computing_peak_finder_id (required) |
| 1237 | + let peak_finder_id = params |
| 1238 | + .get("computing_peak_finder_id") |
| 1239 | + .and_then(|v| v.as_str()) |
| 1240 | + .ok_or_else(|| { |
| 1241 | + anyhow::anyhow!( |
| 1242 | + "Concentration node requires 'computing_peak_finder_id' parameter" |
| 1243 | + ) |
| 1244 | + })?; |
| 1245 | + concentration_node = |
| 1246 | + concentration_node.with_peak_finder_source(peak_finder_id.to_string()); |
| 1247 | + |
| 1248 | + // Extract polynomial coefficients (required array of 5 values) |
| 1249 | + if let Some(coeffs_value) = params.get("polynomial_coefficients") { |
| 1250 | + if let Some(coeffs_array) = coeffs_value.as_array() { |
| 1251 | + if coeffs_array.len() == 5 { |
| 1252 | + let mut coefficients = [0.0; 5]; |
| 1253 | + for (i, coeff) in coeffs_array.iter().enumerate() { |
| 1254 | + if let Some(val) = coeff.as_f64() { |
| 1255 | + coefficients[i] = val; |
| 1256 | + } else { |
| 1257 | + return Err(anyhow::anyhow!( |
| 1258 | + "Polynomial coefficient {} must be a number", |
| 1259 | + i |
| 1260 | + )); |
| 1261 | + } |
| 1262 | + } |
| 1263 | + concentration_node = |
| 1264 | + concentration_node.with_polynomial_coefficients(coefficients); |
| 1265 | + } else { |
| 1266 | + return Err(anyhow::anyhow!( |
| 1267 | + "Polynomial coefficients must be an array of exactly 5 values, got {}", |
| 1268 | + coeffs_array.len() |
| 1269 | + )); |
| 1270 | + } |
| 1271 | + } else { |
| 1272 | + return Err(anyhow::anyhow!("Polynomial coefficients must be an array")); |
| 1273 | + } |
| 1274 | + } |
| 1275 | + |
| 1276 | + // Extract optional parameters |
| 1277 | + if let Some(temp_comp) = params.get("temperature_compensation") { |
| 1278 | + if let Some(enable_temp_comp) = temp_comp.as_bool() { |
| 1279 | + concentration_node = |
| 1280 | + concentration_node.with_temperature_compensation(enable_temp_comp); |
| 1281 | + } |
| 1282 | + } |
| 1283 | + |
| 1284 | + if let Some(spectral_line) = params.get("spectral_line_id") { |
| 1285 | + if let Some(line_id) = spectral_line.as_str() { |
| 1286 | + concentration_node = |
| 1287 | + concentration_node.with_spectral_line_id(line_id.to_string()); |
| 1288 | + } |
| 1289 | + } |
| 1290 | + |
| 1291 | + if let Some(min_threshold) = params.get("min_amplitude_threshold") { |
| 1292 | + if let Some(threshold) = min_threshold.as_f64() { |
| 1293 | + concentration_node = |
| 1294 | + concentration_node.with_min_amplitude_threshold(threshold as f32); |
| 1295 | + } |
| 1296 | + } |
| 1297 | + |
| 1298 | + if let Some(max_conc) = params.get("max_concentration_ppm") { |
| 1299 | + if let Some(max_ppm) = max_conc.as_f64() { |
| 1300 | + concentration_node = |
| 1301 | + concentration_node.with_max_concentration(max_ppm as f32); |
| 1302 | + } |
| 1303 | + } |
| 1304 | + |
| 1305 | + Ok(Box::new(concentration_node)) |
| 1306 | + } |
1223 | 1307 | "gain" => { |
1224 | 1308 | // Extract gain parameters |
1225 | 1309 | let params = config |
|
0 commit comments