ria-toolkit-oss/src/ria_toolkit_oss/signal/block_generator/block.py

123 lines
4.1 KiB
Python
Raw Normal View History

M
2025-12-11 11:13:27 -05:00
import json
from abc import ABC, abstractmethod
import numpy as np
from ria_toolkit_oss.signal.block_generator.data_types import DataType
class Block(ABC):
"""
Abstract base class for signal processing blocks.
This class defines the interface for all signal processing blocks,
including input and output data types and the call method for processing.
"""
@property
@abstractmethod
def input_type(self) -> DataType:
"""
Get the input data type for the block.
:return: The input data type.
:rtype: DataType
"""
pass
@property
@abstractmethod
def output_type(self) -> DataType:
"""
Get the output data type for the block.
:return: The output data type.
:rtype: DataType
"""
pass
@abstractmethod
def get_samples(self, num_samples) -> np.ndarray:
"""
Process the input data and produce output.
:param args: Positional arguments for the processing method.
:param kwargs: Keyword arguments for the processing method.
:return: The processed output data.
:rtype: numpy array
"""
pass
def _get_metadata(self):
metadata = {}
for key, value in vars(self).items():
try:
# Try to serialize the value to check if it's JSON serializable
json.dumps(value)
metadata[f"BlockGenerator:{self.__class__.__name__}:{key}"] = value
except (TypeError, ValueError):
# If the value is not JSON serializable, skip it
continue
for block in self.input:
metadata = self._combine_dicts_and_handle_double_keys(block._get_metadata(), metadata)
return metadata
# TODO improve this
def _combine_dicts_and_handle_double_keys(self, source_dict, other_dict):
for key, value in source_dict.items():
# Find the last colon in the key
last_colon_index = key.rfind(":")
# Ensure there's at least one colon in the key
if last_colon_index == -1:
# If no colon, just append "(1)"
new_key = f"{key}(1)"
else:
# Extract the prefix and the part after the last colon
prefix = key[:last_colon_index]
suffix = key[last_colon_index + 1 :]
# Check if the suffix has a number inside parentheses
if suffix.startswith("(") and suffix.endswith(")") and suffix[1:-1].isdigit():
# Extract the number inside the parentheses and increment it
number = int(suffix[1:-1]) + 1
new_key = f"{prefix}({number})"
else:
# No number at the end, so just append "(1)"
new_key = f"{key}(1)"
# Ensure the new key is unique in both dictionaries
while new_key in other_dict:
# Find the last parentheses to extract the current number
last_paren_index = new_key.rfind(")")
prefix = new_key[:last_paren_index]
suffix = new_key[last_paren_index + 1 :]
# Extract the number in parentheses and increment it
if suffix.startswith("(") and suffix.endswith(")") and suffix[1:-1].isdigit():
number = int(suffix[1:-1]) + 1
else:
number = 1 # Default to 1 if no number in parentheses
# Create the new key with the incremented number
new_key = f"{prefix}({number})"
# Update the other dictionary with the new key
other_dict[new_key] = value
return other_dict
@abstractmethod
def __call__(self, *args, **kwargs) -> np.ndarray:
"""
Process the input data and produce output.
:param args: Positional arguments for the processing method.
:param kwargs: Keyword arguments for the processing method.
:return: The processed output data.
:rtype: numpy array
"""
pass