Teensy 4.0 based Digital Theremin

Status
Not open for further replies.
Hello!

I'm working on my hobby digital theremin project.

Theremin is musical instrument controlled by distance between player's hand and antennas.

In theremin, there are two antennas - one for pitch control and second for volume control. Pitch antenna (right) is usually straight conducting rod, and volume antenna is loop-shaped conducting rod oriented horizontally.
Classic theremins are analog - pitch oscillator frequency is being converted to audible range using heterodyning, and volume antenna cirquit produces volume control voltage to shape pitch signal using VCA.
Digital theremins are actually digital synthesizers controlled by theremin sensors.

This project is started to provide digital theremin design, which is
  • Open source, open hardware
  • Easy to build
  • Low latency of sensors
  • Descent synthesizer
  • Low cost


Challenges: sensors

When hand approaches antenna, its capacicance increases. Total range of capacitance change due to hand movement is about 1.5pF
Antenna self-capacitance is near 7-8pF. To capture hand movements it's necessary to measure antenna capacitance with very high precision.
C of antenna non-linearly depends on hand range. Each 10cm of additional distance reduce C introduced by hand by ~3.5 times. Required distance measurement precision is about 1mm.
It's easy measure C for short distances - when it changes by 0.1..0.01pF. Even RC based sensor might work on 10cm distance.
But the bigger is distance, the finer resolution of C sensor is needed. Averaging of sensor output could increase precision, but introduces latency.
Good theremin should have low latency (less than 1ms). As bad example of digital theremin sensor design you can try Moog Theremini (latency is 0.1..0.5 seconds!!!)

High precision measurement of C requires LC tank with high Q. L should be big enough (0.5mH..10mH), C should be small (C = C_ant + C_hand + C_internal) to keep good sensitivity.

We can either measure of LC oscillator frequency (1) or measure amplitude or phase shift of reference signal passed through LC (2).
(for reference signal frequency close to LC resonance phase shift is PI/2 and amplitude is max; phase shift is easier to track than amplitude change).

For (1) we have to be able measure frequency with very high precision. LC oscillator frequency (in range 0.2MHz..3Mhz varying by 1..5% depending on hand distance) can be either measured directly (requires very high resolution of measurement timer) or converted to lower frequency higher relative change signal using some heterodyning technique.
In digital theremins (like Open.Theremin) there is often used D-trigger based heterodyne which converts oscillator frequency to easy measurable range. But it has aliasing issues and not enough good performance.
(I've tried this approach in Teensy 3.6 based implementation - it's not precise enough).

For (2) we can convert phase shift to PWM using XOR between LC input and output, convert to voltage using lowpass filter, then measure using ADC.

I've experimented a lot with FPGA based design, where main purpose of FPGA was to implement high precision frequency measure - until I visited pjrc site and found that there is Teensy 4.0 available.
Now I switched to development of digital theremin design based on Teensy 4.0 and Teensy Audio Adaptor (revD).
600/800MHz is more than enough for virtually

Although Teensy 4.0 timer performance is higher than one in Teensy 3.6 (150MHz or even 200MHz overclocked vs 60MHz), it's still not enough for direct measure of oscillator frequency.
Possible solution could be to use external IC like TDC7200, but I'm trying to find some easy to build solution, to minimize soldering while providing high sensitivity and low latency.

Main challenge is design of Pitch antenna sensor able to provide enough bits of distance value for hand distances 80..100cm from antenna.
Phase shift based approach (2) is possible, but requires external ADC (24 bits looks enough according to simulation).
LTSpice model:
theremin_sensor_phase_shift_ltspice_model.jpg
LTSpice simulation results - output voltage depending on C_hand with 0.1pF steps:
theremin_sensor_phase_shift_ltspice_simulation_results.png

I hope, this approach can be used for volume antenna where far distances are not required (30..40cm max are usual) - even when measured by Teensy 4.0 internal ADC.

Pitch sensor.

How do we implement sensitive sensor for pitch antenna?
We can go closer to analog theremins.
What if we pass LC oscillator output (F_osc) through heterodyne (mixing with F_ref) to get output signal with frequency F_ref-F_osc?
Oscillator will provide clean sine output. Heterodyne can be built based on analog switch - if F_osc is sampled at F_ref rate and passed through LP filter, output will be clean sine of frequency F_ref-F_osc.
We already have higher precision ADC than one in Teensy 4.0 - it's SGTL5000 from audio board which can provide 16-24 bits once per sample - if Line In of Audio Adaptor is used as ACD.
We only need to make sure that frequency and amplitude of heterodyne output matches Line In capabilities.
How do we measure frequency of heterodyne output? It may vary in amplitude (there is signal damping when hand is close to antenna). Of course, we could detect zero crossings and use interpolation to determine exact time of crossing.
But isn't it possible to have measured value for each sample, not only when signal crosses zero? Tricks with asin() and autocalibration of amplitude, but there is a better way.
Let's use two heterodyne channels, with PI/2 shift between them (use both left and right channels of Line In). In this case we can simple use tan2() on each sample to get phase value signal not dependent on amplitude changes.

We need two reference frequency signals, phase shifted by PI/2, with small duty cycle (0.05..0.2). To achieve this, we can use FlexPWM.
Divider value K for PWM should be divisible by 4 if we need exact PI/2 phase shift. Difference between F_BUS/K and F_BUS/(K+4) should be small enough (e.g. <5KHz) to allow calibration to fit signal in LineIn frequency range.
So, oscillator frequency needs to be < 500KHz.

LTSpice model:
osc_opamp_quadrant_out_ltspice_model_v1.png
Simulation results - quadrant output to be passed to Audio Adaptor Line In:
osc_opamp_quadrant_out_ltspice_model_v1_simulation_heterodyne_quadrants_out.jpg
Reference frequency signals and oscillator output:
osc_opamp_quadrant_out_ltspice_model_v1_simulation_osc_out_and_ref_freq.jpg

Sensor signal, after calibration, will provide LineIn frequency change F_max-F_min 8..15 KHz where F_min is 1KHz..5KHz depending on calibration results (PWM timer resolution).
In Audio IRQ handler, samples read from LineIn can be converted to phase value, then averaged to reduce noise and increase sensitivity, and then transformed to output note frequency for synthesizer.

For Volume sensor, it's enough to get new value once per audio frame (even after additional filtering/averaging, latency will be good enough - because theremin is less sensitive to volume control latency than to pitch control latency).

Parts

  • Teensy 4.0
  • Audio Adaptor rev D
  • LCD Touch Screen - e.g. from pjrc.com or one from buydisplay.com (on the same ILI chip, same resolution, bigger diagonal, with capacitive touch screen controlled over I2C).
  • Two air core inductors (manual winding)
  • A few rail-to-rail opamps for sensors.
  • Analog switch IC for pitch sensor.
  • XOR logic IC for volume sensor.
  • Optional SPDIF transmitter module
  • Optional SPDIF receiver module
  • Optional USB type A socket for usb host
  • MicroSD card socket (or just place Audio Adaptor to make its sd card slot available)
  • 2-3 incremental oncoders with buttons
  • 3-5 pots 10K
  • Several audio jacks
  • Copper or brass tubes for antennas
  • Some box for cabinet


Theremin cabinets I've built
Plywood laser cut design, inspired by Etherwave
cabinet_on_mic_stand.jpg
PPL tubes design
pipe_monster_cabinet_mounted_small.jpg
Most likely I'll use polypropylene tubes based design, with a bit different layout - with two additional boxes for inductors and oscillators placed near antennas.


Nearest goals

Figure out how to generate synchronous PI/2 phase shifted reference frequency signals on two pins. Which pins to choose?
Does it make sense to solder Audio Adapter upside down to be able accessing its SD card slot from rear panel of device to avoid soldering of additional SD card slot and ribbon cable? Is its performance good enough comparing to true 4-bit SDIO available via ribbon cable?
Does it make sense to write my own audio interface code (e.g. to use 48KHz sample rate and 24 bits per sample), or Audio Library is enough?


Links:

 
Last edited:
Just a few thoughts:
1.) A theremin is characterized (see original US patents by inventor Leon Theremin himself) by sound generation through 2 directly heterodyning RF oscillators. From that point of view, the device you are building is not a theremin but a synthesizer with capacitive gesture control, similar to the Moog Series 91 and Theremini. To avoid any confusion, you should perhaps give it a different name.
2.) You might consider using a display with resistive touch screen. Capacitive touch screens (which are RF driven, too) might interfere with your oscillators and vice versa. I recently saw an effect device with capacitive screen completely losing its touch capability when placed on the floor below a Moog Etherwave Plus theremin while the latter was switched on.
3.) The audio library with 16bit/44.1kHz gives theoretically CD quality. The dynamic ranges of a Russian tVox tour theremin or a (unmodified) Etherwave Pro are about 60dB, an upgraded (EPVM1345 module) Etherwave Pro has 72dB, all others are worse. Thus, 16bit audio should be fine (it was for Berlin Philharmonic conductor Herbert von Karajan who worked with Philips on the CD standard in the 1980s).
4.) Pitch sensor granularity: Starting from the idea to have a 5 octave range over 60cm, that makes 1cm per half tone. Pitch steps, to be perceived as continuous pitch, should be <= 4cts which requires a precision of 0.4mm or better if you don't want trained musicians to hear pitch stepping.5.) Your simulated phase detector looks good - with linear capacitance steps. But capacitance varies exponentially with distance. In order to linearize that mathematically afterwards, you need a very high and clean resolution - not sure if the 10bit converters of the T4.0 are sufficient. 10bits are 1024 steps which (before applying exp/log correction) provide you only with 61.7dB dynamic range in an ideal case. Each additional transformation risks to reduce that resolution and range.

I do not intend to discourage you with this. But others have partly been there already and this shared experience might prevent you from going impractical paths.
 
Just a few thoughts:
1.) A theremin is characterized (see original US patents by inventor Leon Theremin himself) by sound generation through 2 directly heterodyning RF oscillators. From that point of view, the device you are building is not a theremin but a synthesizer with capacitive gesture control, similar to the Moog Series 91 and Theremini. To avoid any confusion, you should perhaps give it a different name.
Thank you for feedback.
When can digital theremin be called theremin?
Quadrant heterodyne design is really close to analog theremins.
In approach I'm proposing for pitch sensor, if fine grained reference frequency is used (e.g. with 10-20Hz precision using external PLL), quadrant sine waves produced by heterodyne can be directly fed to audio output (after volume applied). In this case, can it be called real theremin? What if waveform of heterodyne output is directly replaced (using wavetable[tablesize*tan2(sample.left, sample.right)/2/M_PI]) with another one, is it still theremin? If pitch frequency is altered, e.g. to change output pitch range - it's not theremin?

I believe "digital theremin" itself means theremin-like sensors + digital synthesizer.
So far, I have no idea of good name for project.

2.) You might consider using a display with resistive touch screen. Capacitive touch screens (which are RF driven, too) might interfere with your oscillators and vice versa. I recently saw an effect device with capacitive screen completely losing its touch capability when placed on the floor below a Moog Etherwave Plus theremin while the latter was switched on.
Thank you for pointing at this issue. I didn't know it. I have LCD screen with resistive touch from PJRC anyway, so I will use it instead of capacitive screen.

3.) The audio library with 16bit/44.1kHz gives theoretically CD quality. The dynamic ranges of a Russian tVox tour theremin or a (unmodified) Etherwave Pro are about 60dB, an upgraded (EPVM1345 module) Etherwave Pro has 72dB, all others are worse. Thus, 16bit audio should be fine (it was for Berlin Philharmonic conductor Herbert von Karajan who worked with Philips on the CD standard in the 1980s).
41000Hz+16bits obviously is good enough. Pro: Audio Library can be used.
The only objection here is possible latency introduced by default frame size of Audio Library (btw, is it 1 or 2 frames?). I believe it can be fixed by reducing of audio frame size in Audio Library headers.

4.) Pitch sensor granularity: Starting from the idea to have a 5 octave range over 60cm, that makes 1cm per half tone. Pitch steps, to be perceived as continuous pitch, should be <= 4cts which requires a precision of 0.4mm or better if you don't want trained musicians to hear pitch stepping.5.) Your simulated phase detector looks good - with linear capacitance steps. But capacitance varies exponentially with distance. In order to linearize that mathematically afterwards, you need a very high and clean resolution - not sure if the 10bit converters of the T4.0 are sufficient. 10bits are 1024 steps which (before applying exp/log correction) provide you only with 61.7dB dynamic range in an ideal case. Each additional transformation risks to reduce that resolution and range.

I'm not going to use phase shift sensor for pitch - it's possible, but require external 24bit ADC.
Instead, double channel heterodyne which provides quadrant sine waves in audible range design is proposed for pitch sensor, and Audio Adapter Line In ADC will be used to sample it. It's close to analog theremins with the only one difference: heterodyne output is not used directly, but instead converted to frequency, then transformed (linearization, note range) before passing to synthesizer. I believe since analog theremins have enough sensitivity, this approach will work not worse.
I'm pretty sure, my pitch sensor design should work fine. Now I'm making prototype for oscillator and heterodyne to test on real hardware.

Phase shift sensor is proposed for Volume antenna only. It has much smaller working distances (I beleive, max 30-40cm should be ok). Teensy 4.0 ADC with averaging can give 12 bits with averaging. Sensor's LC Q + tuning reference frequency may be played with to be able "zooming" far distance range near resonant frequency, while other are "compressed" - to linearize voltage to C, atan() can be used. If sensor is tuned to use even half of available range - which gives us 11 bits.
With zooming of 0.1pF range corresponding to far hand distances, it's possible to have about 10-12% of ADC input voltage range for 0.1pF change near resonance.
It gives us about 8 bits for 0.1pF range (for all hand distances > 22cm).
Volume control is more tolerant to latency, is averaging could give us a few more bits (*K averaging gives log2(K)/2 bits). I believe it should provide good enough volume control precision for ranges up to 40cm even with internal ADC.

If phase shift to voltage approach won't work good enough, it's possible to switch to another one, e.g. frequency measure.
Direct measure of oscillator frequency (e.g. divided downto 1KHz, measured with FrequencyMeasure with F_BUS precision) gives about 17 bits for period value, bug since it changes only up to 5% for very sensitive sensor, only ~13 of valuable bits are left after range conversion. Non-linearity eats ~2 bits for each 10cm of hand distance, and on 40cm, there should be about 5 bits left, which seems good enough for volume control. If not enough, simple D-trigger based heterodyning should help to bypass sensitivity limit.

I do not intend to discourage you with this. But others have partly been there already and this shared experience might prevent you from going impractical paths.
I've already faced with these issues while trying to implement digital theremin on Teensy 3.6 + D-trigger heterodyne.
I hope, this attempt will be successful. If even Open.Theremin on really poor hardware and bad sensors is almost playable, why it's not possible to get good results with much better, and after a lot of time spent while modelling of different sensor approaches in LTSpice.
 
Last edited:
Simulation of phase shift detection approach - with bigger Q and C values corresponding to hand distances 1cm, 11cm, 21cm, .. Bottom line is 1cm. Blue line - 21cm, green line - 31cm, gray - 41cm, pink - 51cm
Between 41 and 51 there is enough distance in voltage (and ADC bits) - 0.045V to have sensitivity range of volume antenna at least till 51cm.

theremin_sensor_phase_shift_ltspice_simulation_results_lin_dist_steps.png

A lot of analog theremins use similar technique (but usually amplitude change instead of phase change) for Volume control.
So, most likely, this method should work.
 
Phase shift theremin sensor on Teensy 4

Trying to build as simple theremin sensor as possible.

In theremin sensor, we have to measure antenna capacitance with VERY high accuracy.
Typical theremin antenna C is 7-8pF.
Hand close to antenna adds ~1.5pF more. Influence of hand reduces very fast with increasing of hand to antenna distance.
C = C_antenna + C_hand

C_hand reduces ~3.5 times each 10cm

Code:
Distance, cm     C_hand, pF
1	             1.5000000000
11	             0.4285714286
21	             0.1224489796
31	             0.0349854227
41	             0.0099958351
51	             0.0028559529
61	             0.0008159865
71	             0.0002331390
81	             0.0000666111

Measured C_hand could be converted to distance, then to note or volume, then passed to synthesizer as pitch or volume control value.

We could use LC oscillator with antenna as C, and try to measure its frequency directly, but since frequency is changed by about 5% for all hand distances.
For all ranges > 21cm, we have only about 0.3% of frequency change. It's very hard to measure using MCU.

Some method to zoom in working range is required.
For LC oscillator, we can mix its output F_osc with reference frequency F_ref in heterodyne, to get difference frequency F_ref-F_osc.
Another method is to detect phase shift of constant reference frequency signal passed through LC.

If signal passes LC tank, output depends on how close it is to LC resonant frequency.
At resonance, phase shift is PI/2 and its amplitude has maximum value (much bigger than input signal voltage).
When input frequency is higher than resonant frequency, amplitude decreases, and phase shift is < PI/2.
When input frequency is lower than resonant frequency, amplitude decreases, and phase shift is > PI/2.
Change of phase shift as reaction on LC resonance frequency change (C change) depends on LC tank Q.
The bigger Q is, the more sensitivity (phase change per C change) is visible.
By tuning of LC Q, we can "zoom in" C_antenna corresponding to hand distances far from antenna near PI/2 phase shift.
But we need to keep full range readable (still have usable output for distance close to antenna).

Let's wind air core inductor and use its parameters in LTSpice simulation.

I'm using 32 mm diameter of PPL water pipe frame, 0.1mm copper wire, 175mm winding length.
Got 4.272mH on chinese L/C meter from aliexpress.

coil_lc_meter_4_272mh.jpg

Trying to check with Coil64:

Code:
Input:
Inductance L: 4,272 microH
Frequency f: 0.6 MHz
Former diameter D: 32 mm
Wire diameter d: 0.1 mm
Wire diameter with insulation k: 0.109 mm
Winding pitch p: 0.122 mm

Result:
Number of turns of the coil N = 613.288
Length of wire without leads lw = 61.864 m
Length of winding l = 74.930 mm
Weight of wire m = 4.32436 g
Reactance of the coil X = 16,105.061 Ohm

Self capacitance Cs = 1.341 pF
Coil self-resonance frequency Fsr = 1.358 MHz
Coil constructive Q-factor Q = 82
Loss resistance ESR = 196.403 Ohm

LTSpice model: GitHub link

Schematic:

phase_shift_ltspice_model_4mh_schematic.png

Inductor parameters are set from Coil64 results.

We could just pass square 50% duty cycle reference frequency from Teensy pin to LC, but simulation shows some distortion in signal on antenna introduced by square wave input.
I've added square to sine conversion on LRC bandpass filter and NPN buffer - to feed LC tank with almost pure sine.
Delay (phase shift) introduced by this conversion should be const for const reference frequency.
LC resonant frequency is near 690KHz, so bandpass filter should have center frequency near to this value.
Using online calculator http://sim.okawa-denshi.jp/en/RLCtool.php to get filter component values.

Simulation results for square to sin conversion:

phase_shift_ltspice_model_4mh_simulation_square_to_sin.png

Voltage swing on antenna and sensor output:

phase_shift_ltspice_model_4mh_simulation_ant_out.png

Source and output signals of sensor output buffer:

phase_shift_ltspice_model_4mh_simulation_shift_out.png

In this simulation, we change C_hand from 0 to 2pF with 0.1pF step.
During calibration phase, MCU should choose such reference frequency value to be near resonance for hand distances far from antenna.
We should use widest 0.1pF step for far distances, and 14 more steps to the right will correspond to shorter (<21cm) distances.
Reference frequency period is 1.359uS, and width of widest interval is 0.057uS which gives us 4.2% of input range for 0.1pF interval corresponding to distances > 21cm

