Project 12: Digital Theremin

Build a touchless digital theremin that uses capacitive sensing for pitch/volume and generates real-time audio.

Quick Reference

Attribute Value
Difficulty Level 3: Advanced
Time Estimate 2-3 weeks
Main Programming Language C
Alternative Programming Languages MicroPython
Coolness Level Level 4: Musical Magic
Business Potential 3. The “Interactive Art” Tier
Prerequisites ADC basics, PWM, signal timing
Key Topics Capacitive sensing, audio synthesis, PWM/DAC output

1. Learning Objectives

By completing this project, you will:

  1. Implement capacitive sensing using RC timing.
  2. Convert sensor values to pitch and volume.
  3. Generate audio waveforms in real time.
  4. Output audio via PWM or DAC with filtering.
  5. Smooth jitter to produce stable tones.

2. All Theory Needed (Per-Concept Breakdown)

2.1 Capacitive Sensing with RC Timing

Fundamentals

Capacitive sensing measures changes in capacitance caused by a nearby hand. An RC circuit’s time constant changes with capacitance, allowing you to measure proximity by timing how long it takes to charge or discharge.

Deep Dive into the concept

A simple capacitive sensor uses a resistor and a conductive pad. The pad’s capacitance increases when a hand approaches, slowing the charge time. You can measure this by toggling a GPIO pin and timing how long it takes for another pin to reach a threshold. The RP2040 can do this with precise timers or PIO. Noise is a major challenge: environmental changes, humidity, and body coupling affect readings. You must calibrate a baseline at startup and apply filtering to smooth jitter. The sensor should be stable but responsive; typical update rates are 50-200 Hz. Shielding and stable wiring improve results. This project uses two sensors (pitch and volume), so you must ensure they do not interfere with each other.

How this fits on projects

Capacitive sensing drives §3.2 requirements and §5.10 Phase 1.

Definitions & key terms

  • RC time constant -> R * C, controls charge rate
  • Baseline -> reference value for no hand present
  • Threshold -> point at which a voltage is considered “charged”

Mental model diagram (ASCII)

GPIO -> [R] -> Sensor Pad -> GND
         ^ measure charge time

How it works (step-by-step)

  1. Discharge sensor pad.
  2. Start timing and charge through resistor.
  3. Detect when input crosses threshold.
  4. Map time to distance.

Minimal concrete example

gpio_put(drive, 1);
uint32_t t = time_us_32();
while (!gpio_get(sense)) {}
uint32_t dt = time_us_32() - t;

Common misconceptions

  • “Capacitive sensing is precise” -> it’s noisy and environment-dependent.
  • “No calibration needed” -> baseline drift is significant.

Check-your-understanding questions

  1. Why does capacitance affect charge time?
  2. How do you calibrate a baseline?
  3. What causes jitter in readings?

Check-your-understanding answers

  1. More capacitance increases RC time constant.
  2. Sample initial readings and set as reference.
  3. Environmental noise, EMI, and hand movement.

Real-world applications

  • Touchless controls, touchpads, proximity sensors.

Where you’ll apply it

References

  • Capacitive sensing app notes

Key insights

Capacitive sensing is timing-based and must be filtered for stability.

Summary

Measure RC charge time and apply calibration to sense proximity.

Homework/Exercises to practice the concept

  1. Measure baseline charge time in different rooms.
  2. Compare different resistor values for sensitivity.

Solutions to the homework/exercises

  1. Values drift with humidity and nearby objects.
  2. Higher resistance increases sensitivity but slows response.

2.2 Waveform Synthesis and Pitch Mapping

Fundamentals

A theremin generates sound by outputting a waveform at a frequency determined by hand position. Mapping sensor values to musical pitch requires scaling and often logarithmic mapping.

Deep Dive into the concept

Human pitch perception is logarithmic: equal frequency ratios sound like equal musical intervals. That means you should map distance to frequency exponentially, not linearly. You can convert a sensor value to a frequency using a formula like f = f0 * 2^(x) where x is scaled from the sensor range. Waveform synthesis can be done by generating samples for a sine, square, or triangle wave at a fixed sample rate. A lookup table (wavetable) is efficient: you advance a phase accumulator by phase += freq * table_size / sample_rate. The output sample is table[phase]. This method is fast and stable on a microcontroller.

