Sound Reconstruction with a Laser and a Photosensor: From Theory to Code
By B.E. Alejandro
The Problem: Can a Beam of Light Carry Sound?
The idea came from a deceptively simple question in physics class: if sound is a mechanical wave that vibrates air, could that vibration modulate a beam of light and be recovered afterward?
The answer is yes, and the principle is elegant. Sound inside a soundproofed box makes a glass panel vibrate. A 650 nm laser points at the glass from outside; the reflection, modulated by the vibrations, is captured by a BPW34 photodiode. The resulting photocurrent passes through a transimpedance amplifier (LM358 TIA) that converts it to voltage, then through a MAX9814 with automatic gain control (AGC), and finally reaches the PC’s microphone jack, where MATLAB digitizes it and reconstructs the original audio:
$$V(t) = A \cdot \sin(2\pi f t) + \eta(t)$$
where $\eta(t)$ is the noise introduced by the optical-electronic system. That’s precisely the challenge: given that $\eta(t)$ always exists, how do we recover the signal $A \cdot \sin(2\pi f t)$ with the highest possible fidelity?
This post documents the full simulation phase in MATLAB that validates the algorithms before building the actual hardware.
Theoretical Foundations
Fourier Transform (FFT)
Fourier’s theorem establishes that any periodic signal can be decomposed as a sum of sines and cosines. The Discrete Fourier Transform (DFT) does this numerically:
$$X[k] = \sum_{n=0}^{N-1} x[n] \cdot e^{-j2\pi kn/N}$$
The FFT (Fast Fourier Transform) is an efficient algorithm for computing the DFT in $O(N \log N)$ instead of $O(N^2)$. For this project, the FFT serves two purposes:
- Identify which frequencies make up the captured signal
- Filter noise by removing weak spectral components
Singular Value Decomposition (SVD)
Since the project connects to the semester’s vector spaces topic, I also applied SVD to analyze the structure of each signal. Given a trajectory matrix $M$ built from the signal:
$$M = U \cdot \Sigma \cdot V^T$$
The singular values $\sigma_i$ in $\Sigma$ reveal how many “independent modes” the signal needs to be represented. A simple signal (pure tone) has very few large singular values; a complex signal has them spread out.
Connection to the course: SVD is essentially an orthogonal change of basis. The column vectors of $U$ are the new basis in the signal’s space, and the singular values are the “importance coordinates” of each basis vector. Exactly the same orthonormal basis concept we saw in class.
The Hardware
The physical system to be simulated and built is made up of the following components, chosen for their precision and low noise:
| Component | Function | Key Parameter |
|---|---|---|
| D18×65mm 650nm 5mW Laser | Continuous-point light source | Focusable, mounted on a Neiko stand ~30° |
| BPW34 (PIN photodiode) | Light → current | R = 0.3 A/W @ 650 nm, in a black tube |
| LM358 (TIA) | Current → voltage | Rf = 10 kΩ, Cf = 100 pF |
| C_ac 10 µF capacitor | DC offset blocking | fc = 1.6 Hz |
| MAX9814 HiLetgo | AGC amplifier | Av = 40 dB (floating GAIN) |
| C_out 47 µF capacitor | Output offset blocking | fc = 0.34 Hz |
| ShillehTek 3.5mm jack module | PC interface | Microphone input, TRRS breakout |
| ESP32 | 5V power supply | VIN pin → protoboard rail |
| Neiko stand | Position the laser at an angle | ~30° adjustment over the glass |
The main advantage of the BPW34 over an LDR is its response time: 20 ns versus ~1 ms, allowing it to capture audio up to 20 kHz with no degradation from the sensor.
Circuit Diagram

Experimental Setup