Can we measure this signal with good enough precision using Teensy 4.0?

Let's use FlexPWM module, with channel A generating reference frequency signal with 50% duty cycle (even divider value should be used).
Channel B will work in capture mode, capturing PWM counter values for both input (phase shifted) signal edges.
For 690KHz reference frequency (divider 216, actual f=694444Hz), we will have 216 values in PWM counter cycle.
Captured value gives us 7.75 bits of information about phase shift.
Having two edges measured, we get one more bit - 8.75 bits total.
Seems too low. Is it possible to increase number of bits in measured result?
Sure, we can measure it N times, then average. It will give log2(N) more bits.
E.g., for 1ms window, we have 690 measures, providing log2(690)=9.43 bits
Total bits for 1ms averaging is 8.75+9.43 = 18
Is it enough? Let's check.
For short distances (>21cm where we have 1.4pF C_hand range), it's obviously enough.
Let's check what we have for longer (>21cm) range which corresponds to ~0.1pF region near resonance frequency (PI/2 shift).
4.2% input range limit of middle 0.1pF eats log2(100/4.2)=4.57 bits of input range.
18-4.57 = 13.6 bits

Code:
range     bits left
21	     13.6
31	     11.8
41	     10
51	     8.2
61	     6.4
71	     4.6
81	     2.8
91	     1
101	     -0.8

After 61cm distance we see 6.4 bits left in input value.
In general, this means we will have audible quantization of pitch.
But actually, long distances usually correspond to lower frequency notes. And actually, when synthesis of output signal with "dithered" (varying) frequency,
output probably will sound like "average" frequency.
We can as well to increase averaging time interval. Increasing of averaging 4 times, gives additional 10cm of playable distance.
But the bigger averaging interval is, the bigger is latency between hand movement and
I believe 3..4ms averaging interval will still be non-audible.

So, it looks like it's possible to have playable distance 60-90cm of hand from pitch antenna, using only Teensy 4.0 PWM pins, with simple phase shift sensor.

But how will we read measured values? There will be 690000 measure results per second.
We could use interrupt, but at this rate, CPU would waste half of time on interrupt processing (saving/restoring registers, etc).
Fortunately, there is DMA in Teensy 4.0 MCU.
It can be programmed to save results of every capture to ring buffer in RAM.
In Audio ISR, we can do averaging for all values in buffer to get precise enough sensor value per frame.
Summing of 1000 integers once per audio frame doesn't consume a lot of CPU resources unlike interrupt per measure.

Conclusion.

It looks like it's possible to implement phase shift based theremin on Teensy4 with minimal external components.
Pitch antenna max playable range is expected to be 60..80cm.
 
To simplify soldering of sensor prototype, I've created KiCAD project.

Changes comparing to LTSpice model:

* Power input is +5V. 3.3V regulator added to minimize noise via power line.
* Optional capacitor from antenna to ground is routed.

2.54mm prototype board friendly design of Phase Shift sensor PCB is available in KiCAD format on GitHub.
All components are THT/DIP/TO-92

3d render:

phase_shift_sensor_proto_pcb_3d_render.jpeg

Soldering sensor prototype PCB: in progress...
 
