In [1]:
%matplotlib inline
import matplotlib.pyplot as plt
In [2]:
# Add path from jupyter to the dsp4bats library.
import sys
path = ".."
sys.path.append(path)
In [3]:
import pathlib
import numpy as np
import pandas as pd
import dsp4bats
In [4]:
# Settings.
high_pass_filter_freq_hz=15000
threshold_dbfs_below_peak = 20.0
In [5]:
# Core functionality.
def read_file_and_extract_metrics():
# Read signal from file. Length 1 sec.
wave_reader = dsp4bats.WaveFileReader(sound_file_path)
samp_width = wave_reader.samp_width
frame_rate = wave_reader.frame_rate
sampling_freq = wave_reader.sampling_freq
# Create dsp4bats utils.
signal_util = dsp4bats.SignalUtil(sampling_freq)
spectrum_util = dsp4bats.DbfsSpectrumUtil(window_size=128,
window_function='kaiser',
kaiser_beta=14,
sampling_freq=sampling_freq)
# Prepare output file for metrics.
##out_file_name = pathlib.Path(sound_file_path).stem + '_Metrics.txt'
out_file = pathlib.Path(metrics_file_path).open('w')
out_header = spectrum_util.chirp_metrics_header()
out_file.write('\t'.join(map(str, out_header)) + '\n')# Read until end of file.
# Read file.
found_peak_counter = 0
buffer_number = 0
# Read buffer, 1 sec.
signal_1sec = wave_reader.read_buffer()
# Iterate over buffers.
while len(signal_1sec) > 0:
# Get noise level for 1 sec.
noise_level = signal_util.noise_level(signal_1sec)
noise_level_db = signal_util.noise_level_in_db(signal_1sec)
print('Noise level: ', np.round(noise_level, 5), ' Noise (db): ', np.round(noise_level_db, 2))
# Find peaks in time domain.
peaks = signal_util.find_localmax(signal=signal_1sec,
noise_threshold=noise_level*4.0, # Threshold.
jump=int(sampling_freq/1000), # Jump 1 ms.
frame_length=1024) # Window size.
for peak_position in peaks:
# Extract metrics.
result = spectrum_util.chirp_metrics(
signal=signal_1sec,
peak_position=peak_position,
jump_factor=4000,
high_pass_filter_freq_hz=high_pass_filter_freq_hz,
threshold_dbfs = noise_level_db, # + 5.0,
threshold_dbfs_below_peak = threshold_dbfs_below_peak,
max_frames_to_check=100,
max_silent_slots=8,
debug=False)
if result is False:
continue #
else:
result_dict = dict(zip(out_header, result))
## out_row = [result_dict.get(x, '') for x in out_header]
# Add buffer steps to peak_signal_index, start_signal_index and end_signal_index.
out_row = []
for key in out_header:
if '_signal_index' in key:
# Adjust index if more than one buffer was read.
index = int(result_dict.get(key, 0))
index += buffer_number * signal_util.sampling_freq
out_row.append(index)
else:
out_row.append(result_dict.get(key, ''))
# Write to file.
out_file.write('\t'.join(map(str, out_row)) + '\n')
#
found_peak_counter += 1
#
buffer_number += 1
# Read next buffer.
signal_1sec = wave_reader.read_buffer()
# Done.
print('Detected peak counter: ' + str(found_peak_counter))
wave_reader.close()
out_file.close()
#
return sampling_freq # We need this later...
In [6]:
# Read the produced text file as a dataframe. Calculate and add more columns.
def read_metrics_from_file():
# Read dataframe.
peak_df = pd.read_csv(metrics_file_path, sep="\t")
peak_df.tail()
# Plot time instead of index.
peak_df['time_peak_s'] = peak_df.peak_signal_index / sampling_freq
peak_df['time_start_s'] = peak_df.start_signal_index / sampling_freq
peak_df['time_end_s'] = peak_df.end_signal_index / sampling_freq
# Calculate intervals between chirps.
peak_df['interval_s'] = peak_df.time_peak_s.diff()
peak_df.loc[(peak_df.interval_s > 0.2)] = np.NaN # Too long interval.
return peak_df
In [7]:
# Plot two diagrams to visualise metrics.
def plot_diagrams():
fig, (ax1, ax2) = plt.subplots(2,1,
figsize=(16, 10),
dpi=150,
sharex=True)
# ax1 - peak freq, etc.
cs1 = ax1.scatter(
x=peak_df.time_peak_s,
y=peak_df.peak_freq_khz,
s=150,
c=peak_df.peak_dbfs,
cmap=plt.get_cmap('Reds'), #'YlOrRd'
alpha=0.5)
ax1.vlines(x=peak_df.time_peak_s,
#ymin=peak_df.start_freq_khz,
#ymax=peak_df.end_freq_khz,
ymin=peak_df.max_freq_khz,
ymax=peak_df.min_freq_khz,
linewidth=0.5,
alpha=0.8
)
ax1.hlines(y=peak_df.peak_freq_khz,
xmin=peak_df.time_start_s,
xmax=peak_df.time_end_s,
linewidth=0.5,
alpha=0.8
)
cbar = fig.colorbar(cs1, ax=ax1, label='dBFS')
ax1.set_ylim((0,120))
ax1.minorticks_on()
ax1.grid(which='major', linestyle='-', linewidth='0.5', alpha=0.6)
ax1.grid(which='minor', linestyle='-', linewidth='0.5', alpha=0.3)
ax1.tick_params(which='both', top='off', left='off', right='off', bottom='off')
# ax2 - interval.
cs2 = ax2.scatter(
x=peak_df.time_peak_s,
y=peak_df.interval_s,
s=40,
color='blue',
label='Interval (s)',
alpha=0.5
)
ax2.set_ylim((0,0.2))
ax2.minorticks_on()
ax2.grid(which='major', linestyle='-', linewidth='0.5', alpha=0.6)
ax2.grid(which='minor', linestyle='-', linewidth='0.5', alpha=0.3)
ax2.tick_params(which='both', top='off', left='off', right='off', bottom='off')
# ax3 - duration.
ax3 = ax2.twinx()
ax3.scatter(
x=peak_df.time_peak_s,
y=peak_df.duration_ms,
s=40,
marker='s',
color='red',
label='Duration (ms)',
alpha=0.5
)
ax3.set_ylim((0,20.0))
# Legends
ax2.legend(loc='upper left')
ax3.legend(loc='upper right')
# Adjust size on second diagram.
pos = ax1.get_position()
pos2 = ax2.get_position()
ax2.set_position([pos.x0,pos2.y0,pos.width,pos2.height])
ax3.set_position([pos.x0,pos2.y0,pos.width,pos2.height])
# Titles and labels.
file_name = pathlib.Path(sound_file_path).name
fig.suptitle('Metrics from: ' + file_name,
fontsize=12, fontweight='bold', ha='right')
ax1.set_title('Peak and min/max frequencies, amplitude and start/stop time')
ax1.set_xlabel('Time(s)')
ax1.set_ylabel('Frequency (kHz)')
ax2.set_xlabel('Time(s)')
ax2.set_title('Interval (s) and duration (ms)')
ax2.set_ylabel('Interval (s)')
ax3.set_ylabel('Duration (ms)')
# Save and plot.
fig.savefig(plot_file_path)
plt.show()
In [ ]:
In [8]:
# Calculate and plot metrics for Mdau.
# Settings.
sound_file_path = 'data_in/Mdau_TE384.wav'
metrics_file_path = 'data_out/Mdau_TE384_Metrics.txt'
plot_file_path = 'data_out/Mdau_TE384_Metrics.png'
# Run it.
sampling_freq = read_file_and_extract_metrics()
peak_df = read_metrics_from_file()
plot_diagrams()
In [9]:
# View dataframe for Mdau.
peak_df
Out[9]:
In [ ]:
In [10]:
# Calculate and plot metrics for Ppip.
# Settings.
sound_file_path = 'data_in/Ppip_TE384.wav'
metrics_file_path = 'data_out/Ppip_TE384_Metrics.txt'
plot_file_path = 'data_out/Ppip_TE384_Metrics.png'
# Run it.
sampling_freq = read_file_and_extract_metrics()
peak_df = read_metrics_from_file()
plot_diagrams()
In [11]:
# View dataframe for Ppip.
peak_df
Out[11]:
In [ ]:
In [12]:
# Calculate and plot metrics for syntetic chirps.
# Settings.
sound_file_path = 'data_out/chirp_120_to_30_khz_TE500.wav'
metrics_file_path = 'data_out/chirp_TE500_Metrics.txt'
plot_file_path = 'data_out/chirp_TE500_Metrics.png'
# Run it.
sampling_freq = read_file_and_extract_metrics()
peak_df = read_metrics_from_file()
plot_diagrams()
In [ ]:
In [ ]: