Metrics.hpp 2.88 KB
Newer Older
1
2
3
4
#pragma once

#include "elsaDefines.h"
#include "DataContainer.h"
5
#include "Statistics.hpp"
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#include <cmath>
#include <numeric>
#include <algorithm>
#include <utility>

namespace elsa
{
    /**
     * @brief Compute the Relative Error between two given signals.
     *
     * @param dc1 DataContainer signal
     * @param dc2 DataContainer signal
     */
    template <typename data_t = real_t>
    constexpr auto relativeError(DataContainer<data_t> dc1, DataContainer<data_t> dc2)
        -> long double
    {
24
        if (dc1.getDataDescriptor() != dc2.getDataDescriptor()) {
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
            throw LogicError(
                std::string("Metrics::relativeError: shapes of both signals should match"));
        }

        DataContainer<data_t> diff = dc1 - dc2;
        return diff.l2Norm() / dc2.l2Norm();
    }

    /**
     * @brief Compute the Peak Signal-to-Noise Ratio.
     *
     * @param dc1 DataContainer signal
     * @param dc2 DataContainer signal
     * @param dataRange The data range of the signals (distance between minimum and maximum possible
     * values).
     */
    template <typename data_t = real_t>
    constexpr auto peakSignalToNoiseRatio(DataContainer<data_t> dc1, DataContainer<data_t> dc2,
                                          data_t dataRange) -> long double
    {
        if (dc1.getDataDescriptor() != dc2.getDataDescriptor()) {
            throw LogicError(std::string(
                "Metrics::peakSignalToNoiseRatio: shapes of both signals should match"));
        }

50
        long double err = meanSquaredError<data_t>(dc1, dc2);
51
        return 10 * std::log10l((std::pow(dataRange, 2) / err));
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
    }

    /**
     * @brief Compute the Peak Signal-to-Noise Ratio.
     *
     * @param dc1 DataContainer signal
     * @param dc2 DataContainer signal
     */
    template <typename data_t = real_t>
    constexpr auto peakSignalToNoiseRatio(DataContainer<data_t> dc1, DataContainer<data_t> dc2)
        -> long double
    {
        if (dc1.getDataDescriptor() != dc2.getDataDescriptor()) {
            throw LogicError(std::string(
                "Metrics::peakSignalToNoiseRatio: shapes of both signals should match"));
        }

        data_t dataMin = std::numeric_limits<data_t>::min();
        data_t dataMax = std::numeric_limits<data_t>::max();

andibraimllari's avatar
andibraimllari committed
72
73
        data_t trueMin = std::min(minElement(dc1), minElement(dc2));
        data_t trueMax = std::max(maxElement(dc1), maxElement(dc2));
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90

        if (trueMin < dataMin || trueMax > dataMax) {
            throw LogicError(
                std::string("Metrics::peakSignalToNoiseRatio: extreme values of the signals "
                            "exceed the range expected for its data type"));
        }

        data_t dataRange;
        if (trueMin >= 0) {
            dataRange = dataMax;
        } else {
            dataRange = dataMax - dataMin;
        }

        return peakSignalToNoiseRatio(dc1, dc2, dataRange);
    }
} // namespace elsa