Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Measurement statistics module #896

Draft
wants to merge 14 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "common/common.hpp"
#include "common/enum.hpp"
#include "common/grouped_index_vector.hpp"
#include "common/statistics.hpp"
#include "common/three_phase_tensor.hpp"

namespace power_grid_model {
Expand Down Expand Up @@ -78,21 +79,10 @@ template <symmetry_tag sym_type> struct ApplianceShortCircuitSolverOutput {
ComplexValue<sym> i{};
};

// Complex measured value of a sensor in p.u. with a uniform variance across all phases and axes of the complex plane
// (circularly symmetric)
template <symmetry_tag sym_type> struct UniformComplexRandomVariable {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

ComplexValue<sym> value{};
double variance{}; // variance (sigma^2) of the error range, in p.u.
};

// voltage sensor calculation parameters for state estimation
// The value is the complex voltage
// If the imaginary part is NaN, it means the angle calculation is not correct
template <symmetry_tag sym> using VoltageSensorCalcParam = UniformComplexRandomVariable<sym>;
template <symmetry_tag sym> using VoltageSensorCalcParam = UniformComplexRDV<sym>;

// power sensor calculation parameters for state estimation
// The value is the complex power
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-FileCopyrightText: Contributors to the Power Grid Model project <[email protected]>
//
// SPDX-License-Identifier: MPL-2.0

#pragma once

#include "common.hpp"
#include "three_phase_tensor.hpp"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this one again ...


/**
* @file statistics.hpp
* @brief This file contains various structures and functions for handling statistical representations of
* randomly distributed variables(RDV) used in the Power Grid Model, like in the State Estimation algorithms to
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

randomly distributed variable is quite a strange expression. For this specific context, 'random variable' is accurate and comcise enough.

Suggested change
* randomly distributed variables(RDV) used in the Power Grid Model, like in the State Estimation algorithms to
* random variables (RandVar) used in the Power Grid Model, like in the State Estimation algorithms to

or

Suggested change
* randomly distributed variables(RDV) used in the Power Grid Model, like in the State Estimation algorithms to
* random variables (RV) used in the Power Grid Model, like in the State Estimation algorithms to

* handle measurements.
*
* The structures provided in this file are used to represent measured values of sensors
* with different types of variances. These structures support both symmetric and asymmetric representations and
* provide conversion operators to transform between these representations.
*
* A Randomly distributed variable in PGM can have following characteristics:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* A Randomly distributed variable in PGM can have following characteristics:
* A random variable in PGM can have following characteristics:

* - Uniform: Single Variance for all phases
* - Independent: Unique Variance for each phase
* - Real: The Real value without direction, eg. real axis: RealValue (* 1), imaginary axis: RealValue (* 1i).
* - Complex: A combined complex value in `a + bi` notation.
Comment on lines +21 to +24
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* - Uniform: Single Variance for all phases
* - Independent: Unique Variance for each phase
* - Real: The Real value without direction, eg. real axis: RealValue (* 1), imaginary axis: RealValue (* 1i).
* - Complex: A combined complex value in `a + bi` notation.
* - Unified: total variance for all phases
* - Independent: all phases are independent from each other
* - Scalar: a scalar value `RealValue`, eg. real axis: RealValue (* 1), imaginary axis: RealValue (* i).
* - Complex: a complex value with real and imaginary parts.

*
* Based on these, we use combine variables in Polar/Decomposed forms:
* - Decomposed: Treat RDV individually as in cartesian co-ordinates with a separate variance for both real and
* complex component.
* - Polar: RDV is in polar co-ordinates, with magnitude and angle.
Comment on lines +26 to +29
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part is a bit hard to flow from the above, perhaps some inbetween liaison?

Suggested change
* Based on these, we use combine variables in Polar/Decomposed forms:
* - Decomposed: Treat RDV individually as in cartesian co-ordinates with a separate variance for both real and
* complex component.
* - Polar: RDV is in polar co-ordinates, with magnitude and angle.
* [liaison]
* Based on these, we use combined variables in Decomposed/Polar forms:
* - Decomposed: treat random variables individually as in cartesian co-ordinates with separated variances for both real and
* imaginary part.
* - Polar: random variables are in polar co-ordinates, with magnitudes and angles.

*
*/

namespace power_grid_model {
template <symmetry_tag sym_type> struct UniformRealRDV {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

RealValue<sym> value{};
double variance{}; // variance (sigma^2) of the error range, in p.u.

explicit operator UniformRealRDV<asymmetric_t>() const
requires(is_symmetric_v<sym>)
{
return {.value = RealValue<asymmetric_t>{std::piecewise_construct, value}, .variance = variance};
}
explicit operator UniformRealRDV<symmetric_t>() const
requires(is_asymmetric_v<sym>)
{
return {.value = mean_val(value), .variance = variance / 3.0};
}
Comment on lines +42 to +51
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the division by 3 enough? If I convert one sym rand var to asym rand var and back, would I still get the same result?

};

template <symmetry_tag sym_type> struct IndependentRealRDV {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

RealValue<sym> value{};
RealValue<sym> variance{}; // variance (sigma^2) of the error range, in p.u.

explicit operator UniformRealRDV<symmetric_t>() const {
constexpr auto scale = is_asymmetric_v<sym> ? 3.0 : 1.0;
return {.value = mean_val(value), .variance = mean_val(variance) / scale};
}
explicit operator UniformRealRDV<asymmetric_t>() const { return {.value = value, .variance = mean_val(variance)}; }
explicit operator IndependentRealRDV<asymmetric_t>() const
requires(is_symmetric_v<sym>)
{
return {.value = RealValue<asymmetric_t>{std::piecewise_construct, value},
.variance = RealValue<asymmetric_t>{std::piecewise_construct, variance}};
}
explicit operator IndependentRealRDV<symmetric_t>() const
requires(is_asymmetric_v<sym>)
{
return {.value = mean_val(value), .variance = mean_val(variance) / 3.0};
}
};

// Complex measured value of a sensor in p.u. with a uniform variance across all phases and axes of the complex plane
// (rotationally symmetric)
template <symmetry_tag sym_type> struct UniformComplexRDV {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
template <symmetry_tag sym_type> struct UniformComplexRDV {
template <symmetry_tag sym_type> struct UnifiedComplexRandVar {

using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

ComplexValue<sym> value{};
double variance{}; // variance (sigma^2) of the error range, in p.u.
};

inline UniformComplexRDV<symmetric_t> pos_seq(UniformComplexRDV<asymmetric_t> const& var) {
return {.value = pos_seq(var.value), .variance = var.variance / 3.0};
}
inline UniformComplexRDV<asymmetric_t> three_phase(UniformComplexRDV<symmetric_t> const& var) {
return {.value = ComplexValue<asymmetric_t>{var.value}, .variance = var.variance};
}

// Complex measured value of a sensor in p.u. with separate variances per phase (but rotationally symmetric in the
// complex plane)
template <symmetry_tag sym_type> struct IndependentComplexRDV {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

ComplexValue<sym> value{};
RealValue<sym> variance{}; // variance (sigma^2) of the error range, in p.u.

explicit operator UniformComplexRDV<sym>() const {
return UniformComplexRDV<sym>{.value = value, .variance = sum_val(variance)};
}
Comment on lines +108 to +110
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

here and elsewhere: please double-check whether additional conversion operators are required

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added tests without checking implementations. Also it would be nice to now add additional conversion operators if there is a need for it during implementation. The base for the operators are ready and available in this PR.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so do you want me to review as is? i would be reviewing my own code though 😬

};

// Complex measured value of a sensor in p.u. modeled as separate real and imaginary components with independent
// variances (rotationally symmetric)
template <symmetry_tag sym_type> struct DecomposedComplexRDV {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

IndependentRealRDV<sym> real_component;
IndependentRealRDV<sym> imag_component;

ComplexValue<sym> value() const { return {real_component.value, imag_component.value}; }

explicit operator UniformComplexRDV<sym>() const {
return static_cast<UniformComplexRDV<sym>>(static_cast<IndependentComplexRDV<sym>>(*this));
}
explicit operator IndependentComplexRDV<sym>() const {
return IndependentComplexRDV<sym>{.value = value(),
.variance = real_component.variance + imag_component.variance};
}
};

// Complex measured value of a sensor in p.u. in polar coordinates (magnitude and angle)
// (rotationally symmetric)
template <symmetry_tag sym_type> struct PolarComplexRDV {
using sym = sym_type;

static constexpr bool symmetric{is_symmetric_v<sym>};

UniformRealRDV<sym> magnitude;
UniformRealRDV<sym> angle;

ComplexValue<sym> value() const { return magnitude.value * exp(1.0i * angle.value); }

explicit operator UniformComplexRDV<sym>() const {
return static_cast<UniformComplexRDV<sym>>(static_cast<IndependentComplexRDV<sym>>(*this));
}
explicit operator IndependentComplexRDV<sym>() const {
return IndependentComplexRDV<sym>{
.value = value(), .variance = magnitude.variance + magnitude.value * magnitude.value * angle.variance};
}
explicit operator DecomposedComplexRDV<sym>() const {
auto const cos_theta = cos(angle.value);
auto const sin_theta = sin(angle.value);
auto const real_component = magnitude.value * cos_theta;
auto const imag_component = magnitude.value * sin_theta;
return DecomposedComplexRDV<sym>{
.real_component = {.value = real_component,
.variance = magnitude.variance * cos_theta * cos_theta +
imag_component * imag_component * angle.variance},
.imag_component = {.value = imag_component,
.variance = magnitude.variance * sin_theta * sin_theta +
real_component * real_component * angle.variance}};
}
Comment on lines +172 to +179
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we add the exact equations in, especially here, to make it easier to follow?

};
} // namespace power_grid_model
1 change: 1 addition & 0 deletions tests/cpp_unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ set(PROJECT_SOURCES
"test_component_output.cpp"
"test_component_update.cpp"
"test_three_phase_tensor.cpp"
"test_statistics.cpp"
"test_node.cpp"
"test_line.cpp"
"test_generic_branch.cpp"
Expand Down
Loading
Loading