gaitsetpy.eda.statistics

This module contains functions for statistical analysis of sensor data.

Maintainer: @aharshit123456

  1'''
  2This module contains functions for statistical analysis of sensor data.
  3
  4Maintainer: @aharshit123456
  5'''
  6
  7import matplotlib.pyplot as plt
  8import numpy as np
  9
 10def plot_sensor_with_features(sliding_windows, features, start_idx, end_idx, sensor_name="shank", num_windows=10, save=False):
 11    """
 12    @brief Plots sliding windows of a sensor's time series data with overlaid statistical features.
 13
 14    This function plots the first `num_windows` sliding windows within the given `start_idx` and `end_idx`
 15    for a specified sensor and overlays feature values at their corresponding time indices. 
 16    It also displays entropy and dominant frequency in a separate plot.
 17
 18    @param[in] sliding_windows List of dictionaries, where each dictionary contains:
 19                   - 'name': sensor name (str)
 20                   - 'data': List of time-series windows (each as a Pandas Series)
 21    @param[in] features List of dictionaries, where each dictionary contains:
 22                   - 'name': sensor name (str)
 23                   - 'features': Dictionary of extracted feature lists
 24    @param[in] start_idx Start index of the time window to be plotted.
 25    @param[in] end_idx End index of the time window to be plotted.
 26    @param[in] sensor_name Name of the sensor to be plotted (default: "shank").
 27    @param[in] num_windows Number of sliding windows to plot (default: 10).
 28    @param[in] save If True, saves the plot to a file instead of displaying it.
 29
 30    @return None
 31    """
 32
 33    fig, axes = plt.subplots(2, 1, figsize=(20, 10), gridspec_kw={'height_ratios': [3, 1]})
 34    
 35    # Extract sensor windows
 36    sensor_windows = next((sw['data'] for sw in sliding_windows if sw['name'] == sensor_name), None)
 37    if sensor_windows is None:
 38        print(f"Sensor '{sensor_name}' not found in sliding_windows.")
 39        return
 40
 41    # Extract corresponding features
 42    sensor_features = next((feat['features'] for feat in features if feat['name'] == sensor_name), None)
 43    if sensor_features is None:
 44        print(f"Sensor '{sensor_name}' not found in features.")
 45        return
 46
 47    # Filter windows based on start_idx and end_idx
 48    filtered_windows = [series for series in sensor_windows if start_idx <= series.index[0] and series.index[-1] <= end_idx]
 49    
 50    if not filtered_windows:
 51        print(f"No windows found in the specified index range ({start_idx} - {end_idx}).")
 52        return
 53
 54    # Store entropy & frequency features for separate plotting
 55    entropy_values = []
 56    dominant_frequencies = []
 57
 58    # Plot first `num_windows` windows
 59    for i in range(min(num_windows, len(filtered_windows))):
 60        series = filtered_windows[i]  # Each window is a Pandas Series
 61
 62        # Extract time and signal values
 63        time_values = series.index.to_numpy()  # Time is the index
 64        signal_values = series.values  # Sensor readings
 65
 66        # Determine actual start and end indices for this window
 67        window_start, window_end = time_values[0], time_values[-1]
 68
 69        # Plot time series data
 70        axes[0].plot(time_values, signal_values, alpha=0.6)
 71
 72        # Mark start and end of each window with vertical dotted lines
 73        axes[0].axvline(x=window_start, color='black', linestyle='dotted', alpha=0.7)
 74        axes[0].axvline(x=window_end, color='black', linestyle='dotted', alpha=0.7)
 75
 76        # Overlay statistical features
 77        for feature, marker in zip(['mean', 'rms', 'peak_height', 'mode', 'median'], ['x', 'o', 'v', '<', '^']):
 78            if feature in sensor_features and len(sensor_features[feature]) > i:
 79                feature_value = sensor_features[feature][i]
 80                if feature_value != 0:  # Skip zero values
 81                    closest_index = np.argmin(np.abs(signal_values - feature_value))
 82                    closest_time = time_values[closest_index]
 83                    axes[0].scatter(closest_time, feature_value, color='red', marker=marker, s=100)
 84
 85        # Store entropy & frequency features for separate plotting
 86        if 'entropy' in sensor_features and len(sensor_features['entropy']) > i:
 87            entropy_values.append(sensor_features['entropy'][i])
 88        if 'dominant_frequency' in sensor_features and len(sensor_features['dominant_frequency']) > i:
 89            dominant_frequencies.append(sensor_features['dominant_frequency'][i])
 90
 91    # Labels and title for time-series plot
 92    axes[0].set_xlabel('Time')
 93    axes[0].set_ylabel(f'{sensor_name} Signal')
 94    axes[0].set_title(f'First {num_windows} windows of {sensor_name} in range {start_idx}-{end_idx} with Features')
 95
 96    # Frequency-domain & entropy plot (axes[1])
 97    if dominant_frequencies:
 98        window_indices = list(range(len(dominant_frequencies)))
 99        axes[1].plot(window_indices, dominant_frequencies, label="Dominant Frequency", marker="o", linestyle="dashed", color="blue")
100    
101    if entropy_values:
102        axes[1].bar(window_indices, entropy_values, alpha=0.6, label="Entropy", color="green")
103
104    axes[1].set_xlabel("Window Index")
105    axes[1].set_ylabel("Feature Value")
106    axes[1].set_title("Frequency & Entropy Features")
107    axes[1].legend()
108
109    plt.tight_layout()
110
111    # Save or show plot
112    if save:
113        file_path = input("Enter the file path to save the plot (e.g., 'plot.png'): ")
114        plt.savefig(file_path, dpi=300)
115        print(f"Plot saved at {file_path}")
116    else:
117        plt.show()
def plot_sensor_with_features( sliding_windows, features, start_idx, end_idx, sensor_name='shank', num_windows=10, save=False):
 11def plot_sensor_with_features(sliding_windows, features, start_idx, end_idx, sensor_name="shank", num_windows=10, save=False):
 12    """
 13    @brief Plots sliding windows of a sensor's time series data with overlaid statistical features.
 14
 15    This function plots the first `num_windows` sliding windows within the given `start_idx` and `end_idx`
 16    for a specified sensor and overlays feature values at their corresponding time indices. 
 17    It also displays entropy and dominant frequency in a separate plot.
 18
 19    @param[in] sliding_windows List of dictionaries, where each dictionary contains:
 20                   - 'name': sensor name (str)
 21                   - 'data': List of time-series windows (each as a Pandas Series)
 22    @param[in] features List of dictionaries, where each dictionary contains:
 23                   - 'name': sensor name (str)
 24                   - 'features': Dictionary of extracted feature lists
 25    @param[in] start_idx Start index of the time window to be plotted.
 26    @param[in] end_idx End index of the time window to be plotted.
 27    @param[in] sensor_name Name of the sensor to be plotted (default: "shank").
 28    @param[in] num_windows Number of sliding windows to plot (default: 10).
 29    @param[in] save If True, saves the plot to a file instead of displaying it.
 30
 31    @return None
 32    """
 33
 34    fig, axes = plt.subplots(2, 1, figsize=(20, 10), gridspec_kw={'height_ratios': [3, 1]})
 35    
 36    # Extract sensor windows
 37    sensor_windows = next((sw['data'] for sw in sliding_windows if sw['name'] == sensor_name), None)
 38    if sensor_windows is None:
 39        print(f"Sensor '{sensor_name}' not found in sliding_windows.")
 40        return
 41
 42    # Extract corresponding features
 43    sensor_features = next((feat['features'] for feat in features if feat['name'] == sensor_name), None)
 44    if sensor_features is None:
 45        print(f"Sensor '{sensor_name}' not found in features.")
 46        return
 47
 48    # Filter windows based on start_idx and end_idx
 49    filtered_windows = [series for series in sensor_windows if start_idx <= series.index[0] and series.index[-1] <= end_idx]
 50    
 51    if not filtered_windows:
 52        print(f"No windows found in the specified index range ({start_idx} - {end_idx}).")
 53        return
 54
 55    # Store entropy & frequency features for separate plotting
 56    entropy_values = []
 57    dominant_frequencies = []
 58
 59    # Plot first `num_windows` windows
 60    for i in range(min(num_windows, len(filtered_windows))):
 61        series = filtered_windows[i]  # Each window is a Pandas Series
 62
 63        # Extract time and signal values
 64        time_values = series.index.to_numpy()  # Time is the index
 65        signal_values = series.values  # Sensor readings
 66
 67        # Determine actual start and end indices for this window
 68        window_start, window_end = time_values[0], time_values[-1]
 69
 70        # Plot time series data
 71        axes[0].plot(time_values, signal_values, alpha=0.6)
 72
 73        # Mark start and end of each window with vertical dotted lines
 74        axes[0].axvline(x=window_start, color='black', linestyle='dotted', alpha=0.7)
 75        axes[0].axvline(x=window_end, color='black', linestyle='dotted', alpha=0.7)
 76
 77        # Overlay statistical features
 78        for feature, marker in zip(['mean', 'rms', 'peak_height', 'mode', 'median'], ['x', 'o', 'v', '<', '^']):
 79            if feature in sensor_features and len(sensor_features[feature]) > i:
 80                feature_value = sensor_features[feature][i]
 81                if feature_value != 0:  # Skip zero values
 82                    closest_index = np.argmin(np.abs(signal_values - feature_value))
 83                    closest_time = time_values[closest_index]
 84                    axes[0].scatter(closest_time, feature_value, color='red', marker=marker, s=100)
 85
 86        # Store entropy & frequency features for separate plotting
 87        if 'entropy' in sensor_features and len(sensor_features['entropy']) > i:
 88            entropy_values.append(sensor_features['entropy'][i])
 89        if 'dominant_frequency' in sensor_features and len(sensor_features['dominant_frequency']) > i:
 90            dominant_frequencies.append(sensor_features['dominant_frequency'][i])
 91
 92    # Labels and title for time-series plot
 93    axes[0].set_xlabel('Time')
 94    axes[0].set_ylabel(f'{sensor_name} Signal')
 95    axes[0].set_title(f'First {num_windows} windows of {sensor_name} in range {start_idx}-{end_idx} with Features')
 96
 97    # Frequency-domain & entropy plot (axes[1])
 98    if dominant_frequencies:
 99        window_indices = list(range(len(dominant_frequencies)))
