gaitsetpy.features.harup_features

HAR-UP Feature Extractor. Maintainer: @aharshit123456

This file contains the HAR-UP feature extractor class that inherits from BaseFeatureExtractor. It implements the feature extraction methods used in the HAR-UP project.

Reference:

  1'''
  2HAR-UP Feature Extractor.
  3Maintainer: @aharshit123456
  4
  5This file contains the HAR-UP feature extractor class that inherits from BaseFeatureExtractor.
  6It implements the feature extraction methods used in the HAR-UP project.
  7
  8Reference:
  9- Website: https://sites.google.com/up.edu.mx/har-up/
 10- GitHub: https://github.com/jpnm561/HAR-UP
 11'''
 12
 13import numpy as np
 14from typing import List, Dict, Any
 15from scipy.stats import kurtosis, skew
 16from scipy.fftpack import rfft
 17from ..core.base_classes import BaseFeatureExtractor
 18
 19
 20class HARUPFeatureExtractor(BaseFeatureExtractor):
 21    """
 22    HAR-UP feature extractor class.
 23    
 24    This class implements the feature extraction methods used in the HAR-UP project.
 25    It extracts both time-domain and frequency-domain features from sensor data.
 26    """
 27    
 28    def __init__(self, verbose: bool = False):
 29        """
 30        Initialize the HAR-UP feature extractor.
 31        
 32        Args:
 33            verbose: Whether to print progress information
 34        """
 35        super().__init__(
 36            name="harup",
 37            description="HAR-UP Feature Extractor - Extracts features used in the HAR-UP project"
 38        )
 39        self.config = {
 40            'time_domain': True,
 41            'frequency_domain': True,
 42            'verbose': verbose
 43        }
 44        
 45        # Define the features to extract
 46        self.time_domain_features = [
 47            'mean', 'std', 'rms', 'max_amp', 'min_amp', 'median',
 48            'zero_crossings', 'skewness', 'kurtosis', 'q1', 'q3', 'autocorr'
 49        ]
 50        
 51        self.freq_domain_features = [
 52            'energy'
 53        ]
 54    
 55    def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]:
 56        """
 57        Extract features from sliding windows.
 58        
 59        Args:
 60            windows: List of sliding window dictionaries
 61            fs: Sampling frequency
 62            **kwargs: Additional arguments for feature extraction
 63            
 64        Returns:
 65            List of feature dictionaries
 66        """
 67        # Update config with kwargs
 68        self.config.update(kwargs)
 69        
 70        all_features = []
 71        
 72        # Skip label and activity_id windows
 73        sensor_windows = [w for w in windows if w["name"] not in ["labels", "activity_id"]]
 74        
 75        if self.config['verbose']:
 76            print(f"Extracting features from {len(sensor_windows)} sensor windows")
 77        
 78        # Process each sensor window
 79        for window in sensor_windows:
 80            sensor_name = window["name"]
 81            sensor_data = window["data"]
 82            
 83            if self.config['verbose']:
 84                print(f"Processing {sensor_name} with {len(sensor_data)} windows")
 85            
 86            # For each window of this sensor
 87            for i, window_data in enumerate(sensor_data):
 88                features = {}
 89                features["sensor"] = sensor_name
 90                
 91                # Time domain features
 92                if self.config['time_domain']:
 93                    self._extract_time_domain_features(window_data, features)
 94                
 95                # Frequency domain features
 96                if self.config['frequency_domain']:
 97                    self._extract_freq_domain_features(window_data, features)
 98                
 99                all_features.append(features)
