-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgenerate_spectrograms.py
More file actions
242 lines (191 loc) · 9.59 KB
/
generate_spectrograms.py
File metadata and controls
242 lines (191 loc) · 9.59 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
import numpy as np
import matplotlib.pyplot as plt
import os
import random
import librosa
import librosa.display
# Create directory for data
os.makedirs('/home/ubuntu/data', exist_ok=True)
# Set random seed for reproducibility
np.random.seed(42)
random.seed(42)
# Parameters for spectrograms
n_fft = 2048
hop_length = 512
sr = 22050 # Sample rate
duration = 5 # seconds
n_samples = sr * duration
# Function to generate and save a spectrogram
def generate_and_save_spectrogram(audio_data, filename, category):
plt.figure(figsize=(10, 4))
# Generate spectrogram
D = librosa.amplitude_to_db(np.abs(librosa.stft(audio_data, n_fft=n_fft, hop_length=hop_length)), ref=np.max)
# Plot spectrogram
librosa.display.specshow(D, sr=sr, hop_length=hop_length, x_axis='time', y_axis='log')
plt.colorbar(format='%+2.0f dB')
plt.title(f'Spectrogram - {category}')
# Save spectrogram
save_path = os.path.join('/home/ubuntu/data', filename)
plt.savefig(save_path)
plt.close()
return save_path
# 1. Environmental Noise
def generate_environmental_noise(num_samples=20):
print(f"Generating {num_samples} environmental noise spectrograms...")
for i in range(num_samples):
# Generate white noise with varying amplitude
amplitude = np.random.uniform(0.1, 1.0)
noise = np.random.normal(0, amplitude, n_samples)
# Add low-frequency components to simulate sea state
if random.random() > 0.5:
# Create low frequency noise directly at the right size
low_freq = np.random.uniform(0.1, 0.5) # Low frequency in Hz
t = np.linspace(0, duration, n_samples)
low_freq_component = amplitude * 2 * np.sin(2 * np.pi * low_freq * t)
noise = noise + low_freq_component * 0.5
# Non-stationary noise (varying over time)
if random.random() > 0.3:
envelope = np.linspace(0.5, 1.5, n_samples)
envelope = envelope * np.sin(np.linspace(0, 4 * np.pi, n_samples)) * 0.25 + 1.0
noise = noise * envelope
filename = f"env_noise_{i+1:03d}.png"
generate_and_save_spectrogram(noise, filename, "Environmental Noise")
# 2. Biological Signals
def generate_biological_signals(num_samples=20):
print(f"Generating {num_samples} biological signal spectrograms...")
for i in range(num_samples):
# Base signal
t = np.linspace(0, duration, n_samples)
signal_type = random.choice(['whale', 'fish', 'coral'])
if signal_type == 'whale':
# Whale calls - frequency modulated signals
base_freq = np.random.uniform(100, 500)
modulation_depth = np.random.uniform(50, 200)
modulation_rate = np.random.uniform(0.2, 1.0)
# Create frequency modulation
freq = base_freq + modulation_depth * np.sin(2 * np.pi * modulation_rate * t)
phase = 2 * np.pi * np.cumsum(freq) / sr
bio_signal = np.sin(phase)
# Add amplitude envelope
envelope = np.exp(-((t - duration/2)**2) / (2 * (duration/4)**2))
bio_signal = bio_signal * envelope
elif signal_type == 'fish':
# Fish sounds - short pulses
bio_signal = np.zeros(n_samples)
num_pulses = random.randint(3, 10)
for _ in range(num_pulses):
pulse_pos = random.randint(0, n_samples - sr//4)
pulse_len = random.randint(sr//20, sr//5)
pulse = np.sin(2 * np.pi * np.random.uniform(500, 2000) * np.arange(pulse_len) / sr)
pulse = pulse * np.hanning(pulse_len)
bio_signal[pulse_pos:pulse_pos+pulse_len] += pulse
else: # coral
# Fish scraping coral - broadband noise bursts
bio_signal = np.zeros(n_samples)
num_bursts = random.randint(5, 15)
for _ in range(num_bursts):
burst_pos = random.randint(0, n_samples - sr//3)
burst_len = random.randint(sr//10, sr//3)
burst = np.random.normal(0, 1, burst_len)
burst = burst * np.hanning(burst_len)
bio_signal[burst_pos:burst_pos+burst_len] += burst
# Add background noise
noise_level = np.random.uniform(0.05, 0.2)
bio_signal = bio_signal + np.random.normal(0, noise_level, n_samples)
# Normalize
bio_signal = bio_signal / np.max(np.abs(bio_signal))
filename = f"bio_signal_{signal_type}_{i+1:03d}.png"
generate_and_save_spectrogram(bio_signal, filename, f"Biological Signal - {signal_type}")
# 3. Man-made Signals
def generate_manmade_signals(num_samples=20):
print(f"Generating {num_samples} man-made signal spectrograms...")
for i in range(num_samples):
# Base signal
t = np.linspace(0, duration, n_samples)
signal_type = random.choice(['boat', 'ship', 'submarine', 'speedboat'])
if signal_type == 'boat' or signal_type == 'ship':
# Steady state harmonic signals
fundamental_freq = np.random.uniform(50, 200)
num_harmonics = random.randint(3, 10)
man_signal = np.zeros(n_samples)
for h in range(1, num_harmonics + 1):
harmonic_amp = 1.0 / h # Amplitude decreases with harmonic number
harmonic_freq = fundamental_freq * h
man_signal += harmonic_amp * np.sin(2 * np.pi * harmonic_freq * t)
# Add some amplitude modulation
if random.random() > 0.5:
mod_freq = np.random.uniform(0.2, 2.0)
man_signal = man_signal * (1 + 0.2 * np.sin(2 * np.pi * mod_freq * t))
elif signal_type == 'submarine':
# Low frequency tonal with possible frequency shifts
base_freq = np.random.uniform(20, 100)
# Possible frequency shift
if random.random() > 0.5:
# Create a frequency shift at some point
shift_point = random.randint(n_samples // 4, 3 * n_samples // 4)
freq_shift = np.random.uniform(-20, 20)
freq1 = np.ones(shift_point) * base_freq
freq2 = np.ones(n_samples - shift_point) * (base_freq + freq_shift)
freq = np.concatenate([freq1, freq2])
else:
freq = np.ones(n_samples) * base_freq
phase = 2 * np.pi * np.cumsum(freq) / sr
man_signal = np.sin(phase)
else: # speedboat
# High frequency with doppler effect
base_freq = np.random.uniform(500, 2000)
# Simulate doppler effect
approach_time = np.random.uniform(0.3, 0.7) * duration
t_approach = t[t <= approach_time]
t_recede = t[t > approach_time]
# Calculate frequency change due to doppler
doppler_factor = np.random.uniform(1.1, 1.5)
freq_approach = base_freq * np.linspace(1, doppler_factor, len(t_approach))
freq_recede = base_freq * np.linspace(doppler_factor, 1, len(t_recede))
freq = np.concatenate([freq_approach, freq_recede])
phase = 2 * np.pi * np.cumsum(freq) / sr
man_signal = np.sin(phase)
# Add engine harmonics
for h in range(2, 6):
harmonic_amp = 0.3 / h
harmonic_phase = h * phase
man_signal += harmonic_amp * np.sin(harmonic_phase)
# Add background noise
noise_level = np.random.uniform(0.05, 0.2)
man_signal = man_signal + np.random.normal(0, noise_level, n_samples)
# Normalize
man_signal = man_signal / np.max(np.abs(man_signal))
filename = f"manmade_{signal_type}_{i+1:03d}.png"
generate_and_save_spectrogram(man_signal, filename, f"Man-made Signal - {signal_type}")
# 4. Broadband Impulse Transients
def generate_transient_signals(num_samples=10):
print(f"Generating {num_samples} transient signal spectrograms...")
for i in range(num_samples):
# Create a base of silence/low noise
transient_signal = np.random.normal(0, 0.05, n_samples)
# Add 1-3 transient events
num_transients = random.randint(1, 3)
for _ in range(num_transients):
# Position of transient
pos = random.randint(0, n_samples - sr//2)
# Duration of transient
transient_duration = random.randint(sr//100, sr//10)
# Create impulse
impulse = np.random.normal(0, 1, transient_duration)
# Apply envelope
impulse = impulse * np.hanning(transient_duration)
# Scale to random amplitude
amplitude = np.random.uniform(0.5, 5.0)
impulse = impulse * amplitude
# Add to signal
transient_signal[pos:pos+transient_duration] += impulse
# Normalize
transient_signal = transient_signal / np.max(np.abs(transient_signal))
filename = f"transient_{i+1:03d}.png"
generate_and_save_spectrogram(transient_signal, filename, "Transient Signal")
# Generate all types of spectrograms
generate_environmental_noise(20)
generate_biological_signals(20)
generate_manmade_signals(20)
generate_transient_signals(10)
print("Spectrogram generation complete. Total spectrograms generated: 70")