mcp-server-mcsa 0.1.0__py3-none-any.whl → 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_server_mcsa/__init__.py +37 -37
- mcp_server_mcsa/__main__.py +5 -5
- mcp_server_mcsa/analysis/__init__.py +19 -19
- mcp_server_mcsa/analysis/bearing.py +147 -147
- mcp_server_mcsa/analysis/envelope.py +96 -97
- mcp_server_mcsa/analysis/fault_detection.py +424 -425
- mcp_server_mcsa/analysis/file_io.py +429 -428
- mcp_server_mcsa/analysis/motor.py +147 -145
- mcp_server_mcsa/analysis/preprocessing.py +180 -180
- mcp_server_mcsa/analysis/spectral.py +171 -172
- mcp_server_mcsa/analysis/test_signal.py +232 -232
- mcp_server_mcsa/analysis/timefreq.py +132 -132
- mcp_server_mcsa/server.py +954 -955
- {mcp_server_mcsa-0.1.0.dist-info → mcp_server_mcsa-0.1.1.dist-info}/METADATA +3 -1
- mcp_server_mcsa-0.1.1.dist-info/RECORD +18 -0
- {mcp_server_mcsa-0.1.0.dist-info → mcp_server_mcsa-0.1.1.dist-info}/licenses/LICENSE +21 -21
- mcp_server_mcsa-0.1.0.dist-info/RECORD +0 -18
- {mcp_server_mcsa-0.1.0.dist-info → mcp_server_mcsa-0.1.1.dist-info}/WHEEL +0 -0
- {mcp_server_mcsa-0.1.0.dist-info → mcp_server_mcsa-0.1.1.dist-info}/entry_points.txt +0 -0
|
@@ -1,132 +1,132 @@
|
|
|
1
|
-
"""Time–frequency analysis for MCSA.
|
|
2
|
-
|
|
3
|
-
Short‑Time Fourier Transform (STFT) for analysing non‑stationary conditions
|
|
4
|
-
(variable speed/load, start‑up transients).
|
|
5
|
-
"""
|
|
6
|
-
|
|
7
|
-
from __future__ import annotations
|
|
8
|
-
|
|
9
|
-
import numpy as np
|
|
10
|
-
from numpy.typing import NDArray
|
|
11
|
-
from scipy import signal as sig
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
def compute_stft(
|
|
15
|
-
x: NDArray[np.floating],
|
|
16
|
-
fs: float,
|
|
17
|
-
nperseg: int = 256,
|
|
18
|
-
noverlap: int | None = None,
|
|
19
|
-
window: str = "hann",
|
|
20
|
-
) -> dict:
|
|
21
|
-
"""Compute the Short‑Time Fourier Transform of a signal.
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
x: Input signal.
|
|
25
|
-
fs: Sampling frequency in Hz.
|
|
26
|
-
nperseg: Window length per segment (samples).
|
|
27
|
-
noverlap: Overlap between segments. Default → nperseg // 2.
|
|
28
|
-
window: Window function name.
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
Dictionary with:
|
|
32
|
-
- ``frequencies_hz``: 1‑D array of frequency bins.
|
|
33
|
-
- ``times_s``: 1‑D array of time centres.
|
|
34
|
-
- ``magnitude``: 2‑D array (freq × time) of STFT magnitude.
|
|
35
|
-
- ``n_freq_bins``: number of frequency bins.
|
|
36
|
-
- ``n_time_bins``: number of time frames.
|
|
37
|
-
"""
|
|
38
|
-
if noverlap is None:
|
|
39
|
-
noverlap = nperseg // 2
|
|
40
|
-
|
|
41
|
-
freqs, times, Zxx = sig.stft(
|
|
42
|
-
x, fs=fs, window=window, nperseg=nperseg, noverlap=noverlap,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
magnitude = np.abs(Zxx)
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
"frequencies_hz": freqs,
|
|
49
|
-
"times_s": times,
|
|
50
|
-
"magnitude": magnitude,
|
|
51
|
-
"n_freq_bins": len(freqs),
|
|
52
|
-
"n_time_bins": len(times),
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
def compute_spectrogram(
|
|
57
|
-
x: NDArray[np.floating],
|
|
58
|
-
fs: float,
|
|
59
|
-
nperseg: int = 256,
|
|
60
|
-
noverlap: int | None = None,
|
|
61
|
-
window: str = "hann",
|
|
62
|
-
) -> dict:
|
|
63
|
-
"""Compute the spectrogram (magnitude‑squared STFT) of a signal.
|
|
64
|
-
|
|
65
|
-
Convenience wrapper around scipy.signal.spectrogram.
|
|
66
|
-
|
|
67
|
-
Args:
|
|
68
|
-
x: Input signal.
|
|
69
|
-
fs: Sampling frequency in Hz.
|
|
70
|
-
nperseg: Segment length.
|
|
71
|
-
noverlap: Segment overlap. Default → nperseg // 2.
|
|
72
|
-
window: Window function.
|
|
73
|
-
|
|
74
|
-
Returns:
|
|
75
|
-
Dictionary with ``frequencies_hz``, ``times_s``, ``power``
|
|
76
|
-
(2‑D array of spectral power values).
|
|
77
|
-
"""
|
|
78
|
-
if noverlap is None:
|
|
79
|
-
noverlap = nperseg // 2
|
|
80
|
-
|
|
81
|
-
freqs, times, Sxx = sig.spectrogram(
|
|
82
|
-
x, fs=fs, window=window, nperseg=nperseg, noverlap=noverlap,
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
return {
|
|
86
|
-
"frequencies_hz": freqs,
|
|
87
|
-
"times_s": times,
|
|
88
|
-
"power": Sxx,
|
|
89
|
-
"n_freq_bins": len(freqs),
|
|
90
|
-
"n_time_bins": len(times),
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def track_frequency_over_time(
|
|
95
|
-
stft_result: dict,
|
|
96
|
-
target_freq_hz: float,
|
|
97
|
-
tolerance_hz: float = 2.0,
|
|
98
|
-
) -> dict:
|
|
99
|
-
"""Track the amplitude of a specific frequency component over time.
|
|
100
|
-
|
|
101
|
-
Useful for monitoring how a fault signature evolves during a transient
|
|
102
|
-
(e.g. start‑up, load change).
|
|
103
|
-
|
|
104
|
-
Args:
|
|
105
|
-
stft_result: Output from ``compute_stft``.
|
|
106
|
-
target_freq_hz: The target frequency to track.
|
|
107
|
-
tolerance_hz: Frequency tolerance for peak search.
|
|
108
|
-
|
|
109
|
-
Returns:
|
|
110
|
-
Dictionary with ``times_s`` and ``amplitude`` arrays.
|
|
111
|
-
"""
|
|
112
|
-
freqs = stft_result["frequencies_hz"]
|
|
113
|
-
magnitude = stft_result["magnitude"]
|
|
114
|
-
|
|
115
|
-
mask = np.abs(freqs - target_freq_hz) <= tolerance_hz
|
|
116
|
-
if not np.any(mask):
|
|
117
|
-
return {
|
|
118
|
-
"target_freq_hz": target_freq_hz,
|
|
119
|
-
"times_s": stft_result["times_s"].tolist(),
|
|
120
|
-
"amplitude": [0.0] * stft_result["n_time_bins"],
|
|
121
|
-
"found": False,
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
# Max amplitude in the tolerance band at each time step
|
|
125
|
-
amps = np.max(magnitude[mask, :], axis=0)
|
|
126
|
-
|
|
127
|
-
return {
|
|
128
|
-
"target_freq_hz": target_freq_hz,
|
|
129
|
-
"times_s": stft_result["times_s"].tolist(),
|
|
130
|
-
"amplitude": amps.tolist(),
|
|
131
|
-
"found": True,
|
|
132
|
-
}
|
|
1
|
+
"""Time–frequency analysis for MCSA.
|
|
2
|
+
|
|
3
|
+
Short‑Time Fourier Transform (STFT) for analysing non‑stationary conditions
|
|
4
|
+
(variable speed/load, start‑up transients).
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from numpy.typing import NDArray
|
|
11
|
+
from scipy import signal as sig
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def compute_stft(
|
|
15
|
+
x: NDArray[np.floating],
|
|
16
|
+
fs: float,
|
|
17
|
+
nperseg: int = 256,
|
|
18
|
+
noverlap: int | None = None,
|
|
19
|
+
window: str = "hann",
|
|
20
|
+
) -> dict:
|
|
21
|
+
"""Compute the Short‑Time Fourier Transform of a signal.
|
|
22
|
+
|
|
23
|
+
Args:
|
|
24
|
+
x: Input signal.
|
|
25
|
+
fs: Sampling frequency in Hz.
|
|
26
|
+
nperseg: Window length per segment (samples).
|
|
27
|
+
noverlap: Overlap between segments. Default → nperseg // 2.
|
|
28
|
+
window: Window function name.
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
Dictionary with:
|
|
32
|
+
- ``frequencies_hz``: 1‑D array of frequency bins.
|
|
33
|
+
- ``times_s``: 1‑D array of time centres.
|
|
34
|
+
- ``magnitude``: 2‑D array (freq × time) of STFT magnitude.
|
|
35
|
+
- ``n_freq_bins``: number of frequency bins.
|
|
36
|
+
- ``n_time_bins``: number of time frames.
|
|
37
|
+
"""
|
|
38
|
+
if noverlap is None:
|
|
39
|
+
noverlap = nperseg // 2
|
|
40
|
+
|
|
41
|
+
freqs, times, Zxx = sig.stft(
|
|
42
|
+
x, fs=fs, window=window, nperseg=nperseg, noverlap=noverlap,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
magnitude = np.abs(Zxx)
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
"frequencies_hz": freqs,
|
|
49
|
+
"times_s": times,
|
|
50
|
+
"magnitude": magnitude,
|
|
51
|
+
"n_freq_bins": len(freqs),
|
|
52
|
+
"n_time_bins": len(times),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def compute_spectrogram(
|
|
57
|
+
x: NDArray[np.floating],
|
|
58
|
+
fs: float,
|
|
59
|
+
nperseg: int = 256,
|
|
60
|
+
noverlap: int | None = None,
|
|
61
|
+
window: str = "hann",
|
|
62
|
+
) -> dict:
|
|
63
|
+
"""Compute the spectrogram (magnitude‑squared STFT) of a signal.
|
|
64
|
+
|
|
65
|
+
Convenience wrapper around scipy.signal.spectrogram.
|
|
66
|
+
|
|
67
|
+
Args:
|
|
68
|
+
x: Input signal.
|
|
69
|
+
fs: Sampling frequency in Hz.
|
|
70
|
+
nperseg: Segment length.
|
|
71
|
+
noverlap: Segment overlap. Default → nperseg // 2.
|
|
72
|
+
window: Window function.
|
|
73
|
+
|
|
74
|
+
Returns:
|
|
75
|
+
Dictionary with ``frequencies_hz``, ``times_s``, ``power``
|
|
76
|
+
(2‑D array of spectral power values).
|
|
77
|
+
"""
|
|
78
|
+
if noverlap is None:
|
|
79
|
+
noverlap = nperseg // 2
|
|
80
|
+
|
|
81
|
+
freqs, times, Sxx = sig.spectrogram(
|
|
82
|
+
x, fs=fs, window=window, nperseg=nperseg, noverlap=noverlap,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
return {
|
|
86
|
+
"frequencies_hz": freqs,
|
|
87
|
+
"times_s": times,
|
|
88
|
+
"power": Sxx,
|
|
89
|
+
"n_freq_bins": len(freqs),
|
|
90
|
+
"n_time_bins": len(times),
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def track_frequency_over_time(
|
|
95
|
+
stft_result: dict,
|
|
96
|
+
target_freq_hz: float,
|
|
97
|
+
tolerance_hz: float = 2.0,
|
|
98
|
+
) -> dict:
|
|
99
|
+
"""Track the amplitude of a specific frequency component over time.
|
|
100
|
+
|
|
101
|
+
Useful for monitoring how a fault signature evolves during a transient
|
|
102
|
+
(e.g. start‑up, load change).
|
|
103
|
+
|
|
104
|
+
Args:
|
|
105
|
+
stft_result: Output from ``compute_stft``.
|
|
106
|
+
target_freq_hz: The target frequency to track.
|
|
107
|
+
tolerance_hz: Frequency tolerance for peak search.
|
|
108
|
+
|
|
109
|
+
Returns:
|
|
110
|
+
Dictionary with ``times_s`` and ``amplitude`` arrays.
|
|
111
|
+
"""
|
|
112
|
+
freqs = stft_result["frequencies_hz"]
|
|
113
|
+
magnitude = stft_result["magnitude"]
|
|
114
|
+
|
|
115
|
+
mask = np.abs(freqs - target_freq_hz) <= tolerance_hz
|
|
116
|
+
if not np.any(mask):
|
|
117
|
+
return {
|
|
118
|
+
"target_freq_hz": target_freq_hz,
|
|
119
|
+
"times_s": stft_result["times_s"].tolist(),
|
|
120
|
+
"amplitude": [0.0] * stft_result["n_time_bins"],
|
|
121
|
+
"found": False,
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
# Max amplitude in the tolerance band at each time step
|
|
125
|
+
amps = np.max(magnitude[mask, :], axis=0)
|
|
126
|
+
|
|
127
|
+
return {
|
|
128
|
+
"target_freq_hz": target_freq_hz,
|
|
129
|
+
"times_s": stft_result["times_s"].tolist(),
|
|
130
|
+
"amplitude": amps.tolist(),
|
|
131
|
+
"found": True,
|
|
132
|
+
}
|