DSP · Wireless · ESP32 · Real-Time Audio

Digital
Walkie-Talkie

Full-duplex real-time voice communication between two ESP32 nodes over ESP-NOW — no router, no infrastructure. I2S digital microphone → frame segmentation → Spectral Subtraction + NLMS DSP chain → I2S amplifier output.

~4ms
TX Latency
8kHz
Sample Rate
~12dB
SNR Gain
~200m
Range
LEADER: Ahmed Abdulrazeq  |  TEAM: Islam Emad Ismail · Refaat Elsayed Refaat · Omar Tarek Elmaghawri · Omar Ahmed Desokey · Mohammed Reda Alasmar · Omar Alaa Zaghloul  |  SUPERVISOR: Dr. Rania Al-Abd
Hardware Overview

Component Diagram

Both devices share the same hardware layout. The transmitter path goes through the microphone; the receiver path routes to the amplifier and speaker.

TRANSMITTER I2S MIC INMP441 Digital PDM I2S ESP32 TX NODE CPU WiFi Frame segmentation ESP-NOW TX 2.4GHz ANT External WIRELESS CHANNEL ESP-NOW Protocol 802.11 2.4GHz · No AP RECEIVER ANT External 2.4GHz ESP32 RX NODE DSP WiFi Spec.Sub + NLMS Audio reconstruct I2S AMP MAX98357 I2S Class D SPEAKER 4Ω 3W ① Capture ② Sample+Frame ③ Transmit ④ Wireless Hop ⑤ Receive ⑥ DSP Denoise ⑦ Output DSP CHAIN (RX NODE): ① Frame RX ESP-NOW ② Spectral Sub Stationary noise ③ NLMS Filter Adaptive noise ④ DAC / I2S Reconstruct ⑤ Speaker Clean audio out
ESP32 (×2)
Dual-core Xtensa LX6 · 240MHz · Built-in 2.4GHz WiFi chipset
I2S Microphone (INMP441)
Digital MEMS microphone · I2S PDM output · 24-bit · SNR 61dB
MAX98357A Amplifier
I2S input Class-D amp · 3.2W output · Single supply · No external components
External Antenna (×2)
2.4GHz directional antenna · SMA connector · ~4dBi gain · Extends range to ~200m
4Ω 3W Speaker
Full-range speaker driver matched to MAX98357A output
DSP Software (ESP32)
Spectral Subtraction + NLMS adaptive filter running bare-metal on core 1
Interactive Simulation

DSP Pipeline

Visualize how Spectral Subtraction and NLMS filtering clean the noisy audio signal in real time.

Audio Waveform Monitor LIVE
SNR: —
FREQUENCY SPECTRUM (0–4kHz)
Processing Chain — Latency Breakdown
① I2S Capture & Sampling ~0.125ms / frame
I2S DMA reads 16 samples from INMP441 at 8kHz. PDM to PCM decimation. 16-bit fixed-point buffer.
fs = 8000 Hz · frame = 16 samples · t_frame = 2ms
② ESP-NOW Transmission ~4ms
Frame packed as raw byte payload. ESP-NOW sends directly to MAC address — no AP, no DHCP, no IP overhead. One-way latency ≈ 4ms at 10m.
Protocol: IEEE 802.11 · Payload: 250 bytes max · Mode: Station
③ Spectral Subtraction ~6ms
FFT → estimate noise PSD in silence frames → subtract noise magnitude from signal magnitude → IFFT reconstruct. Removes stationary background noise (fan, HVAC).
|Ŝ(ω)| = |X(ω)| − α·|N̂(ω)| · ĉlamp to 0
④ NLMS Adaptive Filter ~3ms
Normalized Least Mean Squares adapts filter coefficients frame-by-frame to cancel dynamic noise (wind, movement). Converges in ~50ms after startup.
w(n+1) = w(n) + μ·e(n)·x(n) / (||x(n)||² + ε)
⑤ DAC / I2S Output ~2ms
Cleaned PCM samples streamed to MAX98357A via I2S. Class-D amplification to 4Ω speaker. Total pipeline: ~15ms end-to-end.
Total: 4ms (TX) + 9ms (DSP) + 2ms (DAC) = ~15ms
Technical Specifications

System Specs