How this fits on projects

Waveform synthesis is required in §3.2 and §5.10 Phase 2.

Definitions & key terms

  • Wavetable -> precomputed waveform samples
  • Phase accumulator -> index into wavetable
  • Log mapping -> exponential mapping to pitch

Mental model diagram (ASCII)

Sensor value -> Frequency -> Phase -> Waveform sample

How it works (step-by-step)

  1. Normalize sensor value to 0..1.
  2. Map to frequency using exponential scale.
  3. Advance phase accumulator.
  4. Output waveform sample.

Minimal concrete example

phase += (freq * TABLE_SIZE) / SAMPLE_RATE;
output = table[phase % TABLE_SIZE];

Common misconceptions

  • “Linear mapping sounds fine” -> it feels uneven across range.
  • “Sine wave is required” -> other waves are valid for character.

Check-your-understanding questions

  1. Why use exponential mapping for pitch?
  2. How does a phase accumulator work?
  3. What sets the maximum frequency?

Check-your-understanding answers

  1. Human perception is logarithmic.
  2. It advances through a waveform table based on frequency.
  3. The audio sample rate and Nyquist limit.

Real-world applications

  • Synthesizers, musical instruments, DSP effects.

Where you’ll apply it

References

  • DSP basics texts

Key insights

Pitch mapping is a perceptual problem, not just a numeric one.

Summary

Map sensor values to frequency with exponential scaling and generate waveforms via a phase accumulator.

Homework/Exercises to practice the concept

  1. Build a 256-sample sine wavetable.
  2. Map sensor values to musical notes (A4=440 Hz).

Solutions to the homework/exercises

  1. Use sin(2pii/256) scaled to 0-255.
  2. Use f = 440 * 2^(n/12) for semitone steps.

2.3 PWM Audio Output and Filtering

Fundamentals

PWM can approximate analog audio by varying duty cycle at a high carrier frequency. A low-pass filter smooths the PWM into an audio waveform.

Deep Dive into the concept

PWM audio uses a high-frequency carrier (e.g., 100-200 kHz). The duty cycle corresponds to the audio sample amplitude. The speaker or an RC filter integrates the PWM into a smoother signal. If the PWM frequency is too low, you hear the carrier as a whine. If it’s too high, you may exceed the PWM resolution or output driver limits. The RP2040 PWM peripheral can generate high-frequency PWM with reasonable resolution, but you must choose a balance: higher frequency reduces audible noise but reduces bit depth. You can improve output with a simple RC filter or an audio amplifier module. Buffering audio samples and updating duty cycle at a fixed sample rate (e.g., 22 kHz) yields stable audio.

How this fits on projects

Audio output is required for §3.2 and §5.10 Phase 3.

Definitions & key terms

  • Carrier frequency -> PWM base frequency
  • Low-pass filter -> removes high-frequency carrier
  • Duty cycle -> percentage of time signal is high

Mental model diagram (ASCII)

Audio sample -> PWM duty -> RC filter -> Speaker

How it works (step-by-step)

  1. Generate audio sample value.
  2. Convert to PWM duty cycle.
  3. Output PWM at high frequency.
  4. Filter to recover audio.

Minimal concrete example

pwm_set_gpio_level(audio_pin, sample_value);

Common misconceptions

  • “PWM is perfect audio” -> requires filtering.
  • “Higher carrier is always better” -> reduces effective resolution.

Check-your-understanding questions

  1. Why is a low-pass filter needed?
  2. What happens if PWM frequency is audible?
  3. How does PWM resolution affect audio quality?

Check-your-understanding answers

  1. It removes the high-frequency carrier.
  2. You hear a whine or hiss.
  3. Higher resolution means lower quantization noise.

Real-world applications

  • Simple audio output on microcontrollers, beepers, synths.

Where you’ll apply it

References

  • PWM audio tutorials

Key insights

Good audio output is about balancing PWM frequency, resolution, and filtering.

Summary

PWM can produce usable audio with high carrier frequency and filtering.

Homework/Exercises to practice the concept

  1. Measure PWM carrier frequency with a scope.
  2. Compare audio quality with and without RC filter.

