Main

 avatar
unknown
c_cpp
21 days ago
6.9 kB
8
Indexable
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <sstream>
#include <algorithm>
#include <numeric>
#include <filesystem>
#include <map>
#include <set>
#include <functional>
#include <unordered_set>

using namespace std;
namespace fs = filesystem;

struct Parameters {
    int vt, width, pulse_delta, below_drop_ratio;
    double drop_ratio;
};

bool parseIniFile(const string& filename, Parameters& params) {
    ifstream file(filename);
    if (!file) {
        cerr << "Invalid INI file: " << filename << " could not be opened.\n";
        return false;
    }

    map<string, string> paramMap;
    set<string> allowedKeys = { "vt", "width", "pulse_delta", "drop_ratio", "below_drop_ratio" };

    string line;
    while (getline(file, line)) {
        if (line.empty() || line[0] == '#') continue;

        istringstream iss(line);
        string key, value;
        if (getline(iss, key, '=') && getline(iss, value)) {
            // Checking for any unexpected keys
            if (allowedKeys.find(key) == allowedKeys.end()) {
                cerr << "Invalid or duplicate INI key: " << key << "\n";
                return false;
            }
            // Checking for duplicates
            if (paramMap.find(key) != paramMap.end()) {
                cerr << "Invalid or duplicate INI key: " << key << "\n";
                return false;
            }
            paramMap[key] = value;
        }
    }

    // Check for missing keys
    for (const string& requiredKey : allowedKeys) {
        if (paramMap.find(requiredKey) == paramMap.end()) {
            cerr << "Invalid INI file: missing one or more keys\n";
            return false;
        }
    }

    try {
        params.vt = stoi(paramMap.at("vt"));
        params.width = stoi(paramMap.at("width"));
        params.pulse_delta = stoi(paramMap.at("pulse_delta"));
        params.drop_ratio = stod(paramMap.at("drop_ratio"));
        params.below_drop_ratio = stoi(paramMap.at("below_drop_ratio"));
    }
    catch (const invalid_argument& e) {
        cerr << "Invalid value for vt in " << filename << "\n";
        return false;
    }
    return true;
}

vector<int> readAndNegateFile(const string& filename) {
    ifstream file(filename);
    vector<int> data((istream_iterator<int>(file)), istream_iterator<int>());
    transform(data.begin(), data.end(), data.begin(), negate<int>());
    return data;
}

vector<int> smoothData(const vector<int>& data) {
    if (data.size() < 7) return data;
    vector<int> smoothed;

    copy(data.begin(), data.begin() + 3, back_inserter(smoothed));
    for (size_t i = 3; i < data.size() - 3; ++i) {
        int avg = ((data[i - 3]) + (2 * data[i - 2]) + (3 * data[i - 1]) + (3 * data[i]) + (3 * data[i + 1]) + (2 * data[i + 2]) + (data[i + 3])) / 15;
        smoothed.push_back(avg);
    }
    copy(data.end() - 3, data.end(), back_inserter(smoothed));

    return smoothed;
}

vector<int> detectPulses(const vector<int>& smoothed, int vt) {
    vector<int> pulses;
    for (size_t i = 0; i < smoothed.size() - 2; ++i) {
        if (smoothed[i + 2] - smoothed[i] > vt) {
            pulses.push_back(i);
            while (i + 2 < smoothed.size() && smoothed[i + 2] >= smoothed[i]) {
                i++;
            }
        }
    }
    return pulses;
}

void processFiles(const Parameters& params) {
    for (const auto& entry : fs::directory_iterator(".")) {
        if (entry.path().extension() == ".dat") {
            vector<int> data = readAndNegateFile(entry.path().string());
            if (data.empty()) continue;

            vector<int> smoothed = smoothData(data);
            vector<int> pulses = detectPulses(smoothed, params.vt);

            if (pulses.empty()) continue;
            cout << entry.path().filename() << ":\n";

            unordered_set<int> ignored_pulses;

            for (auto it = pulses.begin(); it != pulses.end(); ++it) {
                auto nextIt = adjacent_find(it, pulses.end(), [params](int a, int b) { return b - a <= params.pulse_delta; });
                if (nextIt != pulses.end()) {
                    int firstPulse = *it;
                    int nextPulse = *nextIt;

                    int peak = smoothed[firstPulse];
                    for (int j = firstPulse + 1; j <= nextPulse; ++j) {
                        peak = max(peak, smoothed[j]);
                    }
                    if (peak > 0) {
                        int drop_count = 0;
                        for (int j = firstPulse + 1; j < nextPulse; ++j) {
                            if (smoothed[j] > params.drop_ratio * peak) {
                                drop_count++;
                            }
                        }
                        if (drop_count < params.below_drop_ratio) {
                            // Ensure the first pulse is not already ignored
                            if (ignored_pulses.count(firstPulse) == 0) {
                                ignored_pulses.insert(firstPulse);
                                cout << "Found piggyback at " << firstPulse << "\n";
                            }
                        }
                    }
                    it = nextIt;
                }
            }
            for (size_t i = 0; i < pulses.size(); ++i) {
                if (ignored_pulses.count(pulses[i])) continue;

                int pulseStart = pulses[i];
                int pulseEnd = min(pulseStart + params.width, static_cast<int>(data.size()));
                for (size_t j = i + 1; j < pulses.size(); ++j) {
                    if (pulses[j] < pulseEnd) {
                        pulseEnd = pulses[j];
                        break;
                    }
                }
                int area = 0;
                for (int k = pulseStart; k < pulseEnd && k < data.size(); ++k) {
                    area += data[k];
                }
                cout << pulseStart << " (" << area << ")\n";
            }
        }
    }
}

void printParameters(const Parameters& params) {
    cout << "# Pulse parameters\n";
    cout << "vt = " << params.vt << "\n";
    cout << "width = " << params.width << "\n";
    cout << "pulse_delta = " << params.pulse_delta << "\n";
    cout << "drop_ratio = " << params.drop_ratio << "\n";
    cout << "below_drop_ratio = " << params.below_drop_ratio << "\n";
    cout << "\n";
}

int main(int argc, char* argv[]) {
    if (argc != 2) {
        cerr << "Usage: " << argv[0] << " <ini_file>\n";
        return 1;
    }

    Parameters params;
    if (!parseIniFile(argv[1], params)) {
        return 1;
    }

    printParameters(params);

    processFiles(params);
    return 0;
}
Editor is loading...
Leave a Comment