The 3D scene shows the full setup: a soundproofed box with a vibrating glass panel, an industrial D18×65 mm laser on a Neiko stand aimed at the glass at ~30°, the BPW34 in a black tube at the specular reflection angle, and the full circuit (ESP32 + LM358 + MAX9814 + jack module) on the protoboard. The animation syncs the glass vibration with the real-time signals at each stage of the pipeline.
Simulation Methodology
To validate the algorithms without hardware, I generated four types of signal in MATLAB and simulated the complete process through the real optical-electronic pipeline: generation → optical modulation → BPW34 → TIA → MAX9814 → FFT filtering → reconstruction → validation.
Unlike simply adding Gaussian noise, the model simulates the entire physical chain:
function v_out =
% 1. Optical modulation: the vibrating glass modulates the reflection
= * ;
% 2. BPW34: photocurrent = responsivity x power + shot noise
= * + * 1e-4 * randn;
% 3. LM358 TIA: I → V, remove DC offset (like the C_ac capacitor)
= * ;
= - mean;
% 4. MAX9814: amplify and clip (±1.65V)
= * ;
= max;
end
The BPW34’s noise (shot noise) is just 0.8% of the signal — notably lower than the ~5% typical of an LDR, which explains the higher SNR results.
The Four Test Signals
| Signal | Frequencies | Why it’s interesting |
|---|---|---|
| Pure tone | 1000 Hz | Baseline case, simplest possible signal |
| C Major chord | 262 + 330 + 392 Hz | Three simultaneous frequencies (C, E, G) |
| Sweep (chirp) | 100 → 1000 Hz | Time-varying frequency |
| Complex signal | 262·k Hz, k=1..5 | Harmonic series, simulates a human voice |
The Reconstruction Algorithm
The core of the system is spectral filtering: a binary mask is applied to the FFT spectrum that keeps only the components above 10% of the peak magnitude, and the signal is then reconstructed with the IFFT. The key is preserving the spectrum’s Hermitian symmetry so the IFFT returns real values:
function senial_rec =
= length;
= fft;
% Magnitude of the one-sided spectrum (DC up to and including Nyquist)
= abs;
= max * 0.1;
% Binary mask: 1 where the signal exceeds the threshold
= double;
% Full mask with Hermitian symmetry for a real-valued signal
= zeros;
= ;
= flipud;
= real;
end
A mistake I made: in earlier versions I used
N/2directly for indexing, which broke wheneverNwas odd. The correct fix isfloor(N/2)in every index, and building the conjugate symmetry explicitly. This guarantees the mask has exactlyNelements regardless of the parity of the signal length.
Results
Full Plots
The following figure shows the complete pipeline for all four signals: ideal signal → signal captured by the sensor (BPW34→MAX9814) → reconstructed signal → FFT spectrum with the resulting SNR.

The most striking visual result: the “Reconstructed” column (green) recovers the waveform with a fidelity that makes the result almost indistinguishable from the original, despite the visible noise in the “Captured” column.
Quantitative Metrics
To avoid relying solely on visual inspection, I computed three error metrics for each signal. The reconstructed signal is scaled before comparison (least-squares inner product) to separate phase/shape error from amplitude error:
| Signal | RMS Error | SNR (dB) | Correlation | Result |
|---|---|---|---|---|
| Pure tone | 2.79 × 10⁻⁶ | 102.1 dB | 1.0000 | Excellent |
| Chord | 2.87 × 10⁻⁴ | 62.1 dB | 1.0000 | Excellent |
| Sweep | 1.06 × 10⁻² | 30.5 dB | 0.9996 | Very good |
| Complex | 3.00 × 10⁻⁴ | 63.1 dB | 1.0000 | Excellent |
Reference: in audio, an SNR above 20 dB is already considered acceptable for voice playback. Above 40 dB is transparent to the human ear under most conditions. This system’s results range from 30.5 to 102.1 dB.
SVD Analysis

The singular value analysis confirms the theoretical intuition about the complexity of each signal:
| Signal | Cumulative variance in 5 modes | |
|---|---|---|
| Pure tone | 99.0% | nearly all the energy in 1–2 modes |
| Chord | 84.3% | ~3 significant modes (one per frequency) |
| Sweep | 9.3% | energy very spread out |
| Complex | 88.6% | several modes (harmonics) |
The sweep case is the most revealing: since the frequency changes continuously from 100 to 1000 Hz over 3 seconds, no fixed mode can capture the signal well. It needs hundreds of singular vectors to be represented faithfully. This mathematically explains why it has the lowest SNR: a fixed-threshold FFT filter isn’t the best tool for time-varying signals.
The Full Code
The complete script is available in the project’s repository:
Source code: script_prueba_demostracion.m — MATLAB R2016b or later, requires the Signal Processing Toolbox.
Conclusions
The simulation results are clear:
FFT spectral filtering works. SNR of up to 102.1 dB for the pure tone and a correlation of 1.0000 for three of the four signals. The system recovers the waveform with enough fidelity for audio playback.
The hardest signal is the sweep (chirp). At 30.5 dB and a correlation of 0.9996, it’s still very good, but it exposes the limitation of the fixed-threshold filter: it’s not the best choice for signals whose frequency varies over time. The STFT (Short-Time Fourier Transform) or a Wavelet transform would be better tools for that case.
SVD confirms vector-space theory. The effective rank of the signal (as measured by the singular values) directly reflects its complexity: 1–2 modes for the pure tone, hundreds for the sweep.
The BPW34 outperforms the LDR. The BPW34’s shot noise is just 0.8% of the signal, versus the ~5% typical of an LDR. This translates directly into a higher SNR and more faithful reconstruction.
The simulation validates the architecture before the hardware. I now know the algorithms work. I can build the real system with confidence.
Next Steps
The hardware is defined and on its way:
- Physical assembly: D18×65mm laser on a Neiko stand, BPW34 in a black tube, circuit on an 830-point protoboard
- First real capture: compare experimental SNR against the simulated one (target: >20 dB)
- Test signals: pure tone from a generator, then voice, then music
- Future work: STFT to improve reconstruction of the chirp and other time-varying signals
The next post will document the hardware build and the first real audio capture.
This project is part of the Physics II course (Waves, Oscillations, and Vector Spaces), second semester. All the code is freely available on GitHub.