Skip to content

Commit 53d605b

Browse files
committed
address more comments
Signed-off-by: Santiago Figueroa Manrique <figueroa1395@gmail.com>
1 parent 22e0519 commit 53d605b

File tree

1 file changed

+104
-110
lines changed

1 file changed

+104
-110
lines changed

tests/cpp_unit_tests/test_current_sensor.cpp

Lines changed: 104 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -25,63 +25,61 @@ void check_nan_preserving_equality(RealValue<asymmetric_t> const& actual, RealVa
2525
check_nan_preserving_equality(actual(i), expected(i));
2626
}
2727
}
28+
using TerminalAndAngleTypePair = std::pair<MeasuredTerminalType, AngleMeasurementType>;
29+
30+
auto const terminal_and_angle_measurement_types = [] {
31+
std::vector<TerminalAndAngleTypePair> result;
32+
for (auto const terminal_type :
33+
{MeasuredTerminalType::branch_from, MeasuredTerminalType::branch_to, MeasuredTerminalType::branch3_1,
34+
MeasuredTerminalType::branch3_2, MeasuredTerminalType::branch3_3}) {
35+
for (auto const angle_measurement_type :
36+
{AngleMeasurementType::global_angle, AngleMeasurementType::local_angle}) {
37+
result.emplace_back(terminal_type, angle_measurement_type);
38+
}
39+
}
40+
return result;
41+
}();
2842
} // namespace
2943

3044
TEST_CASE("Test current sensor") {
3145
SUBCASE("Symmetric Current Sensor") {
32-
for (auto const terminal_type :
33-
{MeasuredTerminalType::branch_from, MeasuredTerminalType::branch_to, MeasuredTerminalType::branch3_1,
34-
MeasuredTerminalType::branch3_2, MeasuredTerminalType::branch3_3}) {
46+
for (auto const [terminal_type, angle_measurement_type] : terminal_and_angle_measurement_types) {
3547
CAPTURE(terminal_type);
36-
for (auto const angle_measurement_type :
37-
{AngleMeasurementType::global_angle, AngleMeasurementType::local_angle}) {
38-
CAPTURE(angle_measurement_type);
39-
40-
CurrentSensorInput<symmetric_t> sym_current_sensor_input{};
41-
sym_current_sensor_input.id = 0;
42-
sym_current_sensor_input.measured_object = 1;
43-
sym_current_sensor_input.measured_terminal_type = terminal_type;
44-
sym_current_sensor_input.angle_measurement_type = angle_measurement_type;
45-
sym_current_sensor_input.i_sigma = 1.0;
46-
sym_current_sensor_input.i_measured = 1.0 * 1e3;
47-
sym_current_sensor_input.i_angle_measured = pi / 4.;
48-
sym_current_sensor_input.i_angle_sigma = 0.2;
49-
50-
double const u_rated = 10.0e3;
51-
double const base_current = base_power_3p / u_rated / sqrt3;
52-
double const i_pu = 1.0e3 / base_current;
53-
double const i_sigma_pu = 1.0 / base_current;
54-
double const i_variance_pu = i_sigma_pu * i_sigma_pu;
55-
double const i_angle = pi / 4.;
56-
double const i_angle_sigma_pi = 0.2;
57-
double const i_angle_variance_pu = i_angle_sigma_pi * i_angle_sigma_pi;
48+
CAPTURE(angle_measurement_type);
49+
50+
CurrentSensorInput<symmetric_t> sym_current_sensor_input{};
51+
sym_current_sensor_input.id = 0;
52+
sym_current_sensor_input.measured_object = 1;
53+
sym_current_sensor_input.measured_terminal_type = terminal_type;
54+
sym_current_sensor_input.angle_measurement_type = angle_measurement_type;
55+
sym_current_sensor_input.i_sigma = 1.0;
56+
sym_current_sensor_input.i_measured = 1.0 * 1e3;
57+
sym_current_sensor_input.i_angle_measured = pi / 4.;
58+
sym_current_sensor_input.i_angle_sigma = 0.2;
5859

60+
double const u_rated = 10.0e3;
61+
double const base_current = base_power_3p / u_rated / sqrt3;
62+
double const i_pu = 1.0e3 / base_current;
63+
double const i_sigma_pu = 1.0 / base_current;
64+
double const i_variance_pu = i_sigma_pu * i_sigma_pu;
65+
double const i_angle = pi / 4.;
66+
double const i_angle_sigma_pi = 0.2;
67+
double const i_angle_variance_pu = i_angle_sigma_pi * i_angle_sigma_pi;
68+
69+
CurrentSensor<symmetric_t> const sym_current_sensor{sym_current_sensor_input, u_rated};
70+
CHECK(sym_current_sensor.get_terminal_type() == terminal_type);
71+
CHECK(sym_current_sensor.get_angle_measurement_type() == angle_measurement_type);
72+
73+
SUBCASE("Output for symmetric parameters") {
5974
auto const i_sym = ComplexValue<symmetric_t>{(1e3 * exp(1.0i * i_angle)) / base_current};
60-
auto const i_asym = ComplexValue<asymmetric_t>{(1e3 * exp(1.0i * i_angle)) / base_current,
61-
(1e3 * exp(1.0i * (i_angle + deg_240))) / base_current,
62-
(1e3 * exp(1.0i * (i_angle + deg_120))) / base_current};
63-
auto const i_asym_local = ComplexValue<asymmetric_t>{(1e3 * exp(1.0i * i_angle)) / base_current,
64-
(1e3 * exp(1.0i * i_angle)) / base_current,
65-
(1e3 * exp(1.0i * i_angle)) / base_current};
66-
67-
CurrentSensor<symmetric_t> const sym_current_sensor{sym_current_sensor_input, u_rated};
68-
6975
CurrentSensorCalcParam<symmetric_t> sym_sensor_param = sym_current_sensor.calc_param<symmetric_t>();
70-
CurrentSensorCalcParam<asymmetric_t> asym_sensor_param = sym_current_sensor.calc_param<asymmetric_t>();
71-
7276
CurrentSensorOutput<symmetric_t> const sym_sensor_output =
7377
(angle_measurement_type == AngleMeasurementType::global_angle)
7478
? sym_current_sensor.get_output<symmetric_t>(i_sym, ComplexValue<symmetric_t>{1.0})
7579
: sym_current_sensor.get_output<symmetric_t>(conj(i_sym), ComplexValue<symmetric_t>{1.0});
76-
CurrentSensorOutput<asymmetric_t> const sym_sensor_output_asym_param =
77-
(angle_measurement_type == AngleMeasurementType::global_angle)
78-
? sym_current_sensor.get_output<asymmetric_t>(i_asym, ComplexValue<asymmetric_t>{1.0})
79-
: sym_current_sensor.get_output<asymmetric_t>(conj(i_asym_local),
80-
ComplexValue<asymmetric_t>{1.0});
8180

8281
// Check symmetric sensor output for symmetric parameters
8382
CHECK(sym_sensor_param.angle_measurement_type == angle_measurement_type);
84-
8583
// Var(I_Re) ≈ Var(I) * cos^2(pi/4) + Var(θ) * I^2 * sin^2(pi/4)
8684
CHECK(sym_sensor_param.measurement.real_component.variance ==
8785
doctest::Approx(0.5 * (i_variance_pu + i_angle_variance_pu * i_pu * i_pu)));
@@ -95,8 +93,25 @@ TEST_CASE("Test current sensor") {
9593
CHECK(sym_sensor_output.energized == 1);
9694
CHECK(sym_sensor_output.i_residual == doctest::Approx(0.0));
9795
CHECK(sym_sensor_output.i_angle_residual == doctest::Approx(0.0));
96+
}
97+
98+
SUBCASE("Output for asymmetric parameters") {
99+
auto const i_asym = ComplexValue<asymmetric_t>{(1e3 * exp(1.0i * i_angle)) / base_current,
100+
(1e3 * exp(1.0i * (i_angle + deg_240))) / base_current,
101+
(1e3 * exp(1.0i * (i_angle + deg_120))) / base_current};
102+
auto const i_asym_local = ComplexValue<asymmetric_t>{(1e3 * exp(1.0i * i_angle)) / base_current,
103+
(1e3 * exp(1.0i * i_angle)) / base_current,
104+
(1e3 * exp(1.0i * i_angle)) / base_current};
105+
CurrentSensorCalcParam<asymmetric_t> asym_sensor_param = sym_current_sensor.calc_param<asymmetric_t>();
106+
CurrentSensorOutput<asymmetric_t> const sym_sensor_output_asym_param =
107+
(angle_measurement_type == AngleMeasurementType::global_angle)
108+
? sym_current_sensor.get_output<asymmetric_t>(i_asym, ComplexValue<asymmetric_t>{1.0})
109+
: sym_current_sensor.get_output<asymmetric_t>(conj(i_asym_local),
110+
ComplexValue<asymmetric_t>{1.0});
98111

99112
// Check symmetric sensor output for asymmetric parameters
113+
CHECK(asym_sensor_param.angle_measurement_type == angle_measurement_type);
114+
100115
CHECK(asym_sensor_param.measurement.real_component.variance[0] ==
101116
doctest::Approx(0.5 * (i_variance_pu + i_angle_variance_pu * i_pu * i_pu)));
102117
auto const shifted_i_angle = i_angle + deg_240;
@@ -113,8 +128,6 @@ TEST_CASE("Test current sensor") {
113128
CHECK(sym_sensor_output_asym_param.i_residual[phase] == doctest::Approx(0.0));
114129
CHECK(sym_sensor_output_asym_param.i_angle_residual[phase] == doctest::Approx(0.0));
115130
}
116-
CHECK(sym_current_sensor.get_terminal_type() == terminal_type);
117-
CHECK(sym_current_sensor.get_angle_measurement_type() == angle_measurement_type);
118131
}
119132
}
120133
SUBCASE("Wrong measured terminal type") {
@@ -135,71 +148,52 @@ TEST_CASE("Test current sensor") {
135148
SUBCASE("Symmetric calculation parameters") {
136149
double const u_rated = 10.0e3;
137150
double const base_current = base_power_3p / u_rated / sqrt3;
138-
for (auto const terminal_type :
139-
{MeasuredTerminalType::branch_from, MeasuredTerminalType::branch_to, MeasuredTerminalType::branch3_1,
140-
MeasuredTerminalType::branch3_2, MeasuredTerminalType::branch3_3}) {
141-
for (auto const angle_measurement_type :
142-
{AngleMeasurementType::global_angle, AngleMeasurementType::local_angle}) {
143-
CurrentSensor<symmetric_t> sym_current_sensor{{.id = 1,
144-
.measured_object = 1,
145-
.measured_terminal_type = terminal_type,
146-
.angle_measurement_type = angle_measurement_type},
147-
u_rated};
148-
149-
SUBCASE("No phase shift") {
150-
sym_current_sensor.update({.id = 1,
151-
.i_sigma = 1.0,
152-
.i_angle_sigma = 0.2,
153-
.i_measured = 1.0,
154-
.i_angle_measured = 0.0});
155-
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
156-
157-
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
158-
CHECK(sym_param.measurement.real_component.variance ==
159-
doctest::Approx(pow(1.0 / base_current, 2)));
160-
CHECK(sym_param.measurement.imag_component.variance ==
161-
doctest::Approx(pow(0.2 / base_current, 2)));
162-
CHECK(real(sym_param.measurement.value()) == doctest::Approx(1.0 / base_current));
163-
CHECK(imag(sym_param.measurement.value()) == doctest::Approx(0.0 / base_current));
164-
}
165-
166-
SUBCASE("90deg phase shift") {
167-
sym_current_sensor.update({.id = 1,
168-
.i_sigma = 1.0,
169-
.i_angle_sigma = 0.2,
170-
.i_measured = 1.0,
171-
.i_angle_measured = pi / 2});
172-
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
173-
174-
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
175-
CHECK(sym_param.measurement.real_component.variance ==
176-
doctest::Approx(pow(0.2 / base_current, 2)));
177-
CHECK(sym_param.measurement.imag_component.variance ==
178-
doctest::Approx(pow(1.0 / base_current, 2)));
179-
CHECK(real(sym_param.measurement.value()) == doctest::Approx(0.0 / base_current));
180-
CHECK(imag(sym_param.measurement.value()) == doctest::Approx(1.0 / base_current));
181-
}
182-
183-
SUBCASE("45deg phase shift") {
184-
using std::numbers::sqrt2;
185-
constexpr auto inv_sqrt2 = sqrt2 / 2;
186-
187-
sym_current_sensor.update({.id = 1,
188-
.i_sigma = 1.0,
189-
.i_angle_sigma = 0.2,
190-
.i_measured = 1.0,
191-
.i_angle_measured = pi / 4});
192-
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
193-
194-
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
195-
CHECK(sym_param.measurement.real_component.variance ==
196-
doctest::Approx(1.04 / 2.0 / (base_current * base_current)));
197-
CHECK(sym_param.measurement.imag_component.variance ==
198-
doctest::Approx(sym_param.measurement.real_component.variance));
199-
CHECK(real(sym_param.measurement.value()) == doctest::Approx(inv_sqrt2 / base_current));
200-
CHECK(imag(sym_param.measurement.value()) ==
201-
doctest::Approx(real(sym_param.measurement.value())));
202-
}
151+
for (auto const [terminal_type, angle_measurement_type] : terminal_and_angle_measurement_types) {
152+
CurrentSensor<symmetric_t> sym_current_sensor{{.id = 1,
153+
.measured_object = 1,
154+
.measured_terminal_type = terminal_type,
155+
.angle_measurement_type = angle_measurement_type},
156+
u_rated};
157+
158+
SUBCASE("No phase shift") {
159+
sym_current_sensor.update(
160+
{.id = 1, .i_sigma = 1.0, .i_angle_sigma = 0.2, .i_measured = 1.0, .i_angle_measured = 0.0});
161+
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
162+
163+
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
164+
CHECK(sym_param.measurement.real_component.variance == doctest::Approx(pow(1.0 / base_current, 2)));
165+
CHECK(sym_param.measurement.imag_component.variance == doctest::Approx(pow(0.2 / base_current, 2)));
166+
CHECK(real(sym_param.measurement.value()) == doctest::Approx(1.0 / base_current));
167+
CHECK(imag(sym_param.measurement.value()) == doctest::Approx(0.0 / base_current));
168+
}
169+
170+
SUBCASE("90deg phase shift") {
171+
sym_current_sensor.update(
172+
{.id = 1, .i_sigma = 1.0, .i_angle_sigma = 0.2, .i_measured = 1.0, .i_angle_measured = pi / 2});
173+
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
174+
175+
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
176+
CHECK(sym_param.measurement.real_component.variance == doctest::Approx(pow(0.2 / base_current, 2)));
177+
CHECK(sym_param.measurement.imag_component.variance == doctest::Approx(pow(1.0 / base_current, 2)));
178+
CHECK(real(sym_param.measurement.value()) == doctest::Approx(0.0 / base_current));
179+
CHECK(imag(sym_param.measurement.value()) == doctest::Approx(1.0 / base_current));
180+
}
181+
182+
SUBCASE("45deg phase shift") {
183+
using std::numbers::sqrt2;
184+
constexpr auto inv_sqrt2 = sqrt2 / 2;
185+
186+
sym_current_sensor.update(
187+
{.id = 1, .i_sigma = 1.0, .i_angle_sigma = 0.2, .i_measured = 1.0, .i_angle_measured = pi / 4});
188+
auto const sym_param = sym_current_sensor.calc_param<symmetric_t>();
189+
190+
CHECK(sym_param.angle_measurement_type == angle_measurement_type);
191+
CHECK(sym_param.measurement.real_component.variance ==
192+
doctest::Approx(1.04 / 2.0 / (base_current * base_current)));
193+
CHECK(sym_param.measurement.imag_component.variance ==
194+
doctest::Approx(sym_param.measurement.real_component.variance));
195+
CHECK(real(sym_param.measurement.value()) == doctest::Approx(inv_sqrt2 / base_current));
196+
CHECK(imag(sym_param.measurement.value()) == doctest::Approx(real(sym_param.measurement.value())));
203197
}
204198
}
205199
}
@@ -219,10 +213,10 @@ TEST_CASE("Test current sensor") {
219213
.i_measured = i_measured,
220214
.i_angle_measured = i_angle_measured},
221215
u_rated};
222-
223216
CurrentSensorUpdate<symmetric_t> cs_update{
224217
.id = 1, .i_sigma = nan, .i_angle_sigma = nan, .i_measured = nan, .i_angle_measured = nan};
225218
auto expected = cs_update;
219+
CAPTURE(expected.id);
226220

227221
SUBCASE("Identical") {
228222
// default values

0 commit comments

Comments
 (0)