commit 3a1a479850af3cb443dd4d7f0c1d8f7ee1c80a8d from: Ale date: Sun Mar 15 01:35:23 2026 UTC feat: agregar simulacion 3D animada del montaje experimental - Escena 3D: caja insonorizada, vidrio vibrante, laser KY-008, BPW34 en tubo negro, TIA LM358, MAX9814, laptop - Animacion: vidrio vibra al ritmo del audio, haz laser sigue el punto de impacto en tiempo real - Pipeline corregido: transimpedancia directa + resta DC (sin filter()) - 4 subplots animados: audio, I_foto, V_TIA, FFT con picos marcados - Correlacion original/reconstruido: 1.0000 commit - 9ed0fcb7ca4c03d53491326b279520821be6fff7 commit + 3a1a479850af3cb443dd4d7f0c1d8f7ee1c80a8d blob - /dev/null blob + 72e6e079375bb030552e2d4c12b4dbc53bf8e8d5 (mode 644) --- /dev/null +++ simulacion_3d_laser.m @@ -0,0 +1,404 @@ +%% SIMULACION 3D — MICROFONO LASER +% Visualizacion 3D animada del experimento completo: +% Caja insonorizada → vidrio vibrante → laser → BPW34 → +% TIA (LM358) → MAX9814 → PC → FFT → reconstruccion +% +% Autor: Alejandro B. E. — Fisica 2do Semestre + +clear; close all; clc; + +fprintf('╔══════════════════════════════════════════════════════╗\n'); +fprintf('║ SIMULACION 3D — Microfono Laser ║\n'); +fprintf('╚══════════════════════════════════════════════════════╝\n\n'); +fprintf(' Presiona Q en la figura 3D para detener la animacion.\n\n'); + +%% ═══════════════════════════════════════════════════════ +% PARAMETROS +%% ═══════════════════════════════════════════════════════ + +% Audio simulado (acorde La mayor: 440 + 880 + 660 Hz) +f1 = 440; f2 = 880; f3 = 660; +fs = 8000; % Hz +duracion = 3.0; % s + +t = (0 : 1/fs : duracion - 1/fs)'; +N = length(t); + +% Senal de audio dentro de la caja (normalizada -1 a 1) +audio_original = 0.5*sin(2*pi*f1*t) + ... + 0.3*sin(2*pi*f2*t) + ... + 0.2*sin(2*pi*f3*t); +audio_original = audio_original / max(abs(audio_original)); % normalizar + +% Parametros fisicos +R_bpw34 = 0.3; % A/W — responsividad BPW34 @ 650nm +P_laser = 1e-3; % W — potencia laser +mod_depth = 0.15; % antes 0.4, — — profundidad de modulacion del vidrio +Rf_TIA = 10e3; % Ω — resistencia TIA +Av_MAX = 1; % antes 3, V/V — ganancia MAX9814 + +%% ─── PIPELINE DE SENAL (CORREGIDO) ───────────────────── + +% 1. Modulacion optica: vibracion del vidrio modula P_laser +P_luz = P_laser * (1 + mod_depth * audio_original); +% P_luz oscila entre P_laser*(1-m) y P_laser*(1+m) — nunca negativo + +% 2. BPW34: P_luz → I_foto (corriente) +I_foto = R_bpw34 * P_luz + 1e-8 * randn(N,1); +% I_foto_DC = R * P_laser = 0.3 * 1e-3 = 300 µA (offset DC) +% I_foto_AC = R * P_laser * mod_depth * audio = ±120 µA (señal util) + +% 3. TIA: I_foto → V_tia, luego ELIMINAR DC por resta de media +% (en hardware esto lo hace el capacitor de acoplamiento C_ac) +V_tia_total = I_foto * Rf_TIA; % V = I * Rf → offset DC + señal AC +V_tia = V_tia_total - mean(V_tia_total); % solo componente AC +% V_tia_AC pico = mod_depth * R * P_laser * Rf = 0.4*0.3*1e-3*10e3 = 1.2 mV +% Nota: señal pequeña — el MAX9814 la amplifica + +% 4. MAX9814: amplificar y saturar +V_max = Av_MAX * V_tia; +V_max = max(-1.65, min(1.65, V_max)); % saturacion ±1.65V + +% 5. FFT sobre la señal capturada +Y = fft(V_max); +mag_Y = abs(Y); + +% Filtrado: umbral de magnitud (conservar picos principales) +umbral = max(mag_Y) * 0.08; +mascara = mag_Y > umbral; +% Simetria conjugada obligatoria para ifft real +mascara = mascara | flipud(mascara); +Y_filt = Y .* mascara; + +% 6. Reconstruccion (IFFT) +V_rec = real(ifft(Y_filt)); + +% Escalar V_rec para comparar con audio_original (minimos cuadrados) +factor = (audio_original' * V_rec) / (V_rec' * V_rec + 1e-12); +V_rec_escalado = V_rec * factor; + +% Correlacion +cc = corrcoef(audio_original, V_rec_escalado); +rho = cc(1,2); + +fprintf(' Senal simulada:\n'); +fprintf(' Frecuencias: %.0f + %.0f + %.0f Hz\n', f1, f2, f3); +fprintf(' I_foto DC: %.0f uA\n', mean(I_foto)*1e6); +fprintf(' V_TIA AC pico: %.4f V\n', max(abs(V_tia))); +fprintf(' V_MAX pico: %.4f V\n', max(abs(V_max))); +fprintf(' Correlacion: %.4f\n\n', rho); + +%% ═══════════════════════════════════════════════════════ +% FIGURA PRINCIPAL +%% ═══════════════════════════════════════════════════════ +fig = figure('Name','Simulacion 3D — Microfono Laser', ... + 'NumberTitle','off', ... + 'Position',[30 30 1500 900], ... + 'Color',[0.05 0.05 0.08], ... + 'KeyPressFcn', @(s,e) setappdata(s,'salir', strcmp(e.Key,'q'))); +setappdata(fig, 'salir', false); + +%% ═══════════════════════════════════════════════════════ +% SUBPLOT 3D +%% ═══════════════════════════════════════════════════════ +ax3d = subplot('Position', [0.02 0.35 0.55 0.62]); +set(ax3d,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w','ZColor','w'); +hold(ax3d,'on'); grid(ax3d,'on'); +view(ax3d, 35, 22); +xlabel(ax3d,'X (cm)','Color','w'); +ylabel(ax3d,'Y (cm)','Color','w'); +zlabel(ax3d,'Z (cm)','Color','w'); +title(ax3d,'Montaje experimental 3D','Color',[1 0.7 0.1],'FontWeight','bold','FontSize',12); +ax3d.GridColor = [0.2 0.2 0.2]; +xlim(ax3d,[-2 58]); ylim(ax3d,[-3 38]); zlim(ax3d,[-1 33]); +lighting(ax3d,'gouraud'); +light(ax3d,'Position',[60 60 60],'Style','infinite'); + +% Helper: dibujar caja + function dibujar_caja(ax,x0,y0,z0,Lx,Ly,Lz,col,al) + verts = [x0 y0 z0; + x0+Lx y0 z0; + x0+Lx y0+Ly z0; + x0 y0+Ly z0; + x0 y0 z0+Lz; + x0+Lx y0 z0+Lz; + x0+Lx y0+Ly z0+Lz; + x0 y0+Ly z0+Lz]; + faces = [1 2 6 5; 2 3 7 6; 3 4 8 7; + 4 1 5 8; 1 2 3 4; 5 6 7 8]; + patch(ax,'Vertices',verts,'Faces',faces, ... + 'FaceColor',col,'FaceAlpha',al, ... + 'EdgeColor',[0.55 0.55 0.55],'LineWidth',0.7); + end + +Lc = 20; % tamaño caja (cm) + +% Caja insonorizada +dibujar_caja(ax3d, 0,0,0, Lc,Lc,Lc, [0.35 0.25 0.15], 0.22); +text(ax3d, Lc/2, Lc/2, Lc+1.5,'Caja insonorizada', ... + 'Color',[0.85 0.65 0.3],'FontSize',9,'HorizontalAlignment','center'); + +% Vidrio (cara x=Lc) +[yv,zv] = meshgrid(linspace(0.5,Lc-0.5,12), linspace(0.5,Lc-0.5,12)); +xv0 = Lc * ones(size(yv)); +h_vidrio = surf(ax3d, xv0, yv, zv, ... + 'FaceColor',[0.5 0.8 1.0],'FaceAlpha',0.28, ... + 'EdgeColor',[0.4 0.7 0.9],'EdgeAlpha',0.12); +text(ax3d, Lc+0.3, Lc/2, Lc+0.8,'Vidrio', ... + 'Color',[0.5 0.9 1.0],'FontSize',9); + +% Audifono dentro de la caja +th = linspace(0,2*pi,40); +for lado = [-1 1] + yc = Lc/2 + lado*5; + fill3(ax3d, Lc/2-0.3+zeros(1,40), ... + yc + 3*cos(th), ... + Lc/2 + 3*sin(th), ... + [0.2 0.2 0.2],'FaceAlpha',0.85,'EdgeColor',[0.5 0.5 0.5]); +end +text(ax3d, Lc/2-5, Lc/2, Lc/2+5.5,'Audifono', ... + 'Color',[0.7 0.7 0.7],'FontSize',8); + +% Modulo laser KY-008 +laser_pos = [35, 4, 10]; +[xl,yl,zl] = cylinder(0.8,20); +surf(ax3d, xl*3+laser_pos(1), yl+laser_pos(2), zl+laser_pos(3), ... + 'FaceColor',[0.15 0.65 0.15],'EdgeColor','none','FaceAlpha',0.92); +text(ax3d, laser_pos(1)+0.5, laser_pos(2)-0.5, laser_pos(3)-2.2,'Laser KY-008', ... + 'Color',[0.3 1.0 0.3],'FontSize',8,'FontWeight','bold'); + +% Punto de impacto en vidrio +P_imp = [Lc, 10, 10]; + +% Haz laser (rojo solido) +h_haz_ida = plot3(ax3d, ... + [laser_pos(1) P_imp(1)], ... + [laser_pos(2) P_imp(2)], ... + [laser_pos(3) P_imp(3)], ... + 'r-','LineWidth',2.5); + +% Reflexion hacia BPW34 +v_inc = (P_imp - laser_pos) / norm(P_imp - laser_pos); +n_vid = [-1 0 0]; +v_ref = v_inc - 2*dot(v_inc,n_vid)*n_vid; +bpw34_pos = P_imp + 12*v_ref; + +h_haz_ref = plot3(ax3d, ... + [P_imp(1) bpw34_pos(1)], ... + [P_imp(2) bpw34_pos(2)], ... + [P_imp(3) bpw34_pos(3)], ... + 'r--','LineWidth',1.8); + +% Punto de impacto +plot3(ax3d, P_imp(1),P_imp(2),P_imp(3),'y*','MarkerSize',12,'LineWidth',2); + +% BPW34 (caja negra) +dibujar_caja(ax3d, bpw34_pos(1)-1.2, bpw34_pos(2)-1.2, bpw34_pos(3)-1.2, ... + 2.4, 2.4, 2.4, [0.08 0.08 0.08], 0.92); +text(ax3d, bpw34_pos(1), bpw34_pos(2), bpw34_pos(3)+3.2,'BPW34', ... + 'Color',[1.0 0.85 0.1],'FontSize',9,'FontWeight','bold','HorizontalAlignment','center'); + +% Tubo negro (proteccion de luz ambiente) +[xt,yt,zt] = cylinder(1.5,20); +surf(ax3d, xt+bpw34_pos(1), yt+bpw34_pos(2), zt*5+bpw34_pos(3)-2.5, ... + 'FaceColor',[0.07 0.07 0.07],'EdgeColor','none','FaceAlpha',0.55); + +% Protoboard + LM358 TIA +proto = [37, 14, 4]; +dibujar_caja(ax3d, proto(1), proto(2), proto(3), 9, 5, 0.6, [0.1 0.5 0.1], 0.85); +text(ax3d, proto(1)+4.5, proto(2)+2.5, proto(3)+2,'LM358 TIA', ... + 'Color',[0.4 1.0 0.4],'FontSize',8,'HorizontalAlignment','center'); + +% Cable BPW34 → TIA +plot3(ax3d,[bpw34_pos(1) proto(1)+4], ... + [bpw34_pos(2) proto(2)+2], ... + [bpw34_pos(3) proto(3)+0.5], ... + 'Color',[1 0.55 0.1],'LineWidth',1.5,'LineStyle',':'); + +% MAX9814 +maxp = [37, 21, 4]; +dibujar_caja(ax3d, maxp(1), maxp(2), maxp(3), 7, 4, 1.2, [0.45 0.1 0.55], 0.88); +text(ax3d, maxp(1)+3.5, maxp(2)+2, maxp(3)+2.8,'MAX9814', ... + 'Color',[0.9 0.5 1.0],'FontSize',8,'HorizontalAlignment','center'); + +% Cable TIA → MAX9814 +plot3(ax3d,[proto(1)+4 maxp(1)+3], ... + [proto(2)+5 maxp(2)], ... + [proto(3)+0.5 maxp(3)+0.6], ... + 'Color',[1 0.55 0.1],'LineWidth',1.5,'LineStyle',':'); + +% Laptop +pcp = [46, 14, 4]; +% Pantalla +fill3(ax3d,[pcp(1) pcp(1)+9 pcp(1)+9 pcp(1)], ... + [pcp(2) pcp(2) pcp(2) pcp(2)], ... + [pcp(3) pcp(3) pcp(3)+8 pcp(3)+8], ... + [0.1 0.1 0.16],'EdgeColor',[0.5 0.5 0.5],'FaceAlpha',0.92); +fill3(ax3d,[pcp(1)+0.5 pcp(1)+8.5 pcp(1)+8.5 pcp(1)+0.5], ... + [pcp(2)-0.1 pcp(2)-0.1 pcp(2)-0.1 pcp(2)-0.1], ... + [pcp(3)+0.5 pcp(3)+0.5 pcp(3)+7.5 pcp(3)+7.5], ... + [0.05 0.3 0.4],'EdgeColor','none','FaceAlpha',0.85); +% Base +fill3(ax3d,[pcp(1) pcp(1)+9 pcp(1)+9 pcp(1)], ... + [pcp(2) pcp(2) pcp(2)+4 pcp(2)+4], ... + [pcp(3) pcp(3) pcp(3) pcp(3)], ... + [0.2 0.2 0.2],'EdgeColor',[0.5 0.5 0.5],'FaceAlpha',0.92); +text(ax3d, pcp(1)+4.5, pcp(2)-1.2, pcp(3)+4,'PC + MATLAB', ... + 'Color',[0.3 0.85 1.0],'FontSize',9,'FontWeight','bold','HorizontalAlignment','center'); + +% Cable MAX9814 → PC +plot3(ax3d,[maxp(1)+7 pcp(1)], ... + [maxp(2)+2 pcp(2)+2], ... + [maxp(3)+0.6 pcp(3)+0.5], ... + 'Color',[0.7 0.7 0.7],'LineWidth',2); + +% Leyenda +legend(ax3d,[h_haz_ida,h_haz_ref], ... + {'Haz laser (650nm)','Reflexion hacia BPW34'}, ... + 'Location','northeast','TextColor','w', ... + 'Color',[0.1 0.1 0.15],'EdgeColor',[0.4 0.4 0.4]); + +%% ═══════════════════════════════════════════════════════ +% SUBPLOTS INFERIORES DE SENAL +%% ═══════════════════════════════════════════════════════ +c_audio = [1.0 0.7 0.1]; +c_foto = [1.0 0.4 0.3]; +c_tia = [0.3 0.8 1.0]; +c_rec = [0.4 1.0 0.4]; + +ax_audio = subplot('Position',[0.02 0.03 0.22 0.28]); +ax_ifoto = subplot('Position',[0.26 0.03 0.22 0.28]); +ax_tia = subplot('Position',[0.50 0.03 0.22 0.28]); +ax_fft = subplot('Position',[0.74 0.03 0.24 0.28]); + +function setup_ax(ax, ttl, col) + set(ax,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w', ... + 'GridColor',[0.15 0.15 0.15],'FontSize',8); + grid(ax,'on'); + title(ax, ttl,'Color',col,'FontWeight','bold','FontSize',9); + xlabel(ax,'Tiempo (s)','Color','w','FontSize',8); +end + +setup_ax(ax_audio,'Audio en la caja', c_audio); +setup_ax(ax_ifoto,'BPW34 — I_{foto} (uA)', c_foto); +setup_ax(ax_tia, 'V_{TIA} + MAX9814 (mV)', c_tia); +setup_ax(ax_fft, 'FFT — Espectro', c_rec); + +n_win = round(fs * 0.012); % ventana de 12 ms +t_win = t(1:n_win); + +h_l_audio = plot(ax_audio, t_win, audio_original(1:n_win), 'Color',c_audio,'LineWidth',1.2); +h_l_ifoto = plot(ax_ifoto, t_win, I_foto(1:n_win)*1e6, 'Color',c_foto, 'LineWidth',1.2); +h_l_tia = plot(ax_tia, t_win, V_tia(1:n_win)*1e3, 'Color',c_tia, 'LineWidth',1.2); + +ylim(ax_audio,[-1.3 1.3]); +ylim(ax_ifoto,[min(I_foto)*1e6*1.05 max(I_foto)*1e6*1.05]); +ylim(ax_tia, [min(V_tia)*1e3*1.1 max(V_tia)*1e3*1.1]); + +% FFT estatica +f_vec = (0:floor(N/2)) * fs / N; +mag = abs(Y(1:floor(N/2)+1)) / N; +mag(2:end-1) = 2*mag(2:end-1); +plot(ax_fft, f_vec, mag,'Color',c_rec,'LineWidth',0.9); +xlim(ax_fft,[0 2000]); +set(ax_fft,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w','GridColor',[0.15 0.15 0.15]); +grid(ax_fft,'on'); +title(ax_fft,'FFT — Espectro','Color',c_rec,'FontWeight','bold','FontSize',9); +xlabel(ax_fft,'Frecuencia (Hz)','Color','w','FontSize',8); +hold(ax_fft,'on'); +for fi = [f1 f2 f3] + [~,idx_fi] = min(abs(f_vec - fi)); + plot(ax_fft, fi, mag(idx_fi),'w^','MarkerSize',7,'MarkerFaceColor','w'); + text(ax_fft, fi, mag(idx_fi)*1.12, sprintf('%.0fHz',fi), ... + 'Color','w','FontSize',7,'HorizontalAlignment','center'); +end + +%% ═══════════════════════════════════════════════════════ +% ANIMACION +%% ═══════════════════════════════════════════════════════ +fprintf(' Iniciando animacion (presiona Q para salir)...\n\n'); + +paso = round(fs/30); % ~30 fps +n_frm = floor(N / paso); +amp_v = 0.25; % cm vibracion max del vidrio + +for k = 1:n_frm + + if ~ishandle(fig) || getappdata(fig,'salir'), break; end + + i0 = (k-1)*paso + 1; + i1 = min(i0 + n_win - 1, N); + idx = i0:i1; + + if length(idx) < n_win, break; end + + % Vibracion del vidrio + desp = amp_v * audio_original(i0); + set(h_vidrio,'XData',(Lc + desp)*ones(size(yv))); + + % Haz laser sigue el punto de impacto + P_imp_k = [Lc + desp, P_imp(2), P_imp(3)]; + set(h_haz_ida,'XData',[laser_pos(1) P_imp_k(1)], ... + 'YData',[laser_pos(2) P_imp_k(2)], ... + 'ZData',[laser_pos(3) P_imp_k(3)]); + set(h_haz_ref,'XData',[P_imp_k(1) bpw34_pos(1)], ... + 'YData',[P_imp_k(2) bpw34_pos(2)], ... + 'ZData',[P_imp_k(3) bpw34_pos(3)]); + + % Actualizar graficas + tw = t(idx); + set(h_l_audio,'XData',tw,'YData',audio_original(idx)); + set(h_l_ifoto,'XData',tw,'YData',I_foto(idx)*1e6); + set(h_l_tia, 'XData',tw,'YData',V_tia(idx)*1e3); + xlim(ax_audio,[tw(1) tw(end)]); + xlim(ax_ifoto,[tw(1) tw(end)]); + xlim(ax_tia, [tw(1) tw(end)]); + + title(ax3d, sprintf('Montaje 3D — t = %.3f s | P_{laser} = %.5f W', ... + t(i0), P_luz(i0)), ... + 'Color',[1 0.7 0.1],'FontWeight','bold','FontSize',11); + + drawnow limitrate; +end + +%% ═══════════════════════════════════════════════════════ +% FIGURA FINAL: RECONSTRUCCION +%% ═══════════════════════════════════════════════════════ +fprintf(' Animacion terminada.\n\n'); + +figure('Name','Reconstruccion FFT','NumberTitle','off', ... + 'Position',[80 80 1300 750],'Color',[0.05 0.05 0.08]); + +subplot(3,1,1); +plot(t, audio_original,'Color',c_audio,'LineWidth',0.8); +set(gca,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w','GridColor',[0.15 0.15 0.15]); +grid on; +title('Audio original dentro de la caja','Color',c_audio,'FontWeight','bold','FontSize',11); +xlabel('Tiempo (s)','Color','w'); ylabel('Amplitud','Color','w'); +xlim([0 duracion]); + +subplot(3,1,2); +plot(t, V_max,'Color',c_tia,'LineWidth',0.8); +set(gca,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w','GridColor',[0.15 0.15 0.15]); +grid on; +title('Senal capturada (MAX9814 out)','Color',c_tia,'FontWeight','bold','FontSize',11); +xlabel('Tiempo (s)','Color','w'); ylabel('V (V)','Color','w'); +xlim([0 duracion]); + +subplot(3,1,3); +plot(t, V_rec_escalado,'Color',c_rec,'LineWidth',0.8); +set(gca,'Color',[0.05 0.05 0.08],'XColor','w','YColor','w','GridColor',[0.15 0.15 0.15]); +grid on; +title(sprintf('Senal reconstruida (IFFT) — correlacion: %.4f', rho), ... + 'Color',c_rec,'FontWeight','bold','FontSize',11); +xlabel('Tiempo (s)','Color','w'); ylabel('Amplitud','Color','w'); +xlim([0 duracion]); + +V_play = V_rec_escalado / max(abs(V_rec_escalado) + 1e-10); +fprintf(' Reproduciendo senal reconstruida...\n'); +sound(V_play, fs); + +fprintf('\n╔══════════════════════════════════════════════════════╗\n'); +fprintf('║ Simulacion completada ║\n'); +fprintf('║ Correlacion original / reconstruido: %.4f ║\n', rho); +fprintf('╚══════════════════════════════════════════════════════╝\n'); \ No newline at end of file