Skip to content

Commit 48a9c27

Browse files
committed
Added TIntegrator
feat: Add TIntegrator class for numerical integration - Introduced TIntegrator class to perform numerical integration on a signal line. - Supports three integration methods: - Trapezoidal (default) - Simpson - Boole docs: - Updated Doxygen comments for better clarity and completeness.
1 parent 2198776 commit 48a9c27

File tree

12 files changed

+254
-1
lines changed

12 files changed

+254
-1
lines changed

.clang-tidy

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ Checks: >
1212
CheckOptions:
1313
- key: bugprone-reserved-identifier.AllowedIdentifiers
1414
value: '_USE_MATH_DEFINES'
15+
- key: readability-magic-numbers.IgnoredFloatingPointValues
16+
value: '1.0;100.0;2.0;6.0;90.0'
17+
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredFloatingPointValues
18+
value: '1.0;100.0;2.0;6.0;90.0'
19+
- key: readability-magic-numbers.IgnoredIntegerValues
20+
value: '1;2;3;4;7;12;32'
21+
- key: cppcoreguidelines-avoid-magic-numbers.IgnoredIntegerValues
22+
value: '1;2;3;4;7;12;32'
1523

1624
WarningsAsErrors: 'bugprone-*,performance-*'
1725
HeaderFilterRegex: 'src/*.*'

src/core/TCore.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
* TODO: [GLOBAL] ??? Investigate adding asynchronous computation ???
99
* TODO: [GLOBAL] ??? Investigate adding interfaces for signal processing ???
1010
* TODO: [GLOBAL] Validate @throws tags in the documentation
11-
* ? Consider using "std::optional" for optional parameters
11+
* ? Consider using "std::optional" for optional parameters ?
12+
* ? use ++i instead of i++ in for loops ?
1213
*/
1314

1415
#pragma once

src/core/TSignalLine.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* TODO: ??? Add generation inside the signal line ???
88
* !TODO: ??? Make a class for Point ???
99
* TODO: Add push/pop point method
10+
* !TODO: Make it get only x or y coordinates vector
1011
*/
1112

1213
#pragma once
@@ -46,6 +47,7 @@ static const std::string DEFAULT_GRAPH_LABEL =
4647
} // namespace SL
4748

4849
/**
50+
* @struct Point
4951
* @brief Represents a 2D point with x and y coordinates.
5052
*/
5153
struct Point {
@@ -54,6 +56,7 @@ struct Point {
5456
};
5557

5658
/**
59+
* @struct TSignalLineParams
5760
* @brief Contains parameters used for describing a signal line.
5861
*/
5962
struct TSignalLineParams {

src/gen/TGenerator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ static const std::string DEFAULT_GRAPH_LABEL =
1919
} // namespace GEN
2020

2121
/**
22+
* @struct TGeneratorParams
2223
* @brief Parameters for generating a signal line.
2324
*/
2425
struct TGeneratorParams {

src/io/TFileWriter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <string>
1111

1212
/**
13+
* @struct TFileWriterParams
1314
* @brief Parameters for writing a signal line to a file.
1415
*/
1516
struct TFileWriterParams {

src/io/TGnuPlotViewer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include <string>
1717

1818
/**
19+
* @struct TGnuPlotViewerParams
1920
* @brief Parameters for configuring the GnuPlot viewer.
2021
*/
2122
struct TGnuPlotViewerParams {

src/proc/TDifferentiator.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ bool TDifferentiator::isExecuted() const {
3737
return _isExecuted;
3838
}
3939

40+
// TODO: Move differentiation logic to a separate method for each
41+
// differentiation method
42+
// TODO: Add switch-case for each differentiation method
4043
void TDifferentiator::execute() {
4144
if (_params.signalLine == nullptr) {
4245
throw SignalProcesserException("Invalid signal line (nullptr)");

src/proc/TDifferentiator.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum class DifferentiationMethod : std::uint8_t {
4444
};
4545

4646
/**
47+
* @struct TDifferentiatorParams
4748
* @brief Parameters for differentiating a signal line.
4849
*/
4950
struct TDifferentiatorParams {

src/proc/TIntegrator.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
#include "TIntegrator.h"
2+
#include <cstddef>
3+
#include "TCore.h"
4+
#include "TSignalLine.h"
5+
6+
/**
7+
** PUBLIC METHODS
8+
*/
9+
10+
TIntegrator::TIntegrator(const TSignalLine* signalLine,
11+
IntegrationMethod method)
12+
: _params{signalLine, method} {}
13+
14+
TIntegrator::TIntegrator(TIntegratorParams params) : _params(params) {}
15+
16+
double TIntegrator::getIntegral() const {
17+
if (!_isExecuted) {
18+
throw SignalProcesserException("Integrator not executed");
19+
}
20+
return _integral;
21+
}
22+
23+
const TIntegratorParams& TIntegrator::getParams() const {
24+
return _params;
25+
}
26+
27+
bool TIntegrator::isExecuted() const {
28+
return _isExecuted;
29+
}
30+
31+
// TODO: Move integration logic to a separate method for each integration method
32+
void TIntegrator::execute() {
33+
if (_params.signalLine == nullptr) {
34+
throw SignalProcesserException("Invalid signal line (nullptr)");
35+
}
36+
if (_params.signalLine->getParams().pointsCount < 2) {
37+
throw SignalProcesserException(
38+
"Insufficient number of points: at least 2 points are required");
39+
}
40+
41+
const std::size_t pointsCount = _params.signalLine->getParams().pointsCount;
42+
_integral = 0.0;
43+
44+
switch (_params.method) {
45+
case IntegrationMethod::Trapezoidal:
46+
for (size_t i = 1; i < pointsCount; ++i) {
47+
const double xCoordBefore = _params.signalLine->getPoint(i - 1).x;
48+
const double xCoord = _params.signalLine->getPoint(i).x;
49+
const double yCoordBefore = _params.signalLine->getPoint(i - 1).y;
50+
const double yCoord = _params.signalLine->getPoint(i).y;
51+
_integral += (yCoordBefore + yCoord) / 2.0 * (xCoord - xCoordBefore);
52+
}
53+
break;
54+
55+
case IntegrationMethod::Simpson:
56+
if (pointsCount % 2 == 0) {
57+
throw SignalProcesserException(
58+
"Simpson's rule requires an odd number of points");
59+
}
60+
for (size_t i = 1; i < pointsCount - 1; i += 2) {
61+
const double xCoordBefore = _params.signalLine->getPoint(i - 1).x;
62+
const double xCoordNext = _params.signalLine->getPoint(i + 1).x;
63+
const double yCoordBefore = _params.signalLine->getPoint(i - 1).y;
64+
const double yCoord = _params.signalLine->getPoint(i).y;
65+
const double yCoordNext = _params.signalLine->getPoint(i + 1).y;
66+
_integral += (xCoordNext - xCoordBefore) / 6.0 *
67+
(yCoordBefore + 4 * yCoord + yCoordNext);
68+
}
69+
break;
70+
71+
case IntegrationMethod::Boole:
72+
if (pointsCount % 4 != 1) {
73+
throw SignalProcesserException(
74+
"Boole's rule requires number of points to be 4k + 1");
75+
}
76+
for (size_t i = 0; i < pointsCount - 4; i += 4) {
77+
const double xCoord = _params.signalLine->getPoint(i).x;
78+
const double xCoordNext4 = _params.signalLine->getPoint(i + 4).x;
79+
const double yCoord = _params.signalLine->getPoint(i).y;
80+
const double yCoordNext1 = _params.signalLine->getPoint(i + 1).y;
81+
const double yCoordNext2 = _params.signalLine->getPoint(i + 2).y;
82+
const double yCoordNext3 = _params.signalLine->getPoint(i + 3).y;
83+
const double yCoordNext4 = _params.signalLine->getPoint(i + 4).y;
84+
_integral += (xCoordNext4 - xCoord) / 90.0 *
85+
(7 * yCoord + 32 * yCoordNext1 + 12 * yCoordNext2 +
86+
32 * yCoordNext3 + 7 * yCoordNext4);
87+
}
88+
break;
89+
90+
default:
91+
throw SignalProcesserException("Unknown integration method");
92+
}
93+
94+
_isExecuted = true;
95+
}

src/proc/TIntegrator.h

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#pragma once
2+
3+
#include "TSignalLine.h"
4+
5+
#include <cstdint>
6+
7+
/**
8+
* @enum IntegrationMethod
9+
* @brief Specifies the available methods for numerical integration.
10+
*
11+
* This enumeration defines several methods for performing numerical
12+
* integration:
13+
*
14+
* - `Trapezoidal`:
15+
* This method uses the trapezoidal rule for numerical integration. It
16+
* approximates the area under the curve by dividing the curve into trapezoids.
17+
* This method requires at least two points for computation and works well for
18+
* functions that are linear or approximately linear between points. The
19+
* trapezoidal rule calculates the area of each trapezoid and sums them up.
20+
* - Minimum points required: 2.
21+
*
22+
* - `Simpson`:
23+
* This method uses Simpson's rule, which is based on approximating the
24+
* function by a quadratic polynomial on each segment. It requires an odd number
25+
* of points (at least 3) because it calculates the area using pairs of
26+
* intervals, forming parabolic segments that give a higher level of accuracy
27+
* than the trapezoidal rule for smooth functions.
28+
* - Minimum points required: 3 (must be an odd number).
29+
*
30+
* - `Boole`:
31+
* This method uses Boole's rule (also known as the fifth-degree polynomial
32+
* rule), which is a higher-order numerical integration method. It approximates
33+
* the function using a polynomial of degree 5 on each segment. Boole's rule
34+
* requires that the number of points satisfies the condition \(4k + 1\),
35+
* meaning the number of points must be equal to 5, 9, 13, etc.
36+
* - Minimum points required: 5 (must satisfy \(4k + 1\) condition).
37+
*/
38+
enum class IntegrationMethod : std::uint8_t {
39+
Trapezoidal, ///< Trapezoidal rule (requires at least 2 points).
40+
Simpson, ///< Simpson's rule (requires at least 3 points, and the number must
41+
///< be odd).
42+
Boole ///< Boole's rule (requires at least 5 points, and the number must
43+
///< satisfy 4k + 1).
44+
};
45+
46+
/**
47+
* @struct TIntegratorParams
48+
* @brief Defines the parameters used for numerical integration.
49+
*/
50+
struct TIntegratorParams {
51+
const TSignalLine* signalLine =
52+
nullptr; ///< Pointer to the signal line to be integrated.
53+
IntegrationMethod method =
54+
IntegrationMethod::Trapezoidal; ///< (optional) Integration method.
55+
};
56+
57+
/**
58+
* @class TIntegrator
59+
* @brief Class for performing numerical integration on a signal line.
60+
*/
61+
class TIntegrator {
62+
public:
63+
/**
64+
* @brief Constructs a TIntegrator with a signal line and an integration
65+
* method.
66+
*
67+
* @param signalLine Pointer to the signal line to integrate.
68+
* @param method (optional) The method to use for integration.
69+
*/
70+
TIntegrator(const TSignalLine* signalLine,
71+
IntegrationMethod method = IntegrationMethod::Trapezoidal);
72+
73+
/**
74+
* @brief Constructs a TIntegrator with integration parameters.
75+
*
76+
* @param params Structure containing the parameters for signal integration.
77+
*/
78+
TIntegrator(TIntegratorParams params);
79+
80+
/**
81+
* @brief Default destructor.
82+
*/
83+
~TIntegrator() = default;
84+
85+
/**
86+
* @brief Default copy constructor.
87+
*/
88+
TIntegrator(const TIntegrator&) = default;
89+
90+
/**
91+
* @brief Default move constructor.
92+
*/
93+
TIntegrator(TIntegrator&&) noexcept = default;
94+
95+
/**
96+
* @brief Default copy assignment operator.
97+
*/
98+
TIntegrator& operator=(const TIntegrator&) = default;
99+
100+
/**
101+
* @brief Default move assignment operator.
102+
*/
103+
TIntegrator& operator=(TIntegrator&&) noexcept = default;
104+
105+
/**
106+
* @brief Retrieves the computed integral.
107+
*
108+
* @return double The result of the numerical integration.
109+
*/
110+
[[nodiscard]] double getIntegral() const;
111+
112+
/**
113+
* @brief Retrieves the parameters used for integration.
114+
*
115+
* @return const TIntegratorParams& Reference to the integration parameters.
116+
*/
117+
[[nodiscard]] const TIntegratorParams& getParams() const;
118+
119+
/**
120+
* @brief Checks whether the integration has been executed.
121+
*
122+
* @return bool True if the integration process has been executed, false
123+
* otherwise.
124+
*/
125+
[[nodiscard]] bool isExecuted() const;
126+
127+
/**
128+
* @brief Executes the numerical integration of the signal line.
129+
*/
130+
void execute();
131+
132+
private:
133+
double _integral = 0.0; ///< Stores the computed integral value.
134+
TIntegratorParams _params = {}; ///< Parameters for integration.
135+
bool _isExecuted =
136+
false; ///< Indicates if the integration has been executed.
137+
};

0 commit comments

Comments
 (0)