Solutions to the homework/exercises

  1. Confirm frequency matches PWM configuration.
  2. Filtered output is smoother with less hiss.

3. Project Specification

3.1 What You Will Build

A touchless theremin with two capacitive sensors controlling pitch and volume, generating real-time audio via PWM.

3.2 Functional Requirements

  1. Capacitive sensing: stable proximity measurement.
  2. Pitch mapping: exponential mapping to musical range.
  3. Waveform synthesis: sine/triangle/square output.
  4. Audio output: PWM with RC filter.
  5. Smoothing: filter sensor jitter.

3.3 Non-Functional Requirements

  • Performance: low latency (<20 ms) from hand movement to sound.
  • Reliability: stable baseline for 10 minutes.
  • Usability: smooth pitch transitions without jitter.

3.4 Example Usage / Output

[THEREMIN] pitch=523Hz volume=0.65 waveform=sine

3.5 Data Formats / Schemas / Protocols

  • Internal: sensor_value -> frequency (Hz)
  • Control messages: SET WAVE sine

3.6 Edge Cases

  • No hand present -> mute output.
  • Sudden interference -> recalibrate baseline.
  • Sensor saturation -> clamp to max pitch.

3.7 Real World Outcome

Wave your hands near the antennas to control pitch and volume smoothly.

3.7.1 How to Run (Copy/Paste)

cmake .. && make -j4
picotool load -f theremin.uf2

3.7.2 Golden Path Demo (Deterministic)

  • Hold hand at 20 cm -> pitch ~440 Hz.
  • Move closer to 10 cm -> pitch doubles (~880 Hz).

3.7.3 Failure Demo (Bad Input)

  • Scenario: sensor baseline drift due to humidity.
  • Expected result: firmware triggers recalibration and logs warning.

3.7.4 If CLI: exact terminal transcript

$ minicom -b 115200 -o -D /dev/ttyACM0
[THEREMIN] pitch=523Hz volume=0.65

4. Solution Architecture

4.1 High-Level Design

Sensors -> Filter -> Pitch/Volume Map -> Synth -> PWM -> Speaker

4.2 Key Components

| Component | Responsibility | Key Decisions | |———–|—————-|—————| | Sensor Driver | RC timing | Calibrated baseline | | Filter | Smooth readings | EMA filter | | Synth | Generate waveform | Wavetable | | Audio Output | PWM + RC | 100 kHz carrier | | UI | Debug logs | Serial output |

4.3 Data Structures (No Full Code)

typedef struct {
  uint32_t pitch_hz;
  float volume;
  uint16_t raw_pitch;
  uint16_t raw_vol;
} theremin_state_t;

4.4 Algorithm Overview

Key Algorithm: Sensor-to-Audio Loop

  1. Measure RC timing for pitch and volume.
  2. Filter values and map to frequency/volume.
  3. Generate audio samples via wavetable.
  4. Output via PWM at fixed rate.

Complexity Analysis:

  • Time: O(1) per sample
  • Space: O(1) plus wavetable

5. Implementation Guide

5.1 Development Environment Setup

# Pico SDK

5.2 Project Structure

theremin/
├── firmware/
│   ├── main.c
│   ├── capsense.c
│   ├── synth.c
│   └── audio_pwm.c
└── README.md

5.3 The Core Question You’re Answering

“How do you sense proximity and generate audio in real time on a microcontroller?”

5.4 Concepts You Must Understand First

  1. RC timing and capacitance
  2. Waveform synthesis
  3. PWM audio output

5.5 Questions to Guide Your Design

  1. What pitch range should you support?
  2. How will you smooth sensor jitter?
  3. What PWM frequency yields acceptable audio?

5.6 Thinking Exercise

Compute sample rate needed for clean 5 kHz audio.

5.7 The Interview Questions They’ll Ask

  1. How does capacitive sensing work?
  2. What is Nyquist and how does it apply to audio?
  3. Why does PWM need filtering for audio?

5.8 Hints in Layers

Hint 1: Print raw RC timing values. Hint 2: Add baseline calibration. Hint 3: Generate a fixed tone. Hint 4: Map sensor values to pitch and volume.

5.9 Books That Will Help

