13
13
#include " y_bus.hpp"
14
14
15
15
#include " ../calculation_parameters.hpp"
16
+ #include " ../common/enum.hpp"
17
+ #include " ../common/exception.hpp"
16
18
#include " ../common/three_phase_tensor.hpp"
17
19
#include " ../common/timer.hpp"
18
20
@@ -91,8 +93,9 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
91
93
using sym = sym_type;
92
94
93
95
static constexpr auto is_iterative = true ;
94
- static constexpr auto has_current_sensor_implemented =
95
- false ; // TODO(mgovers): for testing purposes; remove after NRSE has current sensor implemented
96
+ static constexpr auto has_global_current_sensor_implemented =
97
+ false ; // TODO(figueroa1395): for testing purposes; remove after NRSE has global current sensor implemented
98
+ static constexpr auto is_NRSE_solver = true ; // for testing purposes only
96
99
97
100
private:
98
101
enum class Order : IntS { row_major = 0 , column_major = 1 };
@@ -311,15 +314,50 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
311
314
if (measured_values.has_branch_from_power (obj)) {
312
315
auto const ij_voltage_order =
313
316
(type == YBusElementType::bft) ? Order::row_major : Order::column_major;
314
- process_branch_measurement (block, diag_block, rhs_block, y_branch.yff (), y_branch. yft (),
315
- u_state, ij_voltage_order,
316
- measured_values.branch_from_power (obj));
317
+ process_branch_power_measurement (block, diag_block, rhs_block, y_branch.yff (),
318
+ y_branch. yft (), u_state, ij_voltage_order,
319
+ measured_values.branch_from_power (obj));
317
320
}
318
321
if (measured_values.has_branch_to_power (obj)) {
319
322
auto const ij_voltage_order =
320
323
(type == YBusElementType::btf) ? Order::row_major : Order::column_major;
321
- process_branch_measurement (block, diag_block, rhs_block, y_branch.ytt (), y_branch.ytf (),
322
- u_state, ij_voltage_order, measured_values.branch_to_power (obj));
324
+ process_branch_power_measurement (block, diag_block, rhs_block, y_branch.ytt (),
325
+ y_branch.ytf (), u_state, ij_voltage_order,
326
+ measured_values.branch_to_power (obj));
327
+ }
328
+ if (measured_values.has_branch_from_current (obj)) {
329
+ auto const ij_voltage_order =
330
+ (type == YBusElementType::bft) ? Order::row_major : Order::column_major;
331
+ auto const & measurement = measured_values.branch_from_current (obj);
332
+ switch (measurement.angle_measurement_type ) {
333
+ case AngleMeasurementType::local_angle:
334
+ process_branch_local_current_measurement (block, diag_block, rhs_block, y_branch.yff (),
335
+ y_branch.yft (), u_state, ij_voltage_order,
336
+ measurement);
337
+ break ;
338
+ case AngleMeasurementType::global_angle:
339
+ throw SparseMatrixError{};
340
+ default :
341
+ assert (measurement.angle_measurement_type == AngleMeasurementType::local_angle ||
342
+ measurement.angle_measurement_type == AngleMeasurementType::global_angle);
343
+ }
344
+ }
345
+ if (measured_values.has_branch_to_current (obj)) {
346
+ auto const ij_voltage_order =
347
+ (type == YBusElementType::btf) ? Order::row_major : Order::column_major;
348
+ auto const & measurement = measured_values.branch_to_current (obj);
349
+ switch (measurement.angle_measurement_type ) {
350
+ case AngleMeasurementType::local_angle:
351
+ process_branch_local_current_measurement (block, diag_block, rhs_block, y_branch.ytt (),
352
+ y_branch.ytf (), u_state, ij_voltage_order,
353
+ measurement);
354
+ break ;
355
+ case AngleMeasurementType::global_angle:
356
+ throw SparseMatrixError{};
357
+ default :
358
+ assert (measurement.angle_measurement_type == AngleMeasurementType::local_angle ||
359
+ measurement.angle_measurement_type == AngleMeasurementType::global_angle);
360
+ }
323
361
}
324
362
break ;
325
363
}
@@ -412,7 +450,7 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
412
450
multiply_add_jacobian_blocks_rhs (rhs_block, block_F_T_k_w, measured_power, f_x_complex);
413
451
}
414
452
415
- // / @brief Adds contribution of branch measurements to the G(r, r), G(r, c) and eta_r blocks,
453
+ // / @brief Adds contribution of branch power measurements to the G(r, r), G(r, c) and eta_r blocks,
416
454
// / given the iteration passes through (r, c), i.e., row, col
417
455
// /
418
456
// / When iterating via (row, col), have 4 cases regarding branch measurements:
@@ -438,10 +476,11 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
438
476
// / @param y_xi_mu admittance from the branch measurement to other bus
439
477
// / @param u_state Voltage state of iteration voltage state vector
440
478
// / @param order Order enum to determine if (chi, psi) = (row, col) or (col, row)
441
- // / @param measured_power
442
- void process_branch_measurement (NRSEGainBlock<sym>& block, NRSEGainBlock<sym>& diag_block, NRSERhs<sym>& rhs_block,
443
- auto const & y_xi_xi, auto const & y_xi_mu, auto const & u_state, Order const order,
444
- auto const & measured_power) {
479
+ // / @param power_sensor measurement
480
+ void process_branch_power_measurement (NRSEGainBlock<sym>& block, NRSEGainBlock<sym>& diag_block,
481
+ NRSERhs<sym>& rhs_block, auto const & y_xi_xi, auto const & y_xi_mu,
482
+ auto const & u_state, Order const order,
483
+ PowerSensorCalcParam<sym> const & power_sensor) {
445
484
auto const hm_u_chi_u_chi_y_xi_xi = hm_complex_form (y_xi_xi, u_state.u_chi_u_chi_conj (order));
446
485
auto const nl_u_chi_u_chi_y_xi_xi = dot (hm_u_chi_u_chi_y_xi_xi, u_state.abs_u_chi_inv (order));
447
486
@@ -456,22 +495,52 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
456
495
auto const block_rc_or_cr = calculate_jacobian (hm_u_chi_u_psi_y_xi_mu, nl_u_chi_u_psi_y_xi_mu);
457
496
458
497
if (order == Order::row_major) {
459
- multiply_add_branch_blocks (block, diag_block, rhs_block, block_rr_or_cc, block_rc_or_cr, measured_power ,
498
+ multiply_add_branch_blocks (block, diag_block, rhs_block, block_rr_or_cc, block_rc_or_cr, power_sensor ,
460
499
f_x_complex);
461
500
} else {
462
- multiply_add_branch_blocks (block, diag_block, rhs_block, block_rc_or_cr, block_rr_or_cc, measured_power ,
501
+ multiply_add_branch_blocks (block, diag_block, rhs_block, block_rc_or_cr, block_rr_or_cc, power_sensor ,
463
502
f_x_complex);
464
503
}
465
504
}
466
505
506
+ // / @brief Adds contribution of branch current measurements. Logic is similar to powermeasurements, but with an
507
+ // / additional voltage division as per mathematical workout.
508
+ void process_branch_local_current_measurement (NRSEGainBlock<sym>& block, NRSEGainBlock<sym>& diag_block,
509
+ NRSERhs<sym>& rhs_block, auto const & y_xi_xi, auto const & y_xi_mu,
510
+ auto const & u_state, Order const order,
511
+ CurrentSensorCalcParam<sym> const & current_sensor) {
512
+ auto const hm_u_chi_u_chi_y_xi_xi = hm_complex_form (y_xi_xi, u_state.u_chi_u_chi_conj (order));
513
+ auto const hm_hat_u_chi_u_chi_y_xi_xi = dot (hm_u_chi_u_chi_y_xi_xi, u_state.abs_u_chi_inv (order));
514
+ auto const nl_hat_u_chi_u_chi_y_xi_xi = dot (hm_hat_u_chi_u_chi_y_xi_xi, u_state.abs_u_chi_inv (order));
515
+
516
+ auto const hm_u_chi_u_psi_y_xi_mu = hm_complex_form (y_xi_mu, u_state.u_chi_u_psi_conj (order));
517
+ auto const hm_hat_u_chi_u_psi_y_xi_mu = dot (hm_u_chi_u_psi_y_xi_mu, u_state.abs_u_chi_inv (order));
518
+ auto const nl_hat_u_chi_u_psi_y_xi_mu = dot (hm_hat_u_chi_u_psi_y_xi_mu, u_state.abs_u_psi_inv (order));
519
+
520
+ auto const f_x_complex = sum_row (hm_hat_u_chi_u_chi_y_xi_xi + hm_hat_u_chi_u_psi_y_xi_mu);
521
+
522
+ auto block_rr_or_cc = calculate_jacobian (hm_hat_u_chi_u_chi_y_xi_xi, nl_hat_u_chi_u_chi_y_xi_xi);
523
+ block_rr_or_cc.dP_dt += RealTensor<sym>{RealValue<sym>{-imag (f_x_complex)}};
524
+ block_rr_or_cc.dQ_dt += RealTensor<sym>{RealValue<sym>{real (f_x_complex)}};
525
+ auto const block_rc_or_cr = calculate_jacobian (hm_hat_u_chi_u_psi_y_xi_mu, nl_hat_u_chi_u_psi_y_xi_mu);
526
+
527
+ if (order == Order::row_major) {
528
+ multiply_add_branch_blocks (block, diag_block, rhs_block, block_rr_or_cc, block_rc_or_cr,
529
+ current_sensor.measurement , f_x_complex);
530
+ } else {
531
+ multiply_add_branch_blocks (block, diag_block, rhs_block, block_rc_or_cr, block_rr_or_cc,
532
+ current_sensor.measurement , f_x_complex);
533
+ }
534
+ }
535
+
467
536
void multiply_add_branch_blocks (NRSEGainBlock<sym>& block, NRSEGainBlock<sym>& diag_block, NRSERhs<sym>& rhs_block,
468
- auto & left_block, auto const & right_block, auto const & measured_power,
469
- auto const & f_x_complex) {
470
- auto const & block_F_T_k_w = transpose_multiply_weight (left_block, measured_power );
537
+ auto & left_block, auto const & right_block,
538
+ DecomposedComplexRandVar<sym> const & measured_flow, auto const & f_x_complex) {
539
+ auto const & block_F_T_k_w = transpose_multiply_weight (left_block, measured_flow );
471
540
472
541
multiply_add_jacobian_blocks_lhs (diag_block, block_F_T_k_w, left_block);
473
542
multiply_add_jacobian_blocks_lhs (block, block_F_T_k_w, right_block);
474
- multiply_add_jacobian_blocks_rhs (rhs_block, block_F_T_k_w, measured_power , f_x_complex);
543
+ multiply_add_jacobian_blocks_rhs (rhs_block, block_F_T_k_w, measured_flow , f_x_complex);
475
544
}
476
545
477
546
// / @brief Fill Q^T(j,i) of LHS(i, j) from the Q(j, i) of LHS(j, i).
@@ -586,12 +655,12 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
586
655
// / where W_k = [[p_variance, 0], [0, q_variance]]
587
656
// /
588
657
// / @param jac_block F_k(u1, u2, y12)
589
- // / @param power_sensor object with members p_variance and q_variance
658
+ // / @param measured_flow object with members p_variance and q_variance
590
659
// / @return F_k(u1, u2, y12)^T . W
591
660
NRSEJacobian transpose_multiply_weight (NRSEJacobian const & jac_block,
592
- PowerSensorCalcParam <sym> const & power_sensor ) {
593
- auto const w_p = diagonal_inverse (power_sensor .real_component .variance );
594
- auto const w_q = diagonal_inverse (power_sensor .imag_component .variance );
661
+ DecomposedComplexRandVar <sym> const & measured_flow ) {
662
+ auto const w_p = diagonal_inverse (measured_flow .real_component .variance );
663
+ auto const w_q = diagonal_inverse (measured_flow .imag_component .variance );
595
664
596
665
NRSEJacobian product{};
597
666
product.dP_dt = dot (w_p, jac_block.dP_dt );
@@ -620,12 +689,12 @@ template <symmetry_tag sym_type> class NewtonRaphsonSESolver {
620
689
// /
621
690
// / @param rhs_block RHS(row)
622
691
// / @param f_T_k_w F_{k,1}^T . w_k
623
- // / @param power_sensor measurement
692
+ // / @param measured_flow power or current sensor measurement
624
693
// / @param f_x_complex calculated power
625
694
static void multiply_add_jacobian_blocks_rhs (NRSERhs<sym>& rhs_block, NRSEJacobian const & f_T_k_w,
626
- PowerSensorCalcParam <sym> const & power_sensor ,
695
+ DecomposedComplexRandVar <sym> const & measured_flow ,
627
696
ComplexValue<sym> const & f_x_complex) {
628
- ComplexValue<sym> const delta_power = power_sensor .value () - f_x_complex;
697
+ ComplexValue<sym> const delta_power = measured_flow .value () - f_x_complex;
629
698
rhs_block.eta_theta () += dot (f_T_k_w.dP_dt , real (delta_power)) + dot (f_T_k_w.dP_dv , imag (delta_power));
630
699
rhs_block.eta_v () += dot (f_T_k_w.dQ_dt , real (delta_power)) + dot (f_T_k_w.dQ_dv , imag (delta_power));
631
700
}
0 commit comments