Ejemplo n.º 1
0
def ieee1159_voltage(mauka_message: protobuf.mauka_pb2.MaukaMessage,
                     rms_features: np.ndarray,
                     opq_mongo_client: mongo.OpqMongoClient = None):
    """
    Calculate the ieee1159 voltage incidents and add them to the mongo database
    """
    incidents, cycle_offsets = classify_ieee1159_voltage(rms_features)

    for idx, incident in enumerate(incidents):
        start_idx = cycle_offsets[idx][0]
        end_idx = cycle_offsets[idx][1]
        deviations = np.abs(
            rms_features[start_idx:end_idx]) - constants.NOMINAL_VRMS
        # The absolute value of the rms_features here and elsewhere is unecessary provided the rms has been applied
        max_deviation = np.amax(deviations)
        max_deviation_neg = np.amax(-deviations)
        if max_deviation < max_deviation_neg:
            max_deviation = -max_deviation_neg

        mongo.store_incident(
            mauka_message.payload.event_id, mauka_message.payload.box_id,
            mauka_message.payload.start_timestamp_ms +
            analysis.c_to_ms(start_idx),
            mauka_message.payload.start_timestamp_ms +
            analysis.c_to_ms(end_idx), mongo.IncidentMeasurementType.VOLTAGE,
            max_deviation, [incident], [], {}, opq_mongo_client)
Ejemplo n.º 2
0
 def test_itic_region_prohibited(self):
     """
     All test results should return a prohibited ITIC region. First we'll test a few that are clearly prohibited
     and then we will probe around the edge of the prohibited region to test edge cases.
     """
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(300), 500))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(600), 3))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(140), 20))
     self.assertEqual(
         IticRegion.PROHIBITED,
         itic_region(percent_nominal_to_rms(500), analysis.c_to_ms(.02)))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(200), 1))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(140), 3))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(121), 3))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(120), 500))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(110), 501))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(110), 501))
     self.assertEqual(IticRegion.PROHIBITED,
                      itic_region(percent_nominal_to_rms(110), 1000000))
     self.assertEqual(
         IticRegion.PROHIBITED,
         itic_region(percent_nominal_to_rms(10000), analysis.c_to_ms(.02)))
Ejemplo n.º 3
0
def itic(mauka_message: protobuf.mauka_pb2.MaukaMessage,
         segment_threshold: float,
         logger=None,
         opq_mongo_client: mongo.OpqMongoClient = None):
    """
    Computes the ITIC region for a given waveform.
    :param mauka_message:
    :param segment_threshold: Threshold for segmentation
    :param logger: Optional logger to use to print information
    :param opq_mongo_client:  Optional DB client to re-use (otherwise new one will be created)
    :return: ITIC region.
    """
    mongo_client = mongo.get_default_client(opq_mongo_client)
    if len(mauka_message.payload.data) < 0.01:
        return

    segments = analysis.segment(mauka_message.payload.data, segment_threshold)

    if logger is not None:
        logger.debug("Calculating ITIC with {} segments.".format(
            len(segments)))

    for segment in segments:
        start_idx = segment[0]
        end_idx = segment[1] + 1
        subarray = mauka_message.payload.data[start_idx:end_idx]
        mean_rms = numpy.mean(subarray)

        itic_enum = itic_region(mean_rms, analysis.c_to_ms(len(subarray)))

        if itic_enum == IticRegion.NO_INTERRUPTION:
            continue
        else:
            incident_start_timestamp_ms = mauka_message.payload.start_timestamp_ms + analysis.c_to_ms(
                start_idx)
            incident_end_timestamp_ms = mauka_message.payload.start_timestamp_ms + analysis.c_to_ms(
                end_idx)
            if itic_enum is IticRegion.PROHIBITED:
                incident_classification = mongo.IncidentClassification.ITIC_PROHIBITED
            else:
                incident_classification = mongo.IncidentClassification.ITIC_NO_DAMAGE

            mongo.store_incident(mauka_message.event_id, mauka_message.box_id,
                                 incident_start_timestamp_ms,
                                 incident_end_timestamp_ms,
                                 mongo.IncidentMeasurementType.VOLTAGE,
                                 mean_rms - 120.0, [incident_classification],
                                 [], {}, mongo_client)
            if logger is not None:
                logger.debug(
                    "Found ITIC incident [{}] from event {} and box {}".format(
                        itic_enum, mauka_message.event_id,
                        mauka_message.box_id))
