| """ |
| domain/interfaces/services/signal_processor.py |
| ββββββββββββββββββββββββββββββββββββββββββββββββ |
| SignalProcessor β abstract contract for PPG signal preprocessing. |
| |
| Implements the **Template Method** pattern: |
| ``process()`` defines the fixed pipeline (filter β normalize β segment) |
| while ``filter_signal()``, ``normalize()``, and ``segment()`` are abstract |
| and overridden by concrete implementations (e.g. ScipySignalProcessor). |
| """ |
| from __future__ import annotations |
|
|
| from abc import ABC, abstractmethod |
|
|
| import numpy as np |
|
|
|
|
| class SignalProcessor(ABC): |
| """ |
| PPG signal preprocessing contract. |
| |
| Pipeline (Template Method): |
| raw signal β filter_signal() β normalize() β segment() β segments array |
| """ |
|
|
| |
|
|
| @abstractmethod |
| def filter_signal( |
| self, |
| signal: np.ndarray, |
| sampling_rate: float, |
| ) -> np.ndarray: |
| """ |
| Apply a bandpass filter to remove noise and baseline wander. |
| |
| Args: |
| signal: 1-D array of raw PPG amplitude values. |
| sampling_rate: Sampling rate of the signal in Hz. |
| |
| Returns: |
| Filtered signal as a 1-D NumPy array of the same shape. |
| """ |
| ... |
|
|
| @abstractmethod |
| def normalize(self, signal: np.ndarray) -> np.ndarray: |
| """ |
| Normalise the signal to a standard scale. |
| |
| Args: |
| signal: 1-D filtered PPG signal. |
| |
| Returns: |
| Normalised signal (e.g. Z-score: mean=0, std=1). |
| """ |
| ... |
|
|
| @abstractmethod |
| def segment( |
| self, |
| signal: np.ndarray, |
| sampling_rate: float, |
| ) -> np.ndarray: |
| """ |
| Split the signal into fixed-length windows. |
| |
| Args: |
| signal: 1-D normalised PPG signal. |
| sampling_rate: Sampling rate in Hz. |
| |
| Returns: |
| 2-D NumPy array of shape ``(n_segments, window_size)``. |
| """ |
| ... |
|
|
| |
|
|
| def process( |
| self, |
| raw_signal: list[float], |
| sampling_rate: float, |
| ) -> np.ndarray: |
| """ |
| Execute the full preprocessing pipeline. |
| |
| Steps: |
| 1. Convert list β NumPy array |
| 2. filter_signal() |
| 3. normalize() |
| 4. segment() |
| |
| Args: |
| raw_signal: Raw PPG values from a PPGSignal entity. |
| sampling_rate: Sampling rate of the recording in Hz. |
| |
| Returns: |
| 2-D NumPy array of shape ``(n_segments, window_size)`` |
| ready for model inference. |
| """ |
| arr = np.asarray(raw_signal, dtype=np.float64) |
| filtered = self.filter_signal(arr, sampling_rate) |
| normalised = self.normalize(filtered) |
| segments = self.segment(normalised, sampling_rate) |
| return segments |
|
|