taigatakano commited on
Commit
0435fcb
·
1 Parent(s): 8b5f82a

Code refectraing

Browse files
Files changed (2) hide show
  1. app.py +1 -1
  2. lab_tools/spectrogram.py +82 -73
app.py CHANGED
@@ -81,7 +81,7 @@ with gr.Blocks() as main_ui:
81
  wavelet_image = gr.Image(type="filepath", label="Wavelet")
82
  signal_image = gr.Image(type="filepath", label="Signal")
83
 
84
- submit_button.click(spectrogram.spectrogram_ui, inputs=[
85
  file_input, analysis_method,
86
  fs_slider, fmax_slider, column_dropdown, start_time, end_time,
87
  filter_setting, fp_hp, fs_hp, gpass, gstop],
 
81
  wavelet_image = gr.Image(type="filepath", label="Wavelet")
82
  signal_image = gr.Image(type="filepath", label="Signal")
83
 
84
+ submit_button.click(spectrogram.generate_spectrogram_and_signal_plot, inputs=[
85
  file_input, analysis_method,
86
  fs_slider, fmax_slider, column_dropdown, start_time, end_time,
87
  filter_setting, fp_hp, fs_hp, gpass, gstop],
lab_tools/spectrogram.py CHANGED
@@ -1,38 +1,48 @@
1
  import numpy as np
2
  import matplotlib.pyplot as plt
3
  import scipy.signal as signal
 
4
  from lab_tools import labutils
5
  from lab_tools import filter
6
  import math
7
  import os
8
 
9
 
10
- def morlet_wavelet(x, f, width):
11
- sf = f / width
12
- st = 1 / (2 * math.pi * sf)
13
- A = 1 / (st * math.sqrt(2 * math.pi))
14
- h = -np.power(x, 2) / (2 * st**2)
15
- co1 = 1j * 2 * math.pi * f * x
16
- return A * np.exp(co1) * np.exp(h)
 
17
 
18
 
19
- def continuous_wavelet_transform(Fs, data, fmax, width=48, wavelet_R=0.5):
20
- Ts = 1 / Fs
21
- wavelet_length = np.arange(-wavelet_R, wavelet_R, Ts)
22
- data_length = len(data)
23
- cwt_result = np.zeros([fmax, data_length])
 
24
 
25
- for i in range(fmax):
26
- conv_result = np.convolve(data, morlet_wavelet(wavelet_length, i + 1, width), mode='same')
27
- cwt_result[i, :] = (2 * np.abs(conv_result) / Fs) ** 2
 
 
28
 
29
- return cwt_result
 
 
30
 
 
31
 
32
- def plot_cwt(cwt_result, time_data, fmax):
33
- plt.imshow(cwt_result, cmap='jet', aspect='auto',
34
- extent=[time_data[0], time_data[-1], fmax, 0],
35
- vmax=abs(cwt_result).max(), vmin=-abs(cwt_result).max())
 
 
36
  plt.xlabel("Time [sec]")
37
  plt.ylabel("Frequency [Hz]")
38
  plt.colorbar(label="Power")
@@ -40,83 +50,82 @@ def plot_cwt(cwt_result, time_data, fmax):
40
  plt.gca().invert_yaxis()
41
 
42
 
43
- def stft_plot_spectrogram(data, Fs, N, freq_limit=None):
44
- freqs, times, Zxx = signal.stft(data, fs=Fs, window='hann', nperseg=N, noverlap=None)
45
- amp = np.abs(Zxx)
46
- amp[amp == 0] = np.finfo(float).eps
 
47
  fig, ax = plt.subplots(figsize=(12, 6))
48
- spectrogram = ax.pcolormesh(times, freqs, amp, shading="auto", vmin=0, vmax=5)
49
  fig.colorbar(spectrogram, ax=ax, orientation="vertical").set_label("Amplitude")
50
  ax.set_xlabel("Time [s]")
51
  ax.set_ylabel("Frequency [Hz]")
52
- if freq_limit:
53
- ax.set_ylim([0, freq_limit])
54
  plt.show()
55
 
56
 
57
- def normalize_signal(signal, min_val=0, max_val=10):
58
- signal_min = np.min(signal)
59
- signal_max = np.max(signal)
 
60
  if signal_max - signal_min == 0:
61
- return np.full_like(signal, min_val)
62
- return (signal - signal_min) / (signal_max - signal_min) * (max_val - min_val) + min_val
63
 
64
 
65
- # グラフ描画とスペクトログラムの処理を行う関数
66
- def spectrogram_ui(
67
  uploaded_file, analysis_method,
68
- Fs, fmax, column_name, start_time, end_time,
69
- filter_setting, fp_hp, fs_hp, gpass, gstop):
70
- filepath = uploaded_file.name
71
- signal = labutils.load_signal(filepath, column_name)
72
- if len(signal) == 0:
73
  return None, None
74
 
75
  output_dir = "/tmp/spectrogram/"
76
  os.makedirs(output_dir, exist_ok=True)
77
 
78
- # Filter
79
- timestamps = labutils.load_signal(filepath, "Timestamp")
80
- dt = (timestamps[1] - timestamps[0])
81
- samplerate = 1.0 / dt
82
- if filter_setting == "High PASS":
83
- signal = filter.highpass(signal, samplerate, fp_hp, fs_hp, gpass, gstop)
84
- elif filter_setting == "Low PASS":
85
- signal = filter.lowpass(signal, samplerate, fp_hp, fs_hp, gpass, gstop)
86
-
87
- # 時間データを計算
88
- t_data = np.arange(0, len(signal) / Fs, 1 / Fs)
89
-
90
- # スライダーの範囲に基づいてデータをフィルタリング
91
- start_idx = int(start_time * Fs)
92
- end_idx = int(end_time * Fs)
93
- signal = signal[start_idx:end_idx]
94
- t_data = t_data[start_idx:end_idx]
95
-
96
- # 信号を正規化
97
- # signal = normalize_signal(signal, min_val=0, max_val=5)
98
-
99
- # 信号をプロットして保存
100
  plt.figure(dpi=200)
101
  plt.title("Signal")
102
- plt.plot(t_data, signal)
103
  plt.xlim(start_time, end_time)
104
  plt.xlabel("Time [sec]")
105
  plt.ylabel("Voltage [uV]")
106
- signal_filename = "/tmp/spectrogram/signal_plot.png"
107
- plt.savefig(signal_filename)
108
 
109
- # スペクトログラムプロットして保存
110
  if analysis_method == "Short-Time Fourier Transform":
111
  plt.figure(dpi=200)
112
- stft_plot_spectrogram(data=signal, Fs=Fs, N=256, freq_limit=fmax)
113
- spectrogram_filename = "/tmp/spectrogram/stft_spectrogram_plot.png"
114
- plt.savefig(spectrogram_filename)
115
  else:
116
- spectrogram_filename = "/tmp/spectrogram/wavelet_spectrogram_plot.png"
117
- cwt_signal = continuous_wavelet_transform(Fs=Fs, data=signal, fmax=fmax)
118
  plt.figure(dpi=200)
119
- plot_cwt(cwt_signal, t_data, fmax)
120
- plt.savefig(spectrogram_filename)
121
 
122
- return spectrogram_filename, signal_filename
 
1
  import numpy as np
2
  import matplotlib.pyplot as plt
3
  import scipy.signal as signal
4
+ from scipy.signal import fftconvolve
5
  from lab_tools import labutils
6
  from lab_tools import filter
7
  import math
8
  import os
9
 
10
 
11
+ # モルレーウェーブレットの計算
12
+ def calculate_morlet_wavelet(time_array, frequency, wavelet_width):
13
+ scale_factor = frequency / wavelet_width
14
+ std_time = 1 / (2 * math.pi * scale_factor)
15
+ amplitude = 1 / (std_time * np.sqrt(2 * math.pi))
16
+ exp_component = -np.power(time_array, 2) / (2 * std_time**2)
17
+ oscillatory_component = 1j * 2 * math.pi * frequency * time_array
18
+ return amplitude * np.exp(oscillatory_component + exp_component)
19
 
20
 
21
+ # 連続ウェーブレット変換 (Continuous Wavelet Transform)
22
+ def perform_cwt(sample_rate, signal_data, max_frequency, wavelet_width=48, wavelet_range=0.5):
23
+ time_step = 1 / sample_rate
24
+ wavelet_time_array = np.arange(-wavelet_range, wavelet_range, time_step)
25
+ signal_length = len(signal_data)
26
+ cwt_matrix = np.zeros((max_frequency, signal_length))
27
 
28
+ # モルレーウェーブレットを全て事前計算
29
+ wavelets = [
30
+ calculate_morlet_wavelet(wavelet_time_array, freq + 1, wavelet_width)
31
+ for freq in range(max_frequency)
32
+ ]
33
 
34
+ for freq, wavelet in enumerate(wavelets):
35
+ convolution_result = fftconvolve(signal_data, wavelet, mode='same')
36
+ cwt_matrix[freq, :] = (2 * np.abs(convolution_result) / sample_rate) ** 2
37
 
38
+ return cwt_matrix
39
 
40
+
41
+ # CWTの結果をプロットする関数
42
+ def plot_cwt_result(cwt_matrix, time_array, max_frequency):
43
+ plt.imshow(cwt_matrix, cmap='jet', aspect='auto',
44
+ extent=[time_array[0], time_array[-1], max_frequency, 0],
45
+ vmax=abs(cwt_matrix).max(), vmin=-abs(cwt_matrix).max())
46
  plt.xlabel("Time [sec]")
47
  plt.ylabel("Frequency [Hz]")
48
  plt.colorbar(label="Power")
 
50
  plt.gca().invert_yaxis()
51
 
52
 
53
+ # 短時間フーリエ変換 (STFT) のスペクトログラムをプロットする関数
54
+ def plot_stft_spectrogram(signal_data, sample_rate, segment_length, max_frequency=None):
55
+ frequencies, times, stft_result = signal.stft(signal_data, fs=sample_rate, window='hann', nperseg=segment_length, noverlap=None)
56
+ amplitude = np.abs(stft_result)
57
+ amplitude[amplitude == 0] = np.finfo(float).eps
58
  fig, ax = plt.subplots(figsize=(12, 6))
59
+ spectrogram = ax.pcolormesh(times, frequencies, amplitude, shading="auto", vmin=0, vmax=5)
60
  fig.colorbar(spectrogram, ax=ax, orientation="vertical").set_label("Amplitude")
61
  ax.set_xlabel("Time [s]")
62
  ax.set_ylabel("Frequency [Hz]")
63
+ if max_frequency:
64
+ ax.set_ylim([0, max_frequency])
65
  plt.show()
66
 
67
 
68
+ # 信号を正規化する関数
69
+ def normalize_signal(input_signal, min_val=0, max_val=10):
70
+ signal_min = np.min(input_signal)
71
+ signal_max = np.max(input_signal)
72
  if signal_max - signal_min == 0:
73
+ return np.full_like(input_signal, min_val)
74
+ return (input_signal - signal_min) / (signal_max - signal_min) * (max_val - min_val) + min_val
75
 
76
 
77
+ # UI処理: スペクトログラム生成・信号プロット
78
+ def generate_spectrogram_and_signal_plot(
79
  uploaded_file, analysis_method,
80
+ sample_rate, max_frequency, signal_column_name, start_time, end_time,
81
+ filter_type, highpass_cutoff, stopband_cutoff, passband_ripple, stopband_attenuation):
82
+ file_path = uploaded_file.name
83
+ signal_data = labutils.load_signal(file_path, signal_column_name)
84
+ if len(signal_data) == 0:
85
  return None, None
86
 
87
  output_dir = "/tmp/spectrogram/"
88
  os.makedirs(output_dir, exist_ok=True)
89
 
90
+ # フィルタ処理
91
+ timestamps = labutils.load_signal(file_path, "Timestamp")
92
+ delta_time = timestamps[1] - timestamps[0]
93
+ actual_sample_rate = 1.0 / delta_time
94
+ if filter_type == "High PASS":
95
+ signal_data = filter.highpass(signal_data, actual_sample_rate, highpass_cutoff, stopband_cutoff, passband_ripple, stopband_attenuation)
96
+ elif filter_type == "Low PASS":
97
+ signal_data = filter.lowpass(signal_data, actual_sample_rate, highpass_cutoff, stopband_cutoff, passband_ripple, stopband_attenuation)
98
+
99
+ # 時間配列を計算
100
+ time_array = np.arange(0, len(signal_data) / sample_rate, 1 / sample_rate)
101
+
102
+ # 開始時間と終了時間の範囲に基づデータをング
103
+ start_index = int(start_time * sample_rate)
104
+ end_index = int(end_time * sample_rate)
105
+ signal_data = signal_data[start_index:end_index]
106
+ time_array = time_array[start_index:end_index]
107
+
108
+ # 信号プロットの保存
 
 
 
109
  plt.figure(dpi=200)
110
  plt.title("Signal")
111
+ plt.plot(time_array, signal_data)
112
  plt.xlim(start_time, end_time)
113
  plt.xlabel("Time [sec]")
114
  plt.ylabel("Voltage [uV]")
115
+ signal_plot_path = os.path.join(output_dir, "signal_plot.png")
116
+ plt.savefig(signal_plot_path)
117
 
118
+ # スペクトログラムプロット保存
119
  if analysis_method == "Short-Time Fourier Transform":
120
  plt.figure(dpi=200)
121
+ plot_stft_spectrogram(signal_data, sample_rate, segment_length=256, max_frequency=max_frequency)
122
+ spectrogram_plot_path = os.path.join(output_dir, "stft_spectrogram_plot.png")
123
+ plt.savefig(spectrogram_plot_path)
124
  else:
125
+ spectrogram_plot_path = os.path.join(output_dir, "wavelet_spectrogram_plot.png")
126
+ cwt_matrix = perform_cwt(sample_rate, signal_data, max_frequency)
127
  plt.figure(dpi=200)
128
+ plot_cwt_result(cwt_matrix, time_array, max_frequency)
129
+ plt.savefig(spectrogram_plot_path)
130
 
131
+ return spectrogram_plot_path, signal_plot_path