| Topic | Book | Chapter | |——-|——|———| | Sensors | “Making Embedded Systems” | Ch. 8 | | Audio synthesis | “Designing Sound” | Ch. 3 | | Signal processing | “The Scientist and Engineer’s Guide to DSP” | Ch. 1 |

5.10 Implementation Phases

Phase 1: Foundation (3-5 days)

  • Build capacitive sensor and log readings. Checkpoint: stable baseline measurement.

Phase 2: Core Functionality (5-7 days)

  • Add waveform synthesis and PWM output. Checkpoint: fixed tone plays cleanly.

Phase 3: Expressive Control (4-6 days)

  • Map sensor values to pitch/volume with smoothing. Checkpoint: smooth pitch control without jitter.

5.11 Key Implementation Decisions

| Decision | Options | Recommendation | Rationale | |———-|———|—————-|———–| | Filter | EMA vs moving avg | EMA | Lower latency | | Output | PWM vs DAC | PWM (MVP) | Simple hardware | | Mapping | Linear vs log | Log | Musical response |


6. Testing Strategy

6.1 Test Categories

| Category | Purpose | Examples | |———-|———|———-| | Unit Tests | Mapping correctness | Sensor -> pitch conversion | | Integration Tests | Audio output | Measure PWM frequency | | Edge Case Tests | Noise sensitivity | EMI near sensor |

6.2 Critical Test Cases

  1. Baseline: no hand -> mute output.
  2. Pitch doubling: distance halved -> pitch doubles.
  3. Stability: jitter < 10 Hz at steady hand.

6.3 Test Data

Sensor value 1000 -> 440 Hz
Sensor value 2000 -> 880 Hz

7. Common Pitfalls & Debugging

7.1 Frequent Mistakes

| Pitfall | Symptom | Solution | |———|———|———-| | No filtering | Jittery pitch | Add EMA smoothing | | PWM too low | Audible whine | Increase carrier frequency | | Poor grounding | Noisy readings | Short ground leads |

7.2 Debugging Strategies

  • Use serial logs to monitor raw sensor values.
  • Use a scope to verify PWM waveform.

7.3 Performance Traps

  • Heavy math in audio loop can cause underruns.

8. Extensions & Challenges

8.1 Beginner Extensions

  • Add waveform selection button.
  • Add LED feedback for pitch.

8.2 Intermediate Extensions

  • Add quantization to musical scales.
  • Add vibrato effect.

8.3 Advanced Extensions

  • Implement digital filters for tone shaping.
  • Add MIDI output for external synths.

9. Real-World Connections

9.1 Industry Applications

  • Interactive installations and musical art.
  • Touchless controls in consumer devices.
  • Teensy Audio examples for synthesis ideas

9.3 Interview Relevance

  • Sensor processing and audio synthesis are valuable embedded topics.

10. Resources

10.1 Essential Reading

  • Capacitive sensing app notes
  • PWM audio tutorials

10.2 Video Resources

  • Theremin build videos

10.3 Tools & Documentation

  • Oscilloscope for PWM verification

11. Self-Assessment Checklist

11.1 Understanding

  • I can explain capacitive sensing with RC timing.
  • I can map sensor values to musical pitch.
  • I can generate PWM audio output.

11.2 Implementation

  • Pitch control is smooth.
  • Audio output is stable and clear.
  • Baseline calibration works reliably.

11.3 Growth

  • I can add scales and effects.
  • I can improve sensor stability.

12. Submission / Completion Criteria

Minimum Viable Completion:

  • Sensor controls pitch and audio output works.

Full Completion:

  • Two sensors control pitch and volume with smoothing.

Excellence (Going Above & Beyond):

  • Add scales, effects, and MIDI output.

13. Additional Content Rules

13.1 Determinism

Use fixed baseline calibration at startup and fixed sample rate for audio. Log raw sensor values and mapped pitch.

13.2 Outcome Completeness

  • Success demo: §3.7.2
  • Failure demo: §3.7.3
  • CLI exit codes: host calibration tool returns 0 success, 2 sensor not found, 4 unstable baseline.

13.3 Cross-Linking

Concept references in §2.x and related projects in §10.4.

13.4 No Placeholder Text

All sections are fully specified for this project.