@@ -33,26 +33,36 @@ TEST_CASE("Test current sensor") {
33
33
{MeasuredTerminalType::branch_from, MeasuredTerminalType::branch_to, MeasuredTerminalType::branch3_1,
34
34
MeasuredTerminalType::branch3_2, MeasuredTerminalType::branch3_3}) {
35
35
CAPTURE (terminal_type);
36
+ // for (auto const angle_measurement_type : {AngleMeasurementType::global_angle,
37
+ // AngleMeasurementType::local_angle}) {
38
+ // }
39
+ auto const angle_measurement_type = AngleMeasurementType::global_angle;
40
+ CAPTURE (angle_measurement_type);
36
41
37
42
CurrentSensorInput<symmetric_t > sym_current_sensor_input{};
38
43
sym_current_sensor_input.id = 0 ;
39
44
sym_current_sensor_input.measured_object = 1 ;
40
45
sym_current_sensor_input.measured_terminal_type = terminal_type;
41
- sym_current_sensor_input.angle_measurement_type = AngleMeasurementType::local_angle ;
46
+ sym_current_sensor_input.angle_measurement_type = angle_measurement_type ;
42
47
sym_current_sensor_input.i_sigma = 1.0 ;
43
48
sym_current_sensor_input.i_measured = 1.0 * 1e3 ;
44
- sym_current_sensor_input.i_angle_measured = 0.0 ;
49
+ sym_current_sensor_input.i_angle_measured = pi / 4 . ;
45
50
sym_current_sensor_input.i_angle_sigma = 0.2 ;
46
51
47
52
double const u_rated = 10.0e3 ;
48
53
double const base_current = base_power_3p / u_rated / sqrt3;
49
54
double const i_pu = 1.0e3 / base_current;
50
55
double const i_sigma_pu = 1.0 / base_current;
51
- double const i_variance_pu = pow (i_sigma_pu, 2 );
52
- double const i_angle_variance_pu = pow (0.2 , 2 );
56
+ double const i_variance_pu = i_sigma_pu * i_sigma_pu;
57
+ double const i_angle = pi / 4 .;
58
+ double const i_angle_sigma_pi = 0.2 ;
59
+ double const i_angle_variance_pu = i_angle_sigma_pi * i_angle_sigma_pi;
53
60
54
- ComplexValue<symmetric_t > const i_sym = (1.0 * 1e3 + 1i * 0.0 ) / base_current;
55
- ComplexValue<asymmetric_t > const i_asym = i_sym * RealValue<asymmetric_t >{1.0 };
61
+ auto const i_sym = ComplexValue<symmetric_t >{(1e3 * cos (i_angle) + 1i * 1e3 * sin (i_angle)) / base_current};
62
+ auto const i_asym = ComplexValue<asymmetric_t >{
63
+ (1e3 * cos (i_angle) + 1i * 1e3 * sin (i_angle)) / base_current,
64
+ (1e3 * cos (i_angle + deg_240) + 1i * 1e3 * sin (i_angle + deg_240)) / base_current,
65
+ (1e3 * cos (i_angle + deg_120) + 1i * 1e3 * sin (i_angle + deg_120)) / base_current};
56
66
57
67
CurrentSensor<symmetric_t > const sym_current_sensor{sym_current_sensor_input, u_rated};
58
68
@@ -65,60 +75,73 @@ TEST_CASE("Test current sensor") {
65
75
sym_current_sensor.get_output <asymmetric_t >(i_asym);
66
76
67
77
// Check symmetric sensor output for symmetric parameters
68
- CHECK (sym_sensor_param.angle_measurement_type == AngleMeasurementType::local_angle);
69
- CHECK (sym_sensor_param.measurement .real_component .variance == doctest::Approx (i_variance_pu));
78
+ if constexpr (angle_measurement_type == AngleMeasurementType::global_angle) {
79
+ CHECK (sym_sensor_param.angle_measurement_type == AngleMeasurementType::global_angle);
80
+ } else {
81
+ CHECK (sym_sensor_param.angle_measurement_type == AngleMeasurementType::local_angle);
82
+ }
83
+ // Var(I_Re) ≈ Var(I) * cos^2(pi/4) + Var(θ) * I^2 * sin^2(pi/4)
84
+ CHECK (sym_sensor_param.measurement .real_component .variance ==
85
+ doctest::Approx (0.5 * (i_variance_pu + i_angle_variance_pu * i_pu * i_pu)));
86
+ // Var(I_Im) ≈ Var(I) * sin^2(pi/4) + Var(θ) * I^2 * cos^2(pi/4)
70
87
CHECK (sym_sensor_param.measurement .imag_component .variance ==
71
- doctest::Approx (i_angle_variance_pu * i_pu * i_pu));
72
- CHECK (real (sym_sensor_param.measurement .value ()) == doctest::Approx (i_pu));
73
- CHECK (imag (sym_sensor_param.measurement .value ()) == doctest::Approx (0.0 ));
88
+ doctest::Approx (0.5 * (i_variance_pu + i_angle_variance_pu * i_pu * i_pu) ));
89
+ CHECK (real (sym_sensor_param.measurement .value ()) == doctest::Approx (i_pu * cos (i_angle) ));
90
+ CHECK (imag (sym_sensor_param.measurement .value ()) == doctest::Approx (i_pu * sin (i_angle) ));
74
91
75
92
CHECK (sym_sensor_output.id == 0 );
76
93
CHECK (sym_sensor_output.energized == 1 );
77
94
CHECK (sym_sensor_output.i_residual == doctest::Approx (0.0 ));
78
95
CHECK (sym_sensor_output.i_angle_residual == doctest::Approx (0.0 ));
79
96
80
97
// Check symmetric sensor output for asymmetric parameters
81
- CHECK (asym_sensor_param.measurement .real_component .variance [0 ] == doctest::Approx (i_variance_pu));
98
+ CHECK (asym_sensor_param.measurement .real_component .variance [0 ] ==
99
+ doctest::Approx (0.5 * (i_variance_pu + i_angle_variance_pu * i_pu * i_pu)));
100
+ auto const shifted_i_angle = i_angle + deg_240;
82
101
CHECK (asym_sensor_param.measurement .imag_component .variance [1 ] ==
83
- doctest::Approx (i_variance_pu * sin (deg_240 ) * sin (deg_240 ) +
84
- i_angle_variance_pu * i_pu * i_pu * cos (deg_240 ) * cos (deg_240 )));
85
- CHECK (real (asym_sensor_param.measurement .value ()[0 ]) == doctest::Approx (i_pu));
86
- CHECK (imag (asym_sensor_param.measurement .value ()[1 ]) == doctest::Approx (i_pu * sin (deg_240 )));
102
+ doctest::Approx (i_variance_pu * sin (shifted_i_angle ) * sin (shifted_i_angle ) +
103
+ i_angle_variance_pu * i_pu * i_pu * cos (shifted_i_angle ) * cos (shifted_i_angle )));
104
+ CHECK (real (asym_sensor_param.measurement .value ()[0 ]) == doctest::Approx (i_pu * cos (i_angle) ));
105
+ CHECK (imag (asym_sensor_param.measurement .value ()[1 ]) == doctest::Approx (i_pu * sin (shifted_i_angle )));
87
106
88
107
CHECK (sym_sensor_output_asym_param.id == 0 );
89
108
CHECK (sym_sensor_output_asym_param.energized == 1 );
90
- CHECK (sym_sensor_output_asym_param.i_residual [0 ] == doctest::Approx (0.0 ));
91
- CHECK (sym_sensor_output_asym_param.i_angle_residual [1 ] == doctest::Approx (0.0 ));
109
+ for (auto i = 0 ; i < 3 ; ++i) {
110
+ CHECK (sym_sensor_output_asym_param.i_residual [i] == doctest::Approx (0.0 ));
111
+ CHECK (sym_sensor_output_asym_param.i_angle_residual [i] == doctest::Approx (0.0 ));
112
+ }
92
113
93
114
CHECK (sym_current_sensor.get_terminal_type () == terminal_type);
94
115
95
- CHECK (sym_current_sensor.get_angle_measurement_type () == AngleMeasurementType::local_angle );
116
+ CHECK (sym_current_sensor.get_angle_measurement_type () == AngleMeasurementType::global_angle );
96
117
}
97
118
SUBCASE (" Wrong measured terminal type" ) {
98
119
for (auto const terminal_type :
99
120
{MeasuredTerminalType::source, MeasuredTerminalType::shunt, MeasuredTerminalType::load,
100
121
MeasuredTerminalType::generator, MeasuredTerminalType::node}) {
101
- CHECK_THROWS_AS ((CurrentSensor<symmetric_t >{
102
- {1 , 1 , terminal_type, AngleMeasurementType::local_angle, 1.0 , 1.0 , 1.0 , 1.0 }, 1.0 }),
103
- InvalidMeasuredTerminalType);
122
+ CHECK_THROWS_AS (
123
+ (CurrentSensor<symmetric_t >{
124
+ {1 , 1 , terminal_type, AngleMeasurementType::global_angle, 1.0 , 1.0 , 1.0 , 1.0 }, 1.0 }),
125
+ InvalidMeasuredTerminalType);
104
126
}
105
127
}
106
128
SUBCASE (" Symmetric calculation parameters" ) {
107
129
double const u_rated = 10.0e3 ;
108
130
double const base_current = base_power_3p / u_rated / sqrt3;
109
131
110
- CurrentSensor<symmetric_t > sym_current_sensor{{.id = 1 ,
111
- .measured_object = 1 ,
112
- .measured_terminal_type = MeasuredTerminalType::branch3_1,
113
- .angle_measurement_type = AngleMeasurementType::local_angle},
114
- u_rated};
132
+ CurrentSensor<symmetric_t > sym_current_sensor{
133
+ {.id = 1 ,
134
+ .measured_object = 1 ,
135
+ .measured_terminal_type = MeasuredTerminalType::branch3_1,
136
+ .angle_measurement_type = AngleMeasurementType::global_angle},
137
+ u_rated};
115
138
116
139
SUBCASE (" No phase shift" ) {
117
140
sym_current_sensor.update (
118
141
{.id = 1 , .i_sigma = 1.0 , .i_angle_sigma = 0.2 , .i_measured = 1.0 , .i_angle_measured = 0.0 });
119
142
auto const sym_param = sym_current_sensor.calc_param <symmetric_t >();
120
143
121
- CHECK (sym_param.angle_measurement_type == AngleMeasurementType::local_angle );
144
+ CHECK (sym_param.angle_measurement_type == AngleMeasurementType::global_angle );
122
145
CHECK (sym_param.measurement .real_component .variance == doctest::Approx (pow (1.0 / base_current, 2 )));
123
146
CHECK (sym_param.measurement .imag_component .variance == doctest::Approx (pow (0.2 / base_current, 2 )));
124
147
CHECK (real (sym_param.measurement .value ()) == doctest::Approx (1.0 / base_current));
@@ -130,7 +153,7 @@ TEST_CASE("Test current sensor") {
130
153
{.id = 1 , .i_sigma = 1.0 , .i_angle_sigma = 0.2 , .i_measured = 1.0 , .i_angle_measured = pi / 2 });
131
154
auto const sym_param = sym_current_sensor.calc_param <symmetric_t >();
132
155
133
- CHECK (sym_param.angle_measurement_type == AngleMeasurementType::local_angle );
156
+ CHECK (sym_param.angle_measurement_type == AngleMeasurementType::global_angle );
134
157
CHECK (sym_param.measurement .real_component .variance == doctest::Approx (pow (0.2 / base_current, 2 )));
135
158
CHECK (sym_param.measurement .imag_component .variance == doctest::Approx (pow (1.0 / base_current, 2 )));
136
159
CHECK (real (sym_param.measurement .value ()) == doctest::Approx (0.0 / base_current));
@@ -145,7 +168,7 @@ TEST_CASE("Test current sensor") {
145
168
{.id = 1 , .i_sigma = 1.0 , .i_angle_sigma = 0.2 , .i_measured = 1.0 , .i_angle_measured = pi / 4 });
146
169
auto const sym_param = sym_current_sensor.calc_param <symmetric_t >();
147
170
148
- CHECK (sym_param.angle_measurement_type == AngleMeasurementType::local_angle );
171
+ CHECK (sym_param.angle_measurement_type == AngleMeasurementType::global_angle );
149
172
CHECK (sym_param.measurement .real_component .variance ==
150
173
doctest::Approx (1.04 / 2.0 / (base_current * base_current)));
151
174
CHECK (sym_param.measurement .imag_component .variance ==
@@ -164,7 +187,7 @@ TEST_CASE("Test current sensor") {
164
187
CurrentSensor<symmetric_t > const current_sensor{{.id = 1 ,
165
188
.measured_object = 1 ,
166
189
.measured_terminal_type = MeasuredTerminalType::branch3_1,
167
- .angle_measurement_type = AngleMeasurementType::local_angle ,
190
+ .angle_measurement_type = AngleMeasurementType::global_angle ,
168
191
.i_sigma = i_sigma,
169
192
.i_angle_sigma = i_angle_sigma,
170
193
.i_measured = i_measured,
@@ -289,7 +312,7 @@ TEST_CASE("Test current sensor") {
289
312
CurrentSensor<asymmetric_t > const current_sensor{{.id = 1 ,
290
313
.measured_object = 1 ,
291
314
.measured_terminal_type = measured_terminal_type,
292
- .angle_measurement_type = AngleMeasurementType::local_angle ,
315
+ .angle_measurement_type = AngleMeasurementType::global_angle ,
293
316
.i_sigma = i_sigma,
294
317
.i_angle_sigma = i_angle_sigma,
295
318
.i_measured = i_measured,
0 commit comments