100        
101        return all_features
102    
103    def _extract_time_domain_features(self, window_data: np.ndarray, features: Dict[str, Any]):
104        """
105        Extract time domain features from a window.
106        
107        Args:
108            window_data: Window data
109            features: Dictionary to store the extracted features
110        """
111        # Basic statistical features
112        features["mean"] = np.mean(window_data)
113        features["std"] = np.std(window_data)
114        features["rms"] = np.sqrt(np.mean(window_data**2))
115        features["max_amp"] = np.max(np.abs(window_data))
116        features["min_amp"] = np.min(np.abs(window_data))
117        features["median"] = np.median(window_data)
118        
119        # Zero crossings
120        zero_crossings = np.where(np.diff(np.signbit(window_data)))[0]
121        features["zero_crossings"] = len(zero_crossings)
122        
123        # Higher-order statistics
124        features["skewness"] = skew(window_data)
125        features["kurtosis"] = kurtosis(window_data)
126        
127        # Quartiles
128        features["q1"] = np.percentile(window_data, 25)
129        features["q3"] = np.percentile(window_data, 75)
130        
131        # Autocorrelation
132        autocorr = np.correlate(window_data, window_data, mode='full')
133        features["autocorr"] = np.median(autocorr)
134    
135    def _extract_freq_domain_features(self, window_data: np.ndarray, features: Dict[str, Any]):
136        """
137        Extract frequency domain features from a window.
138        
139        Args:
140            window_data: Window data
141            features: Dictionary to store the extracted features
142        """
143        # FFT
144        fft_values = abs(rfft(np.asarray(window_data)))
145        
146        # Energy
147        features["energy"] = np.sum(fft_values**2)
148    
149    def get_feature_names(self) -> List[str]:
150        """
151        Get names of features extracted by this extractor.
152        
153        Returns:
154            List of feature names
155        """
156        feature_names = []
157        
158        if self.config['time_domain']:
159            feature_names.extend(self.time_domain_features)
160        
161        if self.config['frequency_domain']:
162            feature_names.extend(self.freq_domain_features)
163        
164        return feature_names
165
166
167# Legacy function wrapper for backward compatibility
168def extract_harup_features(windows: List[Dict], fs: int = 100, 
169                         time_domain: bool = True, freq_domain: bool = True, 
170                         verbose: bool = False) -> List[Dict]:
171    """
172    Legacy function for extracting HAR-UP features.
173    
174    Args:
175        windows: List of sliding window dictionaries
176        fs: Sampling frequency (default: 100Hz)
177        time_domain: Whether to extract time domain features
178        freq_domain: Whether to extract frequency domain features
179        verbose: Whether to print progress information
180        
181    Returns:
182        List of feature dictionaries
183    """
184    extractor = HARUPFeatureExtractor(verbose=verbose)
185    return extractor.extract_features(
186        windows, 
187        fs=fs, 
188        time_domain=time_domain, 
189        frequency_domain=freq_domain
190    )
class HARUPFeatureExtractor(gaitsetpy.core.base_classes.BaseFeatureExtractor):
 21class HARUPFeatureExtractor(BaseFeatureExtractor):
 22    """
 23    HAR-UP feature extractor class.
 24    
 25    This class implements the feature extraction methods used in the HAR-UP project.
 26    It extracts both time-domain and frequency-domain features from sensor data.
 27    """
 28    
 29    def __init__(self, verbose: bool = False):
 30        """
 31        Initialize the HAR-UP feature extractor.
 32        
 33        Args:
 34            verbose: Whether to print progress information
 35        """
 36        super().__init__(
 37            name="harup",
 38            description="HAR-UP Feature Extractor - Extracts features used in the HAR-UP project"
 39        )
 40        self.config = {
 41            'time_domain': True,
 42            'frequency_domain': True,
 43            'verbose': verbose
 44        }
 45        
 46        # Define the features to extract
 47        self.time_domain_features = [
 48            'mean', 'std', 'rms', 'max_amp', 'min_amp', 'median',
 49            'zero_crossings', 'skewness', 'kurtosis', 'q1', 'q3', 'autocorr'
 50        ]
 51        
 52        self.freq_domain_features = [
 53            'energy'
 54        ]
 55    
 56    def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]:
 57        """
 58        Extract features from sliding windows.
 59        
 60        Args:
 61            windows: List of sliding window dictionaries
 62            fs: Sampling frequency
 63            **kwargs: Additional arguments for feature extraction
 64            
 65        Returns:
 66            List of feature dictionaries
 67        """
 68        # Update config with kwargs
 69        self.config.update(kwargs)
 70        
 71        all_features = []
 72        
 73        # Skip label and activity_id windows
 74        sensor_windows = [w for w in windows if w["name"] not in ["labels", "activity_id"]]
 75        
 76        if self.config['verbose']:
 77            print(f"Extracting features from {len(sensor_windows)} sensor windows")
 78        
 79        # Process each sensor window
 80        for window in sensor_windows:
 81            sensor_name = window["name"]
 82            sensor_data = window["data"]
 83            
 84            if self.config['verbose']:
 85                print(f"Processing {sensor_name} with {len(sensor_data)} windows")
 86            
 87            # For each window of this sensor
 88            for i, window_data in enumerate(sensor_data):
 89                features = {}
 90                features["sensor"] = sensor_name
 91                
 92                # Time domain features
 93                if self.config['time_domain']:
 94                    self._extract_time_domain_features(window_data, features)
 95                
 96                # Frequency domain features
 97                if self.config['frequency_domain']:
 98                    self._extract_freq_domain_features(window_data, features)
 99                