100        axes[1].plot(window_indices, dominant_frequencies, label="Dominant Frequency", marker="o", linestyle="dashed", color="blue")
101    
102    if entropy_values:
103        axes[1].bar(window_indices, entropy_values, alpha=0.6, label="Entropy", color="green")
104
105    axes[1].set_xlabel("Window Index")
106    axes[1].set_ylabel("Feature Value")
107    axes[1].set_title("Frequency & Entropy Features")
108    axes[1].legend()
109
110    plt.tight_layout()
111
112    # Save or show plot
113    if save:
114        file_path = input("Enter the file path to save the plot (e.g., 'plot.png'): ")
115        plt.savefig(file_path, dpi=300)
116        print(f"Plot saved at {file_path}")
117    else:
118        plt.show()

@brief Plots sliding windows of a sensor's time series data with overlaid statistical features.

This function plots the first num_windows sliding windows within the given start_idx and end_idx for a specified sensor and overlays feature values at their corresponding time indices. It also displays entropy and dominant frequency in a separate plot.

@param[in] sliding_windows List of dictionaries, where each dictionary contains: - 'name': sensor name (str) - 'data': List of time-series windows (each as a Pandas Series) @param[in] features List of dictionaries, where each dictionary contains: - 'name': sensor name (str) - 'features': Dictionary of extracted feature lists @param[in] start_idx Start index of the time window to be plotted. @param[in] end_idx End index of the time window to be plotted. @param[in] sensor_name Name of the sensor to be plotted (default: "shank"). @param[in] num_windows Number of sliding windows to plot (default: 10). @param[in] save If True, saves the plot to a file instead of displaying it.

@return None