commit d9dc016f96dad58c96a349496431b952b65f2c0b parent 844f0022ea373db8824af84b68bd311afc8aa406 Author: Martin Kloeckner <mjkloeckner@gmail.com> Date: Wed, 22 Oct 2025 13:47:02 -0300 Updated `tp/**` Diffstat:
31 files changed, 223 insertions(+), 109 deletions(-) diff --git a/tp/main.py b/tp/main.py @@ -1,8 +1,9 @@ -import matplotlib.pyplot as plt import numpy as np from scipy.io import wavfile from utils import * +## Datos + file1_path = 'data/cancion1.wav' file2_path = 'data/cancion2.wav' filter1_h_file_path = 'data/respuesta_impulso_1.txt' @@ -18,96 +19,109 @@ file2_fs, file2_data = wavfile.read(file2_path) filter1_h = np.loadtxt(filter1_h_file_path) filter2_h = np.loadtxt(filter2_h_file_path) -# 'cancion1' -print(f'"{file1_path}", {file1_fs} Hz') - -## grafico completo -plot(file1_fs, file1_data, file1_path) - -## porciones cuasi-periodicas 'cancion1' -plot(file1_fs, file1_data, file1_path, - t_start=0.248, t_width=0.008, a=0.24978, da=0.003) - -plot(file1_fs, file1_data, file1_path, - t_start=0.520, t_width=0.008, a=0.5208, da=0.003) - -## salida de filtro 'cancion1' file1_filter1_output = np.convolve(file1_data, filter1_h, mode='same') file1_filter2_output = np.convolve(file1_data, filter2_h, mode='same') -save_convolved_to_wav(file1_filter1_output, file1_fs, "file1_filter1_output.wav") -save_convolved_to_wav(file1_filter2_output, file1_fs, "file1_filter2_output.wav") - -## generar grafico comparando la muestra 1 original y filtrada 1 -data_arr = [normalize(file1_data), normalize(file1_filter1_output)] -leg_arr = ['Señal de audio', 'Señal de audio filtrada'] - -fig, ax = plot_multiple(file1_fs, data_arr, leg_arr) -save_plot(fig, file1_path, extra_name="_filter1_output_compare") - -fig, ax = plot_multiple(file1_fs, data_arr, leg_arr, t=0.248, dt=0.008) -save_plot(fig, file1_path, extra_name="_filter1_output_compare_0_248_a_0_256") - -## generar grafico comparando la muestra 1 original y filtrada 2 -data_arr = [normalize(file1_data), normalize(file1_filter2_output)] -leg_arr = ['Señal de audio', 'Señal de audio filtrada'] - -fig, ax = plot_multiple(file1_fs, data_arr, leg_arr) -save_plot(fig, file1_path, extra_name="_filter2_output_compare") - -fig, ax = plot_multiple(file1_fs, data_arr, leg_arr, t=0.248, dt=0.008) -save_plot(fig, file1_path, extra_name="_filter2_output_compare_0_248_a_0_256") - -# 'cancion2' -print(f'"{file2_path}", {file2_fs} Hz') - -## grafico completo -plot(file2_fs, file2_data, file2_path, t_start=6) - -## porciones cuasi-periodicas 'cancion2' -plot(file2_fs, file2_data, file2_path, t_start=14.720, t_width=0.01) -plot(file2_fs, file2_data, file2_path, t_start=26.570, t_width=0.01) - -## salida de filtro 'cancion2' file2_filter1_output = np.convolve(file2_data, filter1_h, mode='same') file2_filter2_output = np.convolve(file2_data, filter2_h, mode='same') -save_convolved_to_wav(file2_filter1_output, file2_fs, "file2_filter1_output.wav") -save_convolved_to_wav(file2_filter2_output, file2_fs, "file2_filter2_output.wav") - -## generar grafico comparando la muestra 2 original y filtrada 2 -data_arr = [normalize(file2_data), normalize(file2_filter1_output)] -leg_arr = ['Señal original', 'Señal filtrada'] - -fig, ax = plot_multiple(file2_fs, data_arr, leg_arr, t=6) -save_plot(fig, file2_path, t_start=6, extra_name="_filter1_output_compare") - -fig, ax = plot_multiple(file2_fs, data_arr, leg_arr, t=26.57, dt=0.01) -save_plot(fig, file2_path, t_start=6, - extra_name="_filter1_output_compare_26_57_a_26_58") - -## generar grafico comparando la muestra 2 original y filtrada 2 -data_arr = [normalize(file2_data), normalize(file2_filter2_output)] -leg_arr = ['Señal original', 'Señal filtrada'] - -fig, ax = plot_multiple(file2_fs, data_arr, leg_arr, t=6) -save_plot(fig, file2_path, t_start=6, extra_name="_filter2_output_compare") - -fig, ax = plot_multiple(file2_fs, data_arr, leg_arr, t=26.57, dt=0.01) -save_plot(fig, file2_path, t_start=6, - extra_name="_filter2_output_compare_26_57_a_26_58") - -# Sonido de instrumentos musicales -a4_flauta_fs, a4_flauta_data = wavfile.read(a4_flauta_file_path) -a4_clarinete_fs, a4_clarinete_data = wavfile.read(a4_clarinete_file_path) -a4_violin_fs, a4_violin_data = wavfile.read(a4_violin_file_path) - -## grafico de los instrumentos musicales -fig, ax = plot(a4_flauta_fs, a4_flauta_data, t_start=0.25, t_width=0.010) -save_plot(fig, a4_flauta_file_path) - -fig, ax = plot(a4_clarinete_fs, a4_clarinete_data, t_start=0.25, t_width=0.010) -save_plot(fig, a4_clarinete_file_path) - -fig, ax = plot(a4_violin_fs, a4_violin_data, t_start=0.25, t_width=0.010) -save_plot(fig, a4_violin_file_path) +## 'cancion1' +def time_domain_cancion1(): + ### grafico completo + time_plot(file1_fs, file1_data, file1_path) + + ### porciones cuasi-periodicas 'cancion1' + time_plot(file1_fs, file1_data, "cancion1_0_248s_a_0_256s", + t_start=0.248, t_width=0.008, a=0.24978, da=0.003) + + time_plot(file1_fs, file1_data, "cancion1_0_520s_a_0_528s", + t_start=0.520, t_width=0.008, a=0.5208, da=0.003) + + ### salida de filtro 'cancion1' + save_convolved_to_wav(file1_filter1_output, file1_fs, "file1_filter1_output.wav") + save_convolved_to_wav(file1_filter2_output, file1_fs, "file1_filter2_output.wav") + + ### grafico comparando la muestra 1 original y filtrada 1 + data_arr = [normalize(file1_data), normalize(file1_filter1_output)] + leg_arr = ['Señal de audio', 'Señal de audio filtrada'] + + time_plot_multiple(file1_fs, data_arr, leg_arr, "cancion1_filter1_output_compare.png") + time_plot_multiple(file1_fs, data_arr, leg_arr, "cancion1_filter1_output_compare_0_248_a_0_256", t=0.248, dt=0.008) + + ### grafico comparando la muestra 1 original y filtrada 2 + data_arr = [normalize(file1_data), normalize(file1_filter2_output)] + leg_arr = ['Señal de audio', 'Señal de audio filtrada'] + + time_plot_multiple(file1_fs, data_arr, leg_arr, "cancion1_filter2_output_compare") + time_plot_multiple(file1_fs, data_arr, leg_arr, + "cancion1_filter2_output_compare_0_248_a_0_256", t=0.248, dt=0.008) + +## 'cancion2' +def time_domain_cancion2(): + ### grafico completo + time_plot(file2_fs, file2_data, "cancion2", t_start=6) + + ### porciones cuasi-periodicas 'cancion2' + time_plot(file2_fs, file2_data, "cancion2_14_72s_a_14_73s", t_start=14.720, t_width=0.01) + time_plot(file2_fs, file2_data, "cancion2_26_57s_a_26_58s", t_start=26.570, t_width=0.01) + + save_convolved_to_wav(file2_filter1_output, file2_fs, "file2_filter1_output.wav") + save_convolved_to_wav(file2_filter2_output, file2_fs, "file2_filter2_output.wav") + + ### grafico comparando la muestra 2 original y filtrada 2 + data_arr = [normalize(file2_data), normalize(file2_filter1_output)] + leg_arr = ['Señal original', 'Señal filtrada'] + + time_plot_multiple(file2_fs, data_arr, leg_arr, "cancion2_6s_filter1_output_compare", t=6) + time_plot_multiple(file2_fs, data_arr, leg_arr, "cancion2_6s_filter1_output_compare_26_57_a_26_58", t=26.57, dt=0.01) + + ### grafico comparando la muestra 2 original y filtrada 2 + data_arr = [normalize(file2_data), normalize(file2_filter2_output)] + leg_arr = ['Señal original', 'Señal filtrada'] + + time_plot_multiple(file2_fs, data_arr, leg_arr, "cancion2_6s_filter2_output_compare", t=6) + time_plot_multiple(file2_fs, data_arr, leg_arr, "cancion2_6s_filter2_output_compare_26_57_a_26_58", t=26.57, dt=0.01) + +def time_domain_music_instruments(): + ## Sonido de instrumentos musicales + a4_flauta_fs, a4_flauta_data = wavfile.read(a4_flauta_file_path) + a4_clarinete_fs, a4_clarinete_data = wavfile.read(a4_clarinete_file_path) + a4_violin_fs, a4_violin_data = wavfile.read(a4_violin_file_path) + + ### grafico de los instrumentos musicales + time_plot(a4_flauta_fs, a4_flauta_data, "a4_flauta", t_start=0.25, t_width=0.010) + time_plot(a4_clarinete_fs, a4_clarinete_data, "a4_clarinete", t_start=0.25, t_width=0.010) + time_plot(a4_violin_fs, a4_violin_data, "a4_violin", t_start=0.25, t_width=0.010) + +def time_domain(): + time_domain_cancion1() + time_domain_cancion2() + time_domain_music_instruments() + +def freq_domain_cancion1(): + freq_plot(file1_fs, file1_data, "cancion1_fft", f_max=8000, y_max=1e8) + freq_plot(file1_fs, file1_filter1_output, "cancion1_filter1_output_fft", + f_max=8000, y_max=1e8) + freq_plot(file1_fs, file1_filter2_output, "cancion1_filter2_output_fft", + f_max=8000, y_max=1e8) + +def freq_domain_cancion2(): + freq_plot(file2_fs, file2_data, "cancion2_fft", + f_max=8000, y_max=0.5e8) + freq_plot(file2_fs, file2_filter1_output, "cancion2_filter1_output_fft", + f_max=8000, y_max=0.5e8) + freq_plot(file2_fs, file2_filter2_output, "cancion2_filter2_output_fft", + f_max=8000, y_max=0.5e8) + +def freq_domain(): + freq_domain_cancion1() + freq_domain_cancion2() + + freq_plot(48000, filter1_h, "filter1_h_fft", f_max=2000) + freq_plot(48000, filter2_h, "filter2_h_fft", f_max=8000) + + spectogram_plot(file1_fs, file1_data, "cancion1_espectograma") + spectogram_plot(file2_fs, file2_data, "cancion2_espectograma", t=6) + +time_domain() +freq_domain() diff --git a/tp/plot/a4_clarinete.png b/tp/plot/a4_clarinete.png Binary files differ. diff --git a/tp/plot/a4_flauta.png b/tp/plot/a4_flauta.png Binary files differ. diff --git a/tp/plot/a4_violin.png b/tp/plot/a4_violin.png Binary files differ. diff --git a/tp/plot/cancion1.png b/tp/plot/cancion1.png Binary files differ. diff --git a/tp/plot/cancion1_0_248s_a_0_256s.png b/tp/plot/cancion1_0_248s_a_0_256s.png Binary files differ. diff --git a/tp/plot/cancion1_0_520s_a_0_528s.png b/tp/plot/cancion1_0_520s_a_0_528s.png Binary files differ. diff --git a/tp/plot/cancion1_0_52s_a_0_528s.png b/tp/plot/cancion1_0_52s_a_0_528s.png Binary files differ. diff --git a/tp/plot/cancion1_espectograma.png b/tp/plot/cancion1_espectograma.png Binary files differ. diff --git a/tp/plot/cancion1_fft.png b/tp/plot/cancion1_fft.png Binary files differ. diff --git a/tp/plot/cancion1_filter1_output_compare.png b/tp/plot/cancion1_filter1_output_compare.png Binary files differ. diff --git a/tp/plot/cancion1_filter1_output_compare_0_248_a_0_256.png b/tp/plot/cancion1_filter1_output_compare_0_248_a_0_256.png Binary files differ. diff --git a/tp/plot/cancion1_filter1_output_fft.png b/tp/plot/cancion1_filter1_output_fft.png Binary files differ. diff --git a/tp/plot/cancion1_filter2_output_compare.png b/tp/plot/cancion1_filter2_output_compare.png Binary files differ. diff --git a/tp/plot/cancion1_filter2_output_compare_0_248_a_0_256.png b/tp/plot/cancion1_filter2_output_compare_0_248_a_0_256.png Binary files differ. diff --git a/tp/plot/cancion1_filter2_output_fft.png b/tp/plot/cancion1_filter2_output_fft.png Binary files differ. diff --git a/tp/plot/cancion2.png b/tp/plot/cancion2.png Binary files differ. diff --git a/tp/plot/cancion2_14_72s_a_14_73s.png b/tp/plot/cancion2_14_72s_a_14_73s.png Binary files differ. diff --git a/tp/plot/cancion2_26_57s_a_26_58s.png b/tp/plot/cancion2_26_57s_a_26_58s.png Binary files differ. diff --git a/tp/plot/cancion2_6s.png b/tp/plot/cancion2_6s.png Binary files differ. diff --git a/tp/plot/cancion2_6s_filter1_output_compare.png b/tp/plot/cancion2_6s_filter1_output_compare.png Binary files differ. diff --git a/tp/plot/cancion2_6s_filter1_output_compare_26_57_a_26_58.png b/tp/plot/cancion2_6s_filter1_output_compare_26_57_a_26_58.png Binary files differ. diff --git a/tp/plot/cancion2_6s_filter2_output_compare.png b/tp/plot/cancion2_6s_filter2_output_compare.png Binary files differ. diff --git a/tp/plot/cancion2_6s_filter2_output_compare_26_57_a_26_58.png b/tp/plot/cancion2_6s_filter2_output_compare_26_57_a_26_58.png Binary files differ. diff --git a/tp/plot/cancion2_espectograma.png b/tp/plot/cancion2_espectograma.png Binary files differ. diff --git a/tp/plot/cancion2_fft.png b/tp/plot/cancion2_fft.png Binary files differ. diff --git a/tp/plot/cancion2_filter1_output_fft.png b/tp/plot/cancion2_filter1_output_fft.png Binary files differ. diff --git a/tp/plot/cancion2_filter2_output_fft.png b/tp/plot/cancion2_filter2_output_fft.png Binary files differ. diff --git a/tp/plot/filter1_h_fft.png b/tp/plot/filter1_h_fft.png Binary files differ. diff --git a/tp/plot/filter2_h_fft.png b/tp/plot/filter2_h_fft.png Binary files differ. diff --git a/tp/utils.py b/tp/utils.py @@ -10,6 +10,8 @@ import numpy as np import os from scipy.io import wavfile +from scipy.fft import fft, fftfreq +from scipy.signal import spectrogram plot_dir_name = 'plot' out_dir_name = 'out' @@ -24,7 +26,7 @@ def ticks_label_format(x, pos): # 3 decimales, se eliminan los ceros y puntos return f"{x:.3f}".rstrip("0").rstrip(".") -def graph_multiple_data(x, y_arr, y_lab, t=0, dt=0, a=0, da=0, show=True): +def time_graph_multiple_data(x, y_arr, y_lab, t=0, dt=0, a=0, da=0, show=True): figure, axis = plt.subplots(figsize=(8, 4)) for i, y in enumerate(y_arr): @@ -63,12 +65,16 @@ def graph_multiple_data(x, y_arr, y_lab, t=0, dt=0, a=0, da=0, show=True): return figure, axis # todos deben la misma cantidad de elementos que el primero -def plot_multiple(fs, data_arr, leg_arr, t=0, dt=0, a=0, da=0): +def time_plot_multiple(fs, data_arr, leg_arr, save_name="", t=0, dt=0, a=0, da=0, show=False): x = np.arange(len(data_arr[0])) / fs - fig, ax = graph_multiple_data(x, data_arr, leg_arr, t=t, dt=dt, a=a, da=da, show=False) + fig, ax = time_graph_multiple_data(x, data_arr, leg_arr, t=t, dt=dt, a=a, da=da, show=show) + + if show == False: + save_plot(fig, "cancion1_filter1_output_compare.png") + return fig, ax -def graph_data(x, y, t=0, dt=0, a=0, da=0, show=True): +def time_graph_data(x, y, t=0, dt=0, a=0, da=0, show=True): figure, axis = plt.subplots(figsize=(8, 4)) axis.plot(x, y, label='Señal de audio') @@ -109,36 +115,36 @@ def normalize(data): data /= np.max(np.abs(data)) return data -def plot(fs, data, file_path="", t_start=0, t_width=0, a=0, da=0): +def time_plot(fs, data, save_name="", t_start=0, t_width=0, a=0, da=0): # normaliza la amplitud dividiendo por el valor maximo del tipo de dato data = normalize(data) t = np.arange(len(data)) / fs - fig, ax = graph_data(t, data, t=t_start, dt=t_width, a=a, da=da, show=False) + fig, ax = time_graph_data(t, data, t=t_start, dt=t_width, a=a, da=da, show=False) - if file_path != "": - save_plot(fig, file_path, t_start=t_start, t_width=t_width) + if save_name != "": + save_plot(fig, save_name) return fig, ax -def save_plot(fig, src_file_path, t_start=0, t_width=0, extra_name=''): - basename = os.path.basename(src_file_path) - file_name, ext = os.path.splitext(basename) - fig_file_name = f'{plot_dir_name}/{file_name}' - - if t_start != 0: - fig_name_append_1 = f'_{t_start}s' - fig_name_append_2 = f'_a_{round(t_start + t_width, 3)}s' if t_width != 0 else '' - fig_file_name += fig_name_append_1.replace('.', '_') - fig_file_name += fig_name_append_2.replace('.', '_') +def save_plot(fig, name): + base_name = os.path.basename(name) + file_name, ext = os.path.splitext(base_name) + file_path_no_ext = f'{plot_dir_name}/{file_name}' - fig_file_name += extra_name + save_name = f'{file_path_no_ext}.png' + # if os.path.exists(save_name): + # i = 0 + # while os.path.exists(f'{file_path_no_ext}_{i}.png'): + # i += 1 - print(f'- "{fig_file_name}.png"') + # save_name = f'{file_path_no_ext}_{i}.png' + print(f'- "{save_name}"') # crea carpeta para plots os.makedirs(plot_dir_name, exist_ok=True) - fig.savefig(fig_file_name, dpi=100, bbox_inches="tight") + fig.savefig(save_name, dpi=500, bbox_inches="tight") + plt.close(fig) # liberar memoria def save_convolved_to_wav(convolved, fs, file_path): # normalizar para prevenir clipping @@ -154,3 +160,97 @@ def save_convolved_to_wav(convolved, fs, file_path): print(f'- "{file_path}"') wavfile.write(file_path, fs, convolved_int16) +# frecuencia + +def freq_graph_data(x, y, f_min=0, f_max=0, y_min=0, y_max=0, show=True, save_path=""): + fig, axis = plt.subplots(figsize=(8, 4)) + + axis.plot(x, y, label='Señal de audio') + axis.set(xlabel='Frecuencia [Hz]', ylabel='Magnitud normalizada') + + axis.minorticks_on() + axis.grid(True, which='major', color='black', linestyle=':', linewidth=1.00) + axis.grid(True, which='minor', color='black', linestyle=':', linewidth=0.50) + + # configuracion de ticks del eje x + axis.xaxis.set_major_locator(MaxNLocator(nbins=5)) + axis.xaxis.set_minor_locator(AutoMinorLocator(5)) + + axis.yaxis.set_major_locator(MaxNLocator(nbins=5)) + axis.yaxis.set_minor_locator(AutoMinorLocator(4)) + + plt.tight_layout() + + # max 3 decimales + axis.xaxis.set_major_formatter(FuncFormatter(ticks_label_format)) + + axis.set_xlim([f_min, f_max if f_max != 0 else 20000]) + axis.set_ylim([y_min, y_max if y_max != 0 else 1.05*max(y)]) + + if show: + plt.show() + + return fig, axis + +# hace la transformacion a frecuencias y pasa lo transformado a `freq_graph_data` +def freq_plot(fs, data, save_name="", f_min=0, f_max=0, y_min=0, y_max=0, + t=0, dt=0, a=0, da=0): + + i = 0 + di = fs*len(data) + if t != 0 or dt != 0: + i = int(t*fs) + di = int((t+dt)*fs) + + interval_data = data[i:di] + N = len(interval_data) + interval_fft = fft(interval_data) + interval_freqs = fftfreq(N, d=1/fs) + + # se toma la parte positiva en ambos casos (primer parte del arreglo) + x = interval_freqs[:N // 2] + y = np.abs(interval_fft[:N // 2]) + + fig, ax = freq_graph_data(x, y, f_min, f_max, y_min, y_max, show=False) + + if save_name != "": + save_plot(fig, save_name) + + return fig, ax + + +from datetime import datetime + +def spectogram_plot(fs, data, save_name="", t=0, dt=0, xlim=[], ylim=[], show=False): + if dt == 0: + dt = (len(data)/fs)-t + + i = int(t*fs) + di = int((t+dt)*fs) + interval_data = data[i:di] + + f, time, Sxx = spectrogram(interval_data, fs=fs, nperseg=4096, noverlap=32) + fig, axis = plt.subplots(figsize=(8, 4)) + + plt.pcolormesh(time, f, Sxx**0.10, shading='gouraud') + plt.ylabel('Frecuencia [Hz]') + plt.xlabel('Tiempo [s]') + + if len(xlim) != 0: + plt.xlim(xlim) + + if len(ylim) != 0: + plt.ylim(ylim) + else: + plt.ylim(1, 20000) + + if show == True: + plt.show() + else: + if save_name == "": + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + save_name = f"spectogram_{timestamp}" + + save_plot(fig, save_name) + + return fig, axis