Ejemplo n.º 4
0
def itic_region(rms_voltage: float, duration_ms: float) -> IticRegion:
    """
    Returns the ITIC region of a given RMS voltage and duration.
    The reference curve is at http://www.keysight.com/upload/cmc_upload/All/1.pdf
    :param rms_voltage: The RMS voltage value
    :param duration_ms: The duration of the voltage event in milliseconds
    :return: The appropriate ITIC region enum
    """
    percent_nominal = (rms_voltage / 120.0) * 100.0

    # First, let's check the extreme edge cases. This can save us some time computing
    # point in polygon if we can identify an extreme edge case first.
    if duration_ms < analysis.c_to_ms(0.01):
        return IticRegion.NO_INTERRUPTION

    if rms_voltage <= 0:
        if duration_ms <= 20:
            return IticRegion.NO_INTERRUPTION

        return IticRegion.NO_DAMAGE

    # In the x and y directions
    if duration_ms >= 10000 and percent_nominal >= 500:
        return IticRegion.PROHIBITED

    # In the x-direction
    if duration_ms >= 10000:
        if percent_nominal >= 110:
            return IticRegion.PROHIBITED
        elif percent_nominal <= 90:
            return IticRegion.NO_DAMAGE

        return IticRegion.NO_INTERRUPTION

    # In the y-direction
    if percent_nominal >= 500:
        if duration_ms <= HUNDREDTH_OF_A_CYCLE:
            return IticRegion.NO_INTERRUPTION

        return IticRegion.PROHIBITED

    # If the voltage is not an extreme case, we run point in polygon calculations to determine which region its in
    if point_in_polygon(duration_ms, percent_nominal,
                        NO_INTERRUPTION_REGION_POLYGON):
        return IticRegion.NO_INTERRUPTION

    if point_in_polygon(duration_ms, percent_nominal,
                        PROHIBITED_REGION_POLYGON):
        return IticRegion.PROHIBITED

    if point_in_polygon(duration_ms, percent_nominal,
                        NO_DAMAGE_REGION_POLYGON):
        return IticRegion.NO_DAMAGE

    # If it's directly on the line of one of the polygons, its easiest to just say no_interruption
    return IticRegion.NO_INTERRUPTION
Ejemplo n.º 5
0
 def test_itic_region_very_short_duration(self):
     """
     Any duration less than 0.01 cycles are short enough that they should
     always return no interruption irrelevant of the voltage.
     """
     short_duration = analysis.c_to_ms(0.009)
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(120), short_duration))
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(400), short_duration))
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(4000), short_duration))
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(0), short_duration))
Ejemplo n.º 6
0
def get_ieee_duration(duration_ms: float) -> IncidentIeeeDuration:
    """
    Given a duration in milliseconds, return the corresponding IEEE duration classification.
    :param duration_ms: Duration in milliseconds.
    :return: IEEE duration classification.
    """
    ms_half_c = analysis.c_to_ms(0.5)
    ms_30_c = analysis.c_to_ms(30)
    ms_3_s = 3_000
    ms_1_m = 60_000

    if ms_half_c < duration_ms <= ms_30_c:
        return IncidentIeeeDuration.INSTANTANEOUS
    elif ms_30_c < duration_ms <= ms_3_s:
        return IncidentIeeeDuration.MOMENTARY
    elif ms_3_s < duration_ms <= ms_1_m:
        return IncidentIeeeDuration.TEMPORARY
    elif duration_ms > ms_1_m:
        return IncidentIeeeDuration.SUSTAINED

    return IncidentIeeeDuration.UNDEFINED
Ejemplo n.º 7
0
 def test_itic_region_no_interruption(self):
     """
     All test results should return a no interruption ITIC region. First we'll test a few that are clearly
     no damage and then we will probe around the edge of the no damage region to test edge cases.
     """
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(100), 0))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(100), 1))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(100), 10000))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(100), 1000000))
     self.assertEqual(
         IticRegion.NO_INTERRUPTION,
         itic_region(percent_nominal_to_rms(500), analysis.c_to_ms(0.01)))
     self.assertEqual(
         IticRegion.NO_INTERRUPTION,
         itic_region(percent_nominal_to_rms(1000), analysis.c_to_ms(0.01)))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(0, analysis.c_to_ms(0.01)))
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(0, 20))
     self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(0, 20))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(200), .9))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(140), 2.9))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(120), 2.9))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(110), 0.5))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(90), 9999))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(80), 499))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(70), 19))
     self.assertEqual(IticRegion.NO_INTERRUPTION,
                      itic_region(percent_nominal_to_rms(40), 19))
Ejemplo n.º 8
0
    def test_on_line(self):
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(500), analysis.c_to_ms(0.01)))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(1_000_000), analysis.c_to_ms(0.01)))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(200), 1))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(140), 3))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(120), 3))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(120), 500))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(110), 500))

        # self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(110), 800))

        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(0), 20))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(40), 20))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(70), 20))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(70), 500))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(80), 500))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(80), 10_000))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(90), 10_000))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(90), 100_000))
        self.assertEqual(IticRegion.NO_INTERRUPTION, itic_region(percent_nominal_to_rms(90), 1_000_000))
Ejemplo n.º 9
0
import plugins.base_plugin
import protobuf.mauka_pb2
import protobuf.util


