55#include < cstdio>
66#include < stdexcept>
77
8+ namespace {
9+
10+ bool is_supported_global_polarity (const std::string& polarity) {
11+ return polarity == " positive" ||
12+ polarity == " negative" ||
13+ polarity == " absolute" ;
14+ }
15+
16+ bool is_supported_global_height_mode (const std::string& height_mode) {
17+ return height_mode == " raw" ||
18+ height_mode == " peak_to_baseline" ||
19+ height_mode == " peak_to_peak" ;
20+ }
21+
22+ bool is_supported_global_baseline_mode (const std::string& baseline_mode) {
23+ return baseline_mode == " zero" ||
24+ baseline_mode == " segment_mean" ||
25+ baseline_mode == " edge_mean" ;
26+ }
27+
28+ } // namespace
29+
830
931// -------------------- FullWindowSupport --------------------
1032/* *
@@ -1191,6 +1213,9 @@ GlobalPeakLocator::GlobalPeakLocator(
11911213 bool compute_area,
11921214 bool allow_negative_area,
11931215 std::shared_ptr<BaseSupport> support,
1216+ const std::string& polarity,
1217+ const std::string& height_mode,
1218+ const std::string& baseline_mode,
11941219 bool debug_mode
11951220)
11961221 : BasePeakLocator(
@@ -1201,22 +1226,153 @@ GlobalPeakLocator::GlobalPeakLocator(
12011226 max_number_of_peaks,
12021227 std::move (support),
12031228 debug_mode
1204- )
1229+ ),
1230+ polarity(polarity),
1231+ height_mode(height_mode),
1232+ baseline_mode(baseline_mode)
12051233{
1234+ this ->validate_measurement_modes ();
1235+
12061236 if (this ->debug_mode ) {
12071237 std::printf (
1208- " [GlobalPeakLocator] Initialized | support=%s | compute_width=%d | compute_area=%d | allow_negative_area=%d | padding_value=%d | max_number_of_peaks=%d\n " ,
1238+ " [GlobalPeakLocator] Initialized | support=%s | compute_width=%d | compute_area=%d | allow_negative_area=%d | padding_value=%d | max_number_of_peaks=%d | polarity=%s | height_mode=%s | baseline_mode=%s \n " ,
12091239 this ->support ->get_name ().c_str (),
12101240 static_cast <int >(this ->compute_width ),
12111241 static_cast <int >(this ->compute_area ),
12121242 static_cast <int >(this ->allow_negative_area ),
12131243 this ->padding_value ,
1214- this ->max_number_of_peaks
1244+ this ->max_number_of_peaks ,
1245+ this ->polarity .c_str (),
1246+ this ->height_mode .c_str (),
1247+ this ->baseline_mode .c_str ()
1248+ );
1249+ }
1250+ }
1251+
1252+
1253+ void GlobalPeakLocator::validate_measurement_modes () const {
1254+ if (!is_supported_global_polarity (this ->polarity )) {
1255+ throw std::runtime_error (
1256+ " GlobalPeakLocator polarity must be one of: 'positive', 'negative', 'absolute'."
1257+ );
1258+ }
1259+
1260+ if (!is_supported_global_height_mode (this ->height_mode )) {
1261+ throw std::runtime_error (
1262+ " GlobalPeakLocator height_mode must be one of: 'raw', 'peak_to_baseline', 'peak_to_peak'."
1263+ );
1264+ }
1265+
1266+ if (!is_supported_global_baseline_mode (this ->baseline_mode )) {
1267+ throw std::runtime_error (
1268+ " GlobalPeakLocator baseline_mode must be one of: 'zero', 'segment_mean', 'edge_mean'."
12151269 );
12161270 }
12171271}
12181272
12191273
1274+ double GlobalPeakLocator::compute_baseline (
1275+ const std::vector<double >& signal,
1276+ size_t start,
1277+ size_t end,
1278+ size_t left_boundary,
1279+ size_t right_boundary
1280+ ) const {
1281+ if (this ->baseline_mode == " zero" ) {
1282+ return 0.0 ;
1283+ }
1284+
1285+ if (this ->baseline_mode == " segment_mean" ) {
1286+ double sum = 0.0 ;
1287+
1288+ for (size_t index = start; index < end; ++index) {
1289+ sum += signal[index];
1290+ }
1291+
1292+ return sum / static_cast <double >(end - start);
1293+ }
1294+
1295+ return 0.5 * (signal[left_boundary] + signal[right_boundary]);
1296+ }
1297+
1298+
1299+ size_t GlobalPeakLocator::find_measurement_peak_index (
1300+ const std::vector<double >& signal,
1301+ size_t start,
1302+ size_t end,
1303+ double baseline
1304+ ) const {
1305+ if (this ->polarity == " positive" ) {
1306+ return this ->find_local_peak (signal.data (), start, end);
1307+ }
1308+
1309+ if (this ->polarity == " negative" ) {
1310+ size_t best_index = start;
1311+ double minimum_value = signal[start];
1312+
1313+ for (size_t index = start + 1 ; index < end; ++index) {
1314+ if (signal[index] < minimum_value) {
1315+ minimum_value = signal[index];
1316+ best_index = index;
1317+ }
1318+ }
1319+
1320+ return best_index;
1321+ }
1322+
1323+ size_t best_index = start;
1324+ double maximum_excursion = std::abs (signal[start] - baseline);
1325+
1326+ for (size_t index = start + 1 ; index < end; ++index) {
1327+ const double excursion = std::abs (signal[index] - baseline);
1328+
1329+ if (excursion > maximum_excursion) {
1330+ maximum_excursion = excursion;
1331+ best_index = index;
1332+ }
1333+ }
1334+
1335+ return best_index;
1336+ }
1337+
1338+
1339+ double GlobalPeakLocator::compute_peak_height (
1340+ const std::vector<double >& signal,
1341+ size_t left_boundary,
1342+ size_t right_boundary,
1343+ size_t peak_index,
1344+ double baseline
1345+ ) const {
1346+ const double peak_value = signal[peak_index];
1347+
1348+ if (this ->height_mode == " raw" ) {
1349+ return peak_value;
1350+ }
1351+
1352+ if (this ->height_mode == " peak_to_baseline" ) {
1353+ if (this ->polarity == " positive" ) {
1354+ return peak_value - baseline;
1355+ }
1356+
1357+ if (this ->polarity == " negative" ) {
1358+ return baseline - peak_value;
1359+ }
1360+
1361+ return std::abs (peak_value - baseline);
1362+ }
1363+
1364+ double minimum_value = signal[left_boundary];
1365+ double maximum_value = signal[left_boundary];
1366+
1367+ for (size_t index = left_boundary + 1 ; index <= right_boundary; ++index) {
1368+ minimum_value = std::min (minimum_value, signal[index]);
1369+ maximum_value = std::max (maximum_value, signal[index]);
1370+ }
1371+
1372+ return maximum_value - minimum_value;
1373+ }
1374+
1375+
12201376/* *
12211377 * @brief Detect a global peak using the same signal for value and support.
12221378 *
@@ -1281,13 +1437,28 @@ std::vector<PeakData> GlobalPeakLocator::locate_peaks_with_support(
12811437 right_boundary
12821438 );
12831439
1284- const size_t value_peak_index = this ->find_local_peak (
1285- value_signal.data (),
1440+ const double baseline = this ->compute_baseline (
1441+ value_signal,
1442+ 0 ,
1443+ signal_size,
1444+ left_boundary,
1445+ right_boundary
1446+ );
1447+
1448+ const size_t value_peak_index = this ->find_measurement_peak_index (
1449+ value_signal,
12861450 left_boundary,
1287- right_boundary + 1
1451+ right_boundary + 1 ,
1452+ baseline
12881453 );
12891454
1290- const double peak_value = value_signal[value_peak_index];
1455+ const double peak_value = this ->compute_peak_height (
1456+ value_signal,
1457+ left_boundary,
1458+ right_boundary,
1459+ value_peak_index,
1460+ baseline
1461+ );
12911462
12921463 double width = static_cast <double >(this ->padding_value );
12931464 double area = static_cast <double >(this ->padding_value );
@@ -1322,13 +1493,18 @@ std::vector<PeakData> GlobalPeakLocator::locate_peaks_with_support(
13221493 " support=%s | signal_size=%zu | "
13231494 " support_peak_index=%zu | value_peak_index=%zu | "
13241495 " left_boundary=%zu | right_boundary=%zu | "
1496+ " baseline=%g | polarity=%s | height_mode=%s | baseline_mode=%s | "
13251497 " peak_value=%g | width=%g | area=%g\n " ,
13261498 this ->support ->get_name ().c_str (),
13271499 signal_size,
13281500 support_peak_index,
13291501 value_peak_index,
13301502 left_boundary,
13311503 right_boundary,
1504+ baseline,
1505+ this ->polarity .c_str (),
1506+ this ->height_mode .c_str (),
1507+ this ->baseline_mode .c_str (),
13321508 peak_value,
13331509 width,
13341510 area
0 commit comments