123 lines
4.1 KiB
Python
123 lines
4.1 KiB
Python
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
|