PhaseShift library development progress:
For now, pin2 is hardcoded as reference signal generator (channel A of FlexPWM4 submodule 2), and pin3 (channel B of the same submodule) as input of shifted signal.
Pins are programmed via constructor.
begin() enables reference signal generation of specified frequency and phase shift (50% duty cycle now), and programs input pin for capture of both edges of phase shifted signal.
Method setPeriod() may be used to change frequency and/or phase of reference signal.
For reading of captured values, only polling method is implemented so far (wait for capture flag in FlexPWM submodule, clear capture flags, return captured values read from registers.

TODOs:
* add DMA support to read captured values continuously and put them into ring buffer in memory.
* support more pins (both input and output pins should be routed to the same FexPWM submodule)

Tested by connecting simple RC delay between pin 2 and pin 3, with pot as R.
I see captured phases as two alternating values (e.g. 138,137,137..138..).

Sample code:

Code:
PhaseShift pitchSensor(PITCH_SENSOR_FREF_PIN, PITCH_SENSOR_PHASE_SHIFT_PIN);
uint16_t pitchPeriod = PhaseShift::frequencyToPeriod(PITCH_SENSOR_FREQUENCY);
pitchSensor.begin(pitchPeriod, 0, PITCH_SENSOR_AVERAGING);
  Edges data[1000];
  for (int i = 0; i < 1000; i++) {
    data[i] = pitchSensor.poll();
  }

Link to GitHub with library and test sketch.

Schematic of sensor PCB is changed (simplified to bare minimum). Square reference signal is used as LC input instead of converting it to clean sine.

With max Q (no damping resistors or caps), it's still usable: good "zoom" of 0.1pF C_hand range corresponding to far hand distance (>21cm) - it's ~6% (1/16) of range.
Although there is a distortion before resonance (increasing of C not always increases phase shift), for C_hand > C_resonance everything is ok.

LTSpice model: (download link)
phase_shift_ltspice_model_simple_2mh_schematic.png

In this simulation, C_hand is being changed 0.0..2.0 with 0.1pF step.
Widest 0.1pF step near resonant frequency will be tuned for max hand distances.

phase_shift_ltspice_model_simple_2mh_simulation_output.jpg

Voltage swing on antenna ~200V looks scary for me. Won't it kill 1pF capacitor?

phase_shift_ltspice_model_simple_2mh_simulation_antenna.jpg

KiCad project is available on GitHub, too

phase_shift_kicad_simple_2mh_schematic.png

3D render of sensor PCB:

phase_shift_kicad_simple_2mh_3drender.png

As well, creation of simulator (Qt/C++) is in progress.
It will simulate sensors, ILI touch LCD, pots, encoders, audio playback (audio IRQ will be called from simulator, and synthesizer code will be the same as on real hardware).
 
Based on additional experiments with LTSpice models, schematic of Phase Shift Sensor board is updated.

Better ICs are going to be used as buffers and ESD protection.
Big input capacitance of ICs reduces sensor sensitivity to C_hand changes.
Buffers on 74HC04 are replaced with NC7WZ04 - fast dual inverter with 2.5pF C_in instead of 3.5pF of HC04
ESD protection IC SP721 is replaced with IP4220CZ6 - 4-channel rail-to-rail 6kV ESD protection device, with 2.5pF C_in instead of 3pF of SP721

Other changes:
4.7Meg resistor is connected between antenna and ground to simulate energy loss of real device.
Resistor betwen F_ref buffer and L input, R_q, is set to 22 Ohm. Direct connection (R_q=0) gives better sensitivity by ~20%. R_q=33 works, too. R_q=68 limits output current by allowed 50mA if shorted to 0 or 3.3V, but visible reduces Q.
Centering resistors set to 470K. Tried 100K and 1Meg - no visible difference.
C for feeding output buffer is set to 2.2pF/3
Resistor between cap and centering resistor breaks resonance, so I removed it.

Let's calculate theoretical sensitivity of new schematic - with 1pF ESD protection device and 2.5pF buffer inverter.

Simulation (C_hand step is 0.025pF):

LTSpice model (github link):

phase_shift_ltspice_optimized_1_2mh_schematic.png


Antenna voltage swing is +-100V:

phase_shift_ltspice_optimized_1_2mh_simulation_antenna.png


Output buffer invertor is disconnected and replaced with 2.5pF cap to simulate input capacitance of invertor planned to use

phase_shift_ltspice_optimized_1_2mh_simulation_buf_input.png


Now let's try to estimate sensor sensitivity.

Assuming C_hand is 1.5pF when hand is at 1cm from antenna, and reduced by 3.5 times each 10cm.
Per 1cm, it's 2^(log2(3.5)/10)=1.133461582
It corresponds to log2(1.133461582)=0.18 bits loss per 1cm of hand distance.

Table of C_hand for hand distances with 1cm step:

Code:
dist, cm     C_hand, pF      Bits lost
--------     ----------      ---------
1	         1.50000000      0
2	         1.32337966      0.18
3	         1.16755581      0.36
4	         1.03007974      0.54
5	         0.90879105      0.72
6	         0.80178373      0.9
7	         0.70737618      1.08
8	         0.62408483      1.26
9	         0.55060078      1.44
10	         0.48576925      1.62
11	         0.42857143      1.8
12	         0.37810847      1.98
13	         0.33358737      2.16
14	         0.29430850      2.34
15	         0.25965459      2.52
16	         0.22908106      2.7
17	         0.20210748      2.88
18	         0.17830995      3.06
19	         0.15731451      3.24
20	         0.13879121      3.42
21	         0.12244898      3.6
22	         0.10803099      3.78
23	         0.09531068      3.96
24	         0.08408814      4.14
25	         0.07418702      4.32
26	         0.06545173      4.5
27	         0.05774499      4.68
28	         0.05094570      4.86
29	         0.04494700      5.04
30	         0.03965463      5.22
31	         0.03498542      5.4
32	         0.03086600      5.58
33	         0.02723162      5.76
34	         0.02402518      5.94
35	         0.02119629      6.12
36	         0.01870050      6.3
37	         0.01649857      6.48
38	         0.01455591      6.66
39	         0.01284200      6.84
40	         0.01132990      7.02
41	         0.00999584      7.2
42	         0.00881886      7.38
43	         0.00778046      7.56
44	         0.00686434      7.74
45	         0.00605608      7.92
46	         0.00534300      8.1
47	         0.00471388      8.28
48	         0.00415883      8.46
49	         0.00366914      8.64
50	         0.00323711      8.82
51	         0.00285595      9
52	         0.00251967      9.18
53	         0.00222299      9.36
54	         0.00196124      9.54
55	         0.00173031      9.72
56	         0.00152657      9.9
57	         0.00134682      10.08
58	         0.00118824      10.26
59	         0.00104833      10.44
60	         0.00092489      10.62
61	         0.00081599      10.8
62	         0.00071991      10.98
63	         0.00063514      11.16
64	         0.00056035      11.34
65	         0.00049437      11.52
66	         0.00043616      11.7
67	         0.00038481      11.88
68	         0.00033950      12.06
69	         0.00029952      12.24
70	         0.00026425      12.42
71	         0.00023314      12.6
72	         0.00020569      12.78
73	         0.00018147      12.96
74	         0.00016010      13.14
75	         0.00014125      13.32
76	         0.00012462      13.5
77	         0.00010994      13.68
78	         0.00009700      13.86
79	         0.00008558      14.04
80	         0.00007550      14.22
81	         0.00006661      14.4
82	         0.00005877      14.58
83	         0.00005185      14.76
84	         0.00004574      14.94
85	         0.00004036      15.12
86	         0.00003561      15.3
87	         0.00003141      15.48
88	         0.00002771      15.66
89	         0.00002445      15.84
90	         0.00002157      16.02
91	         0.00001903      16.2
92	         0.00001679      16.38
93	         0.00001481      16.56
94	         0.00001307      16.74
95	         0.00001153      16.92
96	         0.00001017      17.1
97	         0.00000898      17.28
98	         0.00000792      17.46
99	         0.00000699      17.64
100	         0.00000616      17.82

Simulation for 1.2mH inductor (air core 32mm frame diameter 0.2mm copper wire 75mm winding length)
with Series Resistance=32.909, Parallel resistance=2.680319Meg, Parallel capacitance=1.343pF
F_ref=1.436MHz, Q=330 according to Coil64

Stepping C_hand from 0pF to 2pF with 0.025pF step.
For Teensy 4.0 MCU working at 600MHz, FlexPWM resolution = F_BUS = F_CPU/4 = 150MHz
Divider for 150MHz to get value close to 1.436MHz is 110. So, period length in bits is log2(110)=6.78, for both edges measured one more big is added: 7.78
For F_CPU overclocked to 800MH, F_BUS=200MHz, and divider = 147. Period length in bits = 7.2, for both edges it's 8.2

Running simulation, and choosing widest 0.025pF step and calculating "zoom factor" - T_step / T_fref
0.0151/0.693 = 0.021789 = 2.18% of measurable range corresponds 0.025pF C_hand change near resonance.
MCU should tune F_ref with infinite hand distance to match peak of resonance (step of ref freq should cause max step in measured phase shift).
According to distance-to-C_Hand table, 0.025pF corresponds to hand distance ~33cm (C_hand is changed 1.5..0.025 for distances 1cm..33cm).
All bigger distances fall into single 0.025pF interval.

F_BUS=150MHz, log2(110*0.0218)+1=1.26+1=2.26 bits for non-overclocked MCU left for distances >33cm
F_BUS=200MHz, log2(147*0.0218)+1=1.68+1=2.68 bits for 800MHz overclocked MCU left for distances >33cm
(+1 bit is a bonus for both edges measurement)



To increase number of available bits we have to use averaging.
Default parameters of Teensy audio library: F_sample=44100, AUDIO_BLOCK_SAMPLES=128 give 44100/128=344.53 frames per second, frame length=(1/344.53)*1000ms=2.9ms
We have new measure results once per 1.436MHz cycle, 1436000 times per second, 1436000/344.53=4168 measures per 2.9ms audio frame.
If we do averaging for single audio frame w/o overlaps, we should get additional log2(4168)=12 bits for measured phase shift due to averaging.

Measured phase shift will be a number in range 0..110-1
Both edges give 0..110*2-1 = 0..220-1
Averaging (simple sum) of 4168 measurements gives values in range 0..220*4168-0..916960
Near resonance, for 0.025pF range, values will vary by 916960*0.0218=19989.728 log2 = 14.29



2.26+12=14.26 bits for non-overclocked Teensy 4 with F_BUS=150MHz
2.68+12=14.68 bits for overclocked Teensy 4 with F_BUS=200MHz


Let's check how number of available bits reduces after 33cm

Quantization - number of different values from sensor per cm of distance can be calculated as difference between output values with 1cm distance difference: log2(bits_left(dist))-log2(bits_left(dist+1cm))

Values per cm - expected number of different values from sensor averaged for 1 frame length, for distance changed by +-0.5cm

Code:
dist, cm   C_hand, pF   Bits lost  Lost after 33cm	bits left   values per cm
--------   ----------   ---------  ---------------  ---------   -------------
33         0.02723162   5.76       0.00             14.26	    2301.31
34         0.02402518   5.94       0.18             14.08	    2031.37
35         0.02119629   6.12       0.36             13.90	    1793.10
36         0.01870050   6.30       0.54             13.72	    1582.77
37         0.01649857   6.48       0.72             13.54	    1397.12
38         0.01455591   6.66       0.90             13.36	    1233.24
39         0.01284200   6.84       1.08             13.18	    1088.58
40         0.01132990   7.02       1.26             13.00	     960.90
41         0.00999584   7.20       1.44             12.82	     848.19
42         0.00881886   7.38       1.62             12.64	     748.70
43         0.00778046   7.56       1.80             12.46	     660.88
44         0.00686434   7.74       1.98             12.28	     583.36
45         0.00605608   7.92       2.16             12.10	     514.93
46         0.00534300   8.10       2.34             11.92	     454.53
47         0.00471388   8.28       2.52             11.74	     401.22
48         0.00415883   8.46       2.70             11.56	     354.16
49         0.00366914   8.64       2.88             11.38	     312.61
50         0.00323711   8.82       3.06             11.20	     275.95
51         0.00285595   9.00       3.24             11.02	     243.58
52         0.00251967   9.18       3.42             10.84	     215.01
53         0.00222299   9.36       3.60             10.66	     189.79
54         0.00196124   9.54       3.78             10.48	     167.53
55         0.00173031   9.72       3.96             10.30	     147.88
56         0.00152657   9.90       4.14             10.12	     130.53
57         0.00134682   10.08      4.32              9.94        115.22
58         0.00118824   10.26      4.50              9.76        101.70
59         0.00104833   10.44      4.68              9.58         89.77
60         0.00092489   10.62      4.86              9.40         79.24
61         0.00081599   10.80      5.04              9.22         69.95
62         0.00071991   10.98      5.22              9.04         61.74
63         0.00063514   11.16      5.40              8.86         54.50
64         0.00056035   11.34      5.58              8.68         48.11
65         0.00049437   11.52      5.76              8.50         42.47
66         0.00043616   11.70      5.94              8.32         37.48
67         0.00038481   11.88      6.12              8.14         33.09
68         0.00033950   12.06      6.30              7.96         29.21
69         0.00029952   12.24      6.48              7.78         25.78
70         0.00026425   12.42      6.66              7.60         22.76
71         0.00023314   12.60      6.84              7.42         20.09
72         0.00020569   12.78      7.02              7.24         17.73
73         0.00018147   12.96      7.20              7.06         15.65
74         0.00016010   13.14      7.38              6.88         13.82
75         0.00014125   13.32      7.56              6.70         12.20
76         0.00012462   13.50      7.74              6.52         10.76
77         0.00010994   13.68      7.92              6.34          9.50
78         0.00009700   13.86      8.10              6.16          8.39
79         0.00008558   14.04      8.28              5.98          7.40
80         0.00007550   14.22      8.46              5.80          6.54
81         0.00006661   14.40      8.64              5.62          5.77
82         0.00005877   14.58      8.82              5.44          5.09
83         0.00005185   14.76      9.00              5.26          4.49
84         0.00004574   14.94      9.18              5.08          3.97
85         0.00004036   15.12      9.36              4.90          3.50
86         0.00003561   15.30      9.54              4.72          3.09
87         0.00003141   15.48      9.72              4.54          2.73
88         0.00002771   15.66      9.90              4.36          2.41
89         0.00002445   15.84     10.08              4.18          2.13
90         0.00002157   16.02     10.26              4.00          1.88
91         0.00001903   16.20     10.44              3.82          1.66
92         0.00001679   16.38     10.62              3.64          1.46
93         0.00001481   16.56     10.80              3.46          1.29
94         0.00001307   16.74     10.98              3.28          1.14
95         0.00001153   16.92     11.16              3.10          1.01
96         0.00001017   17.10     11.34              2.92          0.89
97         0.00000898   17.28     11.52              2.74          0.78
98         0.00000792   17.46     11.70              2.56          0.69
99         0.00000699   17.64     11.88              2.38          0.61

For 5 octaves set for note range, 1cm per halfnote, 1..61cm range we have 1cm per halfnote.

To see max working range, let's look when number of values per cm falls below acceptable.
At 57.5..58.5 cm range we see 101 distinct values. It's pretty good - one cent resolution.
At 75 cm distance, there are 12 distinct values. It's conditionally acceptable.
At 80 cm we see 6 values per halftone - should be audible if we are not considering automatic smoothing due to different measured values in different frames.
At 90 cm we fall below 2 values per halftone - can consider this as sensitivity limit.

So, I'm expecting at least 70-80 cm of practical playable distance from sensor with these parameters.

======

Sensor prototype PCB is updated (simplified):

phase_shift_sensor_pcb_optimized_1_2mh_prototype.png


KiCAD 3D render of prototype PCB:

phase_shift_sensor_pcb_optimized_1_2mh_prototype_kicad_3drender.png


KiCAD project is available on GitHub
 
have you modeled the pcb parasitics? It is common to see 1-2pf /cm capacitance between adjacent traces. I would expect to see
ground planes and tighter spacing and RF connectors for a
 
have you modeled the pcb parasitics? It is common to see 1-2pf /cm capacitance between adjacent traces. I would expect to see
ground planes and tighter spacing and RF connectors for a

I didn't try to model parasitic capacitance of PCB.

It makes sense to add ground plane below reference frequency buffer cirquit.
Trace from antenna/inductor output should be thin and w/o ground plane imho.

PCB for production version will be smaller - 2x5cm, placed inside inductor frame - 32mm ppl pipe.
Wires from inductor to PCB and from PCB to antenna will be short enough. ~5-7cm for to inductor, 10cm for antenna.

phase_shift_sensor_pcb_optimized_1_2mh_smd_kicad_3drender.png


I've tried to play with model component parameters a bit more and found interesting thing.
It's not necessary to minimize C on inductor output (C_ant+C_hand) to have better sensitivity. At first sight, we have to maximize K_C = C_hand/(C_ant+C_hand).
But actually, Q of serial LC grows with increasing of C, and increased Q can compensate decreased K_C = C_hand / (C_ant+C_hand+C_add).
Adding of C_add 3..10pF between antenna and ground almost does not decrease sensitivity of phase shift to C_hand changes.
It's expected to have 2-3% of phase shift change for 0.025pF C_hand capacity change near LC resonance. (It corresponds to all distances > 33cm -- all destances bigger than 33cm will be visible as 2-3% change of measured phase shift value).
Additional benefit from increased C is smaller LC resonant frequency. The smaller F_ref is, the closer is possible to tune FlexPWM generated F_ref (150 or 200MHz F_BUS with integer divider) to LC resonance.
If F_ref is too far from resonance (for far hand distance), benefit from high Q of LC will be eliminated.

Additional findings:
Parallel LC (comparing to serial LC described above) has lower sensitivity.
Good results may be achieved with 0.2mm wire air core inductor.
If LC is driven by 5V instead of 3.3V, sensitivity of sensor grows accordingly (antenna swing increases from +-100V to +-150V).
Several invertors connected in parallel to increase output current / edge sharpness increase sensitivity as well.
Max sensitivity I saw in model was about 14% of output value range for most zoomed 0.1pF C range.

Testing on real HW should show if this approach is working, and if Teensy 4.0 MCU PWM module is precise enough to measure phase shift enough for use in theremin.

I've soldered simple prototype PCB:

phase_shift_sensor_proto_pcb_photo.jpg


For 74HC04 and SP721 where are sockets for easy replacement. (E.g., experiment - what is better, 74AC04 or 74HC04).
Passive components to play with will be mounted to sockets, too: R for driving of inductor, C between antenna and input buffer, C between antenna and ground.

Just in case, caps are made of 3 bigger caps connected serially. Reason: high expected voltage swing on antenna (up to 400Vpp).
50V caps may be broken by higher voltage.

Going to test this board soon.
 
I would use ground plane techniques and dead bug soldering: http://home.sandiego.edu/~ekim/otherjunk/rf_proto.pdf.

There are a lot of choices in the 74HC04 family. You could try the LVC and LV flavors and the one and two gate tiny SMT versions. I use
the 74HCU04 often too. That's probably a better choice if you plan to put the gates in parallel.


Thank you for sharing of useful link!
Modern SMD 1-2 gate logic ICs are nice for compact PCBs.
It doesn't make sense to use RF connectors for inductor and antenna connection.
Anyway, only 1 wire is needed. Using of RF cable will add unwanted capacity between antenna and ground which would reduce sensitivity.
For main connector, probably easy way is to solder 1.27mm pitch ribbon cable directly to PCB pins.
Output signal (most sensitive to noise) is placed between two ground wires. Reference frequency signal (less sensitive to noise) - between ground and +5V.
Cable length will be 10-15cm. I beleive it should be ok for frequencies 0.7..1MHz.

Played a bit more with LTSpice simulation.
Found 74AHC1G04 spice model - to be used instead of 74HC04.
With 1..1.5mH inductor (0.2mm wire), F_ref is in range 1.3..1.5MHz for which quantization of possible values (integer division of F_CLK) is not enough for fine tuning to position near resonance.
With 0.1mm wire and 2-3mH inductor, with 0.6..1MHz F_ref, step of F_ref is fine enough to tune F_ref to have phase shift delta close to max possible value for far hand distance.
0.1mm inductor has bigger series R, and there is no such big Q gain if two buffers are connected in parallel (inductor drive current is smaller).
5V VCC instead of 3.3V on inductor drive buffer gives visible sensitivity improvement.
So, let's use separate buffer+ESD for driving of LC with 5V supply, and buffer+ESD for phase shifted input with 3.3V supply.
Since input buffer is separated from drive buffer, and uses dedicated 3.3V regulator, there should be less noise in output signal.


Small packages will be used for buffer and ESD protection.
Buffer: 74LVC2G04
ESD protection: IP4220CZ6

In LTSpice simulation, 74AHC1G04 is used (didn't find LVC model).

phase_shift_sensor_board_ltspice_model.png

Simulation results: C_hand varies from 0 to 2pF with 0.025pF step. Leftmost (widest) step corresponds to far hand distance.
(Actually, values for all distances > 33cm will fall into this interval).

phase_shift_sensor_board_ltspice_simulation.jpg

KiCad schematics and PCB 3D render.
20mm width PCB will be placed inside 32mm plastic water pipe which serves as both antenna mount and inductor frame.
Almost unused 40-50mm of PCB is place where coils will be winded. So, main part of sensor PCB will be outside of inductor.
Bottom layer of PCB is GND plane for part outside of inductor.
Inductor side close near wide connector is input - there is 5V voltage swing.
Opposite side - inductor_out and antenna pins - has 80-150V of voltage swing.

phase_shift_sensor_board_kicad.jpg

I'm planning just soldering of wires for inductor, antenna and main sensor connector.
 
Pipe Monster v4 digital theremin antenna and sensors mounting.

Made of 20mm and 32mm PPL pipes and fittings.
Antenna sizes and distance between antennas - like in Etherwave.
32mm pipe pieces (coil + sensor PCB) will be fastened with screws to 20mm pipe pieces welded to fittings.

pipe_monster_v4_partially_assembled.jpg

Bottom 1/2" female thread fitting - mic stand mount (1/2" water pipe male to 3/8" 24 thread female adapter needed) or table mount.

pipe_monster_v4_assembled_nocoils.jpg

Two top 1/2" female fittings - for mounting of cabinet (with 1/2" to 3/8" male-female adapters as nuts). Cables from sensors will go through these 3/8" holes.

pipe_monster_v4_cabinet_mounting.jpg

Inside 32mm pipe, there is
Coils should be winded with 0.1mm copper wire (40..50mm winding length) closer to antenna.
Sensor PCB should be oriented to have main parts outside of coils.

pipe_monster_v4_sensor_pcb_connections.jpg

PhaseShift library development progress update: polling of captured values working fine, DMA support - development in progress.
 
Last edited:
Theremin GUI on previous (abandoned project) version of teensy theremin - on Teensy 3.6

teensy_theremin_gui_on_hardware.jpg

Teensy 3.6 performance is too low. E.g. 60MHz F_BUS gives too low precision for reference frequency.
Phase shift was converted to PWM duty cycle on XOR gate, then passed through LP filter, then read using ADC analogRead().
Teensy 4.0 version has better resolution (200MHz F_BUS for 800MHz overclocked T4), which is enough for tuning of reference frequency.
PWM -> LP filter -> ADC chain is removed completely and replaced with simple LC phase shift circuit on two buffers.
Phase shifted output of sensor is being measured directly by Teensy 4 - thanks to FlexPWM modules.


Simulator (C++, win32 API), now being rewritten using Qt.

teensy_theremin_emulator_screenshot1.png

Simulator allows to develop and debug most of code on PC.
ILI LCD, audio I/O, pots, encoders, and theremin sensors are being emulated.
Most of code: GUI, synthesizer, etc, is reused from firmware. Sketch is just included into simulator code.
Theremin sensors are emulated with GUI box - using mouse. Horizontal position - pitch. Vertical - volume. With using of Wacom tablet, it's even playable :)

Idea: print sensors output to Serial from Teensy, and use in simulator as sensors value.
 
Project status update:
Received ordered phase shift sensor PCBs from pcbway.
Going to solder and test.
DMA code is not ready yet, but direct polling of FlexPWM capture registers is enough for testing.
 
Another theremin sensor design for Teensy 4.

I've changed plan once again - completely different theremin sensor schematic.
Phase shift sensor seems worse than classic heterodyne.

Teensy 4 will work overclocked (with heatsink) at 960MHz. This gives 240MHz bus clock - better timer resolutions.

Instead of phase shift, let's use invertor based oscillator producing square wave ~800-1100KHz depending on inductor.

Heterodyne is based on analog switch IC : reference frequency signal with duty cycle < 50% is used to control switch.
Part of oscillator period is "sampled" every reference clock cycle, then averaged by LP filter, and converted to square.


LTSpice model:

inv_osc_analog_switch_heterodyne_ltspice_model_schematic.png


Antenna voltage:

inv_osc_analog_switch_heterodyne_ltspice_model_simulation_results_antenna_voltage.png

Heterodyne filter ouput:

inv_osc_analog_switch_heterodyne_ltspice_model_simulation_results_het_filter_out.jpg

After heterodyne output buffer:

inv_osc_analog_switch_heterodyne_ltspice_model_simulation_results_het_square_out.png



Oscillator produces F_max-F_min ~ 65KHz output frequency range (for far / near hand distances - C_hand=0..1.5pF).

Reference clock should be 4KHz bigger than minimal oscillator frequency (hand far from antenna) to avoid 16bit timer counter overflow.
240MHz cpu gives possible reference frequency values with steps ~3.5-4KHz.
So, heterodyne output will be in range 4KHz..70KHz .. 8KHz..74KHz depending on nearest available reference frequency.

Theoretical sensitivity - calculated assuming hand near antenna adds 1.5pF, and decreases 3.8 times each 10cm.

Bwelow, T_fbus is number of MCU F_BUS cycles (240MHz) in one output signal period.

Sensitivity near 80cm distance:
For 80cm C_hand = 0.00007550pF F_out = 4003.532 T_fbus = 59947.06598
For 81cm C_hand = 0.00006661pF F_out = 4003.084 T_fbus = 59953.77732
Difference in measured T_fbus for 80..81cm range is 6.711339738 F_BUS clock cycles (at ~4KHz)
Measuring of both raising and falling edges gives x2 better sensitivity: 13.42267948
Summary for 1ms (x4 times) gives 53.6907179 f_bus cycles.
So, at 80cm, we have ~53 distinct values measured for 1ms interval (0.2mm precision).
Bigger averaging gives bigger precision.


Sensitivity near 90cm distance:
For 80cm C_hand = 0.00002157pF F_out = 4000.813 T_fbus = 59987.8021
For 81cm C_hand = 0.00001903pF F_out = 4000.685 T_fbus = 59989.7221
Difference in measured T_fbus for 90..91cm range is 1.919994632 F_BUS clock cycles (at ~4KHz)
Measuring of both raising and falling edges gives x2 better sensitivity: 3.839989264
Summary for 1ms (x4 times) gives 15.35995706 f_bus cycles.
So, at 90cm, we have ~15 distinct values measured for 1ms interval (0.7mm precision).
Bigger averaging gives bigger precision.
Actually, even if no values outside 1ms frame are summarized, "autosmoothing" will work due to dithering between note frequencies calculated for sequential frames.


Oscillator PCB - KiCad schematic:

inv_oscillator_kicad_schematic.png

Oscillator PCB - KiCad 3d render:

inv_oscillator_kicad_pcb_3d_render.png

Gerber file preview

inv_oscillator_kicad_pcb_gerber_view_top.png

inv_oscillator_kicad_pcb_gerber_view_bottom.png


Heterodyne PCB (dual channel) - KiCad schematic:

analog_switch_heterodyne_pcb_kicad_pcb_3d_render.png

Heterodyne PCB (dual channel) - 3d render:

analog_switch_heterodyne_pcb_kicad_schematic.png

Gerber file preview

analog_switch_heterodyne_pcb_kicad_pcb_gerber_view_top.png


analog_switch_heterodyne_pcb_kicad_pcb_gerber_view_bottom.png


Bypassing 16 bit counter limit.

With eFlexPWM instead of Quad Timer, it's possible to measure intervals longer than 16bit counter (4ms) - using 4 bit cycle counter.
So min frequency diff (between F_ref and F_osc with hand far from antenna) may be 0.25ms / 250Hz.
With 1000Hz min diff, precision at 1m distance is 0.6mm for single mixer output clock cycle (1ms) even w/o additional averaging.
Capture value and capture cycle registers lay in memory in consequent addresses, so they can be read by the same DMA channel.

Bypassing F_ref quantization.

At 960MHz CPU and 240MHz bus clock, dividers 240, 241, 242 produce freqency 1000000.00Hz, 995850.62Hz, 991735.54Hz - steps ~4.2KHz
So, if we try to set frequency close to some value, actual value may be up to 4.2KHz from ideal (requested) frequency.
Instead of 1KHz frequency diff, we could get 5.2KHz - and have 47mm quantization instead of 1.76mm with 1KHz offset.

With eFlexPWM, it's possible to use fractional part (FRACVAL1 5 bit register) to "dither" generated F_ref period.
I'm not sure if it would work fine, but hopefully it will allow to have *32 smoother F_ref quantization.
 
Hello,

I 'm trying to make a theremin sensor. (only the sensor part)
I read this post and was wondering if the schematic titled "theremin sensor 3.3v" could do the job?
I'm using a 3.2 teensy + audioshield,
I will be very pleased if you could send me any suggestion

Thanks!
 
Status
Not open for further replies.
Back
Top