Skip to content

Commit

Permalink
[BUGFIX] Fix stuck sensor detection only applying to last column (#177)
Browse files Browse the repository at this point in the history
* Append index faults by column to avoid only returning last columns faults

* Add test for find_sensor_stuck_faults

* Ruff format.

* Option for returning stuck sensors by column.

* Rerun smarteole examples in case.

* Rerun artificial data examples.
  • Loading branch information
misi9170 authored Mar 11, 2024
1 parent ee58970 commit 0c1fb64
Show file tree
Hide file tree
Showing 10 changed files with 2,363 additions and 2,539 deletions.

Large diffs are not rendered by default.

2,402 changes: 1,204 additions & 1,198 deletions examples_artificial_data/01_raw_data_processing/01_northing_calibration.ipynb

Large diffs are not rendered by default.

48 changes: 24 additions & 24 deletions examples_smarteole/03_filter_ws_power_curves.ipynb

Large diffs are not rendered by default.

1,708 changes: 854 additions & 854 deletions examples_smarteole/04_northing_calibration.ipynb

Large diffs are not rendered by default.

70 changes: 35 additions & 35 deletions examples_smarteole/05_baseline_energy_ratio_analysis.ipynb

Large diffs are not rendered by default.

100 changes: 50 additions & 50 deletions examples_smarteole/06_wake_steering_energy_ratio_analysis.ipynb

Large diffs are not rendered by default.

Large diffs are not rendered by default.

98 changes: 49 additions & 49 deletions examples_smarteole/08_emgauss_tuning_day_night.ipynb

Large diffs are not rendered by default.

18 changes: 14 additions & 4 deletions flasc/turbine_analysis/find_sensor_faults.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,26 +25,36 @@ def find_sensor_stuck_faults(
n_consecutive_measurements=3,
plot_figures=True,
verbose=False,
return_by_column=False,
):
# Settings which indicate a sensor-stuck type of fault: the standard
# deviation between the [no_consecutive_measurements] number of
# consecutive measurements is less than [stddev_threshold].

# TODO: remove unused argument 'ti'

index_faults = {c: np.array([]) for c in columns}
for c in columns:
if verbose:
print("Processing column %s" % c)
measurement_array = np.array(df[c])

index_faults = _find_sensor_stuck_single_timearray(
column_index_faults = _find_sensor_stuck_single_timearray(
measurement_array=measurement_array,
no_consecutive_measurements=n_consecutive_measurements,
stddev_threshold=stddev_threshold,
index_array=df.index,
)

if (plot_figures) & (len(index_faults) > 0):
_plot_top_sensor_faults(df, c, index_faults)
if (plot_figures) & (len(column_index_faults) > 0):
_plot_top_sensor_faults(df, c, column_index_faults)

index_faults[c] = column_index_faults

return index_faults
if return_by_column:
return index_faults
else:
return np.unique(np.concatenate([v for v in index_faults.values()]))


def _plot_top_sensor_faults(
Expand Down
48 changes: 48 additions & 0 deletions tests/turbine_analysis_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import numpy as np
import pandas as pd

from flasc.turbine_analysis.find_sensor_faults import find_sensor_stuck_faults


def test_find_sensor_stuck_faults():
df_test = pd.DataFrame({"a": [0, 0, 0, 1, 2, 3, 4], "b": [4, 5, 6, 6, 7, 7, 7]})

# Test default behavior
results_a = find_sensor_stuck_faults(df_test, columns=["a"], ti=0, plot_figures=False)
assert (results_a == np.array([0, 1, 2])).all()

results_b = find_sensor_stuck_faults(df_test, columns=["b"], ti=0, plot_figures=False)
assert (results_b == np.array([4, 5, 6])).all()

results_ab = find_sensor_stuck_faults(df_test, columns=["a", "b"], ti=0, plot_figures=False)
assert (results_ab == np.array([0, 1, 2, 4, 5, 6])).all()

results_ba = find_sensor_stuck_faults(df_test, columns=["b", "a"], ti=0, plot_figures=False)
assert (results_ab == results_ba).all()

results_ab2 = find_sensor_stuck_faults(
df_test, columns=["a", "b"], ti=0, n_consecutive_measurements=2, plot_figures=False
)
assert (results_ab2 == np.array([0, 1, 2, 3, 4, 5, 6])).all()

# Test returning by column
results = find_sensor_stuck_faults(
df_test, columns=["a", "b"], ti=0, plot_figures=False, return_by_column=True
)
test_dict = {"a": np.array([0, 1, 2]), "b": np.array([4, 5, 6])}
assert results["a"].size == 3
assert results["b"].size == 3
assert results.keys() == test_dict.keys()
assert all((results[k] == test_dict[k]).all() for k in test_dict)

# Test stddev_threshold
df_test = pd.DataFrame({"a": [0, 0.1, -0.1, 0.05, 1]})
std_true = np.std(df_test["a"][:-1])

results = find_sensor_stuck_faults(df_test, columns=["a"], ti=0, plot_figures=False)
assert results.size == 0 # Empty array, no fault detected

results = find_sensor_stuck_faults(
df_test, columns=["a"], ti=0, stddev_threshold=std_true * 2, plot_figures=False
)
assert (results == np.array([0, 1, 2, 3])).all()

0 comments on commit 0c1fb64

Please sign in to comment.