📡
ESP-NOW Protocol
Peer-to-peer 802.11 protocol bypassing full WiFi stack. Sub-10ms latency without router.
Frequency2.4GHz IEEE 802.11
Max Payload250 bytes/frame
Latency~4ms @ 10m
Range (w/ ant)~200m LOS
AuthMAC pairing
🔊
Audio Chain
Digital audio path — no analog conversion until final output stage. Maximum SNR preservation.
Sample Rate8kHz (voice)
Bit Depth16-bit PCM
Frame Size16 samples
InterfaceI2S (full duplex)
SNR gain~12dB (DSP)
Hardware
Compact portable design. Low power consumption. Battery operable for field deployment.
MCUESP32 (×2 nodes)
MicrophoneINMP441 I2S MEMS
AmplifierMAX98357A I2S
Speaker4Ω 3W full-range
Power3.3V / 5V USB
/* NEON RIBBON */ (function(){ const canvas=document.getElementById('ribbon-canvas'); if(!canvas)return; const ctx=canvas.getContext('2d'); const CFG={SPEED_X:.14,SPEED_Y:.14,MAX_LENGTH:90,RS:.018,GS:.013,BS:.022,SPREAD:16}; let anim=0,W=0,H=0; const pts=[],mouse={x:0,y:0},prev={x:0,y:0},cs={r:0,g:200,b:255,sz:0}; function resize(){W=canvas.width=innerWidth;H=canvas.height=innerHeight} resize();window.addEventListener('resize',resize,{passive:true}); document.addEventListener('mousemove',e=>{mouse.x=e.clientX;mouse.y=e.clientY},{passive:true}); mouse.x=prev.x=innerWidth/2;mouse.y=prev.y=innerHeight/2; function sp(p){p.x+=p.dx;p.y+=p.dy} function dl(){ const n=pts.length;if(n<3)return; for(let i=n-1;i>1;i--){ const p0=pts[i],p1=pts[i-1],p2=pts[i-2]; ctx.beginPath();ctx.strokeStyle=p0.color;ctx.lineWidth=p0.sz;ctx.globalAlpha=i/n; ctx.moveTo((p1.x+p0.x)/2,(p1.y+p0.y)/2); ctx.quadraticCurveTo(p1.x,p1.y,(p1.x+p2.x)/2,(p1.y+p2.y)/2);ctx.stroke();sp(p0); } if(pts[0])sp(pts[0]);if(pts[n-1])sp(pts[n-1]); } function draw(){ let dx=Math.max(-CFG.SPREAD,Math.min(CFG.SPREAD,(mouse.x-prev.x)*CFG.SPEED_X)); let dy=Math.max(-CFG.SPREAD,Math.min(CFG.SPREAD,(mouse.y-prev.y)*CFG.SPEED_Y)); prev.x=mouse.x;prev.y=mouse.y;cs.sz+=.12;cs.r+=CFG.RS;cs.g+=CFG.GS;cs.b+=CFG.BS; const sz=Math.abs(Math.sin(cs.sz)*8)+1; const r=Math.floor(Math.sin(cs.r)*128+128),g=Math.floor(Math.sin(cs.g)*128+128),b=Math.floor(Math.sin(cs.b)*128+128); pts.push({x:mouse.x,y:mouse.y,dx,dy,sz,color:`rgb(${r},${g},${b})`}); if(pts.length>CFG.MAX_LENGTH)pts.shift(); ctx.globalCompositeOperation='source-over';ctx.globalAlpha=1; ctx.fillStyle='rgba(0,0,0,.05)';ctx.fillRect(0,0,W,H); ctx.globalCompositeOperation='lighter';dl();dl();dl(); anim=requestAnimationFrame(draw); } draw(); document.addEventListener('visibilitychange',()=>{if(document.hidden)cancelAnimationFrame(anim);else draw()}); })(); /* 3D TILT on cards */ document.querySelectorAll('.spec-card,.feature-card,.stat-card,.phase-card,.card,.metric-card,.tech-card,.detail-card,.comp-card,.step-card,.challenge-card').forEach(card=>{ card.style.transition='transform .32s ease,box-shadow .32s'; card.addEventListener('mousemove',e=>{ const r=card.getBoundingClientRect(); const x=(e.clientX-r.left)/r.width-.5,y=(e.clientY-r.top)/r.height-.5; card.style.transform=`perspective(820px) rotateX(${-y*8}deg) rotateY(${x*10}deg) scale3d(1.015,1.015,1.015)`; },{passive:true}); card.addEventListener('mouseleave',()=>{card.style.transform='perspective(820px) rotateX(0) rotateY(0) scale3d(1,1,1)'}); }); /* CIPHER TEXT on section headings */ (function(){ const CHARS='ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789#@!%'; function cipher(el,target,delay){ setTimeout(()=>{ let frame=0;const total=Math.floor(1000/30); const id=setInterval(()=>{ const prog=frame/total;let out=''; for(let i=0;i(i/target.length)?target[i]:CHARS[Math.floor(Math.random()*CHARS.length)]; el.textContent=out; if(frame>=total){clearInterval(id);el.textContent=target} frame++; },30); },delay); } const ro=new IntersectionObserver(entries=>{ entries.forEach(e=>{ if(e.isIntersecting){ const el=e.target; const orig=el.dataset.cipherText||el.textContent; el.dataset.cipherText=orig; cipher(el,orig,0); ro.unobserve(el); } }); },{threshold:.3}); document.querySelectorAll('h2,h3').forEach(h=>{ if(h.textContent.trim().length<60)ro.observe(h); }); })();