class IticRegion(enum.Enum):
    """
    Enumerations of ITIC regions.
    """
    NO_INTERRUPTION = "NO_INTERRUPTION"
    PROHIBITED = "PROHIBITED"
    NO_DAMAGE = "NO_DAMAGE"
    OTHER = "OTHER"


HUNDREDTH_OF_A_CYCLE = analysis.c_to_ms(0.01)
"""Hundredth of a power cycle in milliseconds"""

PROHIBITED_REGION_POLYGON = [[HUNDREDTH_OF_A_CYCLE, 500], [1, 200], [3, 140],
                             [3, 120], [20, 120], [500, 120], [500, 110],
                             [10000, 110], [10000, 500],
                             [HUNDREDTH_OF_A_CYCLE, 500]]
"""Polygon representing the prohibited region"""

NO_DAMAGE_REGION_POLYGON = [[20, 0], [20, 40], [20, 70], [500, 70], [500, 80],
                            [10000, 80], [10000, 90], [10000, 0], [20, 0]]
"""Polygon representing the no damage region"""

NO_INTERRUPTION_REGION_POLYGON = [[0, 0], [0, 500],
                                  [HUNDREDTH_OF_A_CYCLE, 500], [1, 200],
                                  [3, 140], [3, 120], [20, 120], [500, 120],
Ejemplo n.º 10
0
def itic(mauka_message: protobuf.mauka_pb2.MaukaMessage,
         segment_threshold: float,
         itic_plugin: typing.Optional['IticPlugin'] = None,
         opq_mongo_client: typing.Optional[mongo.OpqMongoClient] = None) -> typing.List[int]:
    """
    Computes the ITIC region for a given waveform.
    :param itic_plugin: An instance of this plugin.
    :param mauka_message: A mauka message.
    :param segment_threshold: Threshold for segmentation
    :param opq_mongo_client:  Optional DB client to re-use (otherwise new one will be created)
    :return: ITIC region.
    """
    mongo_client = mongo.get_default_client(opq_mongo_client)
    if len(mauka_message.payload.data) < 0.01:
        maybe_debug(itic_plugin, "Bad payload data length: %d" % len(mauka_message.payload.data))

    maybe_debug(itic_plugin, "Preparing to get segments for %d Vrms values" % len(mauka_message.payload.data))
    # segments = analysis.segment(mauka_message.payload.data, segment_threshold)
    try:
        segments = analysis.segment_array(numpy.array(list(mauka_message.payload.data)))
    except Exception as exception:
        itic_plugin.logger.error("Error segmenting data for ITIC plugin: %s", str(exception))
        segments = []

    if len(segments) == 0:
        maybe_debug(itic_plugin, "No segments found. Ignoring")
        return []

    maybe_debug(itic_plugin, "Calculating ITIC with {} segments.".format(len(segments)))

    incident_ids = []
    for i, segment in enumerate(segments):
        try:
            segment_len = analysis.c_to_ms(len(segment))
            start_t = analysis.c_to_ms(sum([len(segments[x]) for x in range(0, i)]))
            end_t = start_t + segment_len
            mean_rms = segment.mean()
            maybe_debug(itic_plugin, "start=%f end=%f mean=%f" % (start_t, end_t, mean_rms))

            itic_enum = itic_region(mean_rms, segment_len)

            if itic_enum == IticRegion.NO_INTERRUPTION:
                maybe_debug(itic_plugin, "NO_INTERRUPTION")
                continue
            else:
                incident_start_timestamp_ms = mauka_message.payload.start_timestamp_ms + start_t
                incident_end_timestamp_ms = mauka_message.payload.start_timestamp_ms + end_t
                if itic_enum is IticRegion.PROHIBITED:
                    maybe_debug(itic_plugin, "PROHIBITED")
                    incident_classification = mongo.IncidentClassification.ITIC_PROHIBITED
                else:
                    maybe_debug(itic_plugin, "NO_DAMAGE")
                    incident_classification = mongo.IncidentClassification.ITIC_NO_DAMAGE

                incident_id = mongo.store_incident(
                    itic_plugin.request_next_available_incident_id(),
                    mauka_message.payload.event_id,
                    mauka_message.payload.box_id,
                    incident_start_timestamp_ms,
                    incident_end_timestamp_ms,
                    mongo.IncidentMeasurementType.VOLTAGE,
                    mean_rms - 120.0,
                    [incident_classification],
                    [],
                    {},
                    mongo_client)

                maybe_debug(itic_plugin, "Stored incident")

                maybe_debug(itic_plugin,
                            "Found ITIC incident [{}] from event {} and box {}".format(
                                itic_enum,
                                mauka_message.event_id,
                                mauka_message.box_id))

                incident_ids.append(incident_id)
        except Exception as exception:
            itic_plugin.logger.error("Error storing ITIC incident: %s", str(exception))

    return incident_ids