100                all_features.append(features)
101        
102        return all_features
103    
104    def _extract_time_domain_features(self, window_data: np.ndarray, features: Dict[str, Any]):
105        """
106        Extract time domain features from a window.
107        
108        Args:
109            window_data: Window data
110            features: Dictionary to store the extracted features
111        """
112        # Basic statistical features
113        features["mean"] = np.mean(window_data)
114        features["std"] = np.std(window_data)
115        features["rms"] = np.sqrt(np.mean(window_data**2))
116        features["max_amp"] = np.max(np.abs(window_data))
117        features["min_amp"] = np.min(np.abs(window_data))
118        features["median"] = np.median(window_data)
119        
120        # Zero crossings
121        zero_crossings = np.where(np.diff(np.signbit(window_data)))[0]
122        features["zero_crossings"] = len(zero_crossings)
123        
124        # Higher-order statistics
125        features["skewness"] = skew(window_data)
126        features["kurtosis"] = kurtosis(window_data)
127        
128        # Quartiles
129        features["q1"] = np.percentile(window_data, 25)
130        features["q3"] = np.percentile(window_data, 75)
131        
132        # Autocorrelation
133        autocorr = np.correlate(window_data, window_data, mode='full')
134        features["autocorr"] = np.median(autocorr)
135    
136    def _extract_freq_domain_features(self, window_data: np.ndarray, features: Dict[str, Any]):
137        """
138        Extract frequency domain features from a window.
139        
140        Args:
141            window_data: Window data
142            features: Dictionary to store the extracted features
143        """
144        # FFT
145        fft_values = abs(rfft(np.asarray(window_data)))
146        
147        # Energy
148        features["energy"] = np.sum(fft_values**2)
149    
150    def get_feature_names(self) -> List[str]:
151        """
152        Get names of features extracted by this extractor.
153        
154        Returns:
155            List of feature names
156        """
157        feature_names = []
158        
159        if self.config['time_domain']:
160            feature_names.extend(self.time_domain_features)
161        
162        if self.config['frequency_domain']:
163            feature_names.extend(self.freq_domain_features)
164        
165        return feature_names

HAR-UP feature extractor class.

This class implements the feature extraction methods used in the HAR-UP project. It extracts both time-domain and frequency-domain features from sensor data.

HARUPFeatureExtractor(verbose: bool = False)
29    def __init__(self, verbose: bool = False):
30        """
31        Initialize the HAR-UP feature extractor.
32        
33        Args:
34            verbose: Whether to print progress information
35        """
36        super().__init__(
37            name="harup",
38            description="HAR-UP Feature Extractor - Extracts features used in the HAR-UP project"
39        )
40        self.config = {
41            'time_domain': True,
42            'frequency_domain': True,
43            'verbose': verbose
44        }
45        
46        # Define the features to extract
47        self.time_domain_features = [
48            'mean', 'std', 'rms', 'max_amp', 'min_amp', 'median',
49            'zero_crossings', 'skewness', 'kurtosis', 'q1', 'q3', 'autocorr'
50        ]
51        
52        self.freq_domain_features = [
53            'energy'
54        ]

Initialize the HAR-UP feature extractor.

Args: verbose: Whether to print progress information

config
time_domain_features
freq_domain_features
def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]:
 56    def extract_features(self, windows: List[Dict], fs: int, **kwargs) -> List[Dict]:
 57        """
 58        Extract features from sliding windows.
 59        
 60        Args:
 61            windows: List of sliding window dictionaries
 62            fs: Sampling frequency
 63            **kwargs: Additional arguments for feature extraction
 64            
 65        Returns:
 66            List of feature dictionaries
 67        """
 68        # Update config with kwargs
 69        self.config.update(kwargs)
 70        
 71        all_features = []
 72        
 73        # Skip label and activity_id windows
 74        sensor_windows = [w for w in windows if w["name"] not in ["labels", "activity_id"]]
 75        
 76        if self.config['verbose']:
 77            print(f"Extracting features from {len(sensor_windows)} sensor windows")
 78        
 79        # Process each sensor window
 80        for window in sensor_windows:
 81            sensor_name = window["name"]
 82            sensor_data = window["data"]
 83            
 84            if self.config['verbose']:
 85                print(f"Processing {sensor_name} with {len(sensor_data)} windows")
 86            
 87            # For each window of this sensor
 88            for i, window_data in enumerate(sensor_data):
 89                features = {}
 90                features["sensor"] = sensor_name
 91                
 92                # Time domain features
 93                if self.config['time_domain']:
 94                    self._extract_time_domain_features(window_data, features)
 95                
 96                # Frequency domain features
 97                if self.config['frequency_domain']:
 98                    self._extract_freq_domain_features(window_data, features)
 99                
100                all_features.append(features)
101        
102        return all_features

Extract features from sliding windows.

Args: windows: List of sliding window dictionaries fs: Sampling frequency **kwargs: Additional arguments for feature extraction

Returns: List of feature dictionaries

def get_feature_names(self) -> List[str]:
150    def get_feature_names(self) -> List[str]:
151        """
152        Get names of features extracted by this extractor.
153        
154        Returns:
155            List of feature names
156        """
157        feature_names = []
158        
159        if self.config['time_domain']:
160            feature_names.extend(self.time_domain_features)
161        
162        if self.config['frequency_domain']:
163            feature_names.extend(self.freq_domain_features)
164        
165        return feature_names

Get names of features extracted by this extractor.

Returns: List of feature names

def extract_harup_features( windows: List[Dict], fs: int = 100, time_domain: bool = True, freq_domain: bool = True, verbose: bool = False) -> List[Dict]:
169def extract_harup_features(windows: List[Dict], fs: int = 100, 
170                         time_domain: bool = True, freq_domain: bool = True, 
171                         verbose: bool = False) -> List[Dict]:
172    """
173    Legacy function for extracting HAR-UP features.
174    
175    Args:
176        windows: List of sliding window dictionaries
177        fs: Sampling frequency (default: 100Hz)
178        time_domain: Whether to extract time domain features
179        freq_domain: Whether to extract frequency domain features
180        verbose: Whether to print progress information
181        
182    Returns:
183        List of feature dictionaries
184    """
185    extractor = HARUPFeatureExtractor(verbose=verbose)
186    return extractor.extract_features(
187        windows, 
188        fs=fs, 
189        time_domain=time_domain, 
190        frequency_domain=freq_domain
191    )

Legacy function for extracting HAR-UP features.

Args: windows: List of sliding window dictionaries fs: Sampling frequency (default: 100Hz) time_domain: Whether to extract time domain features freq_domain: Whether to extract frequency domain features verbose: Whether to print progress information

Returns: List of feature dictionaries