Update 2020: Several people have asked for the firmware source code, and you can now find the code on GitHub. It ain't pretty, but should give you an idea of how this whole thing fit together.

After building the nixie tube alarm clock, which incorporates a bright, self-dimming light intended to wake me up gently, I wanted to use it to induce a lucid dream state [1]. I tried rapidly flashing the bright light at around 5 AM, hoping it would coincide with a dream, but I had little luck. I had to be able to detect REM sleep in order to affect my dreams, as most dreams occur in the REM phase of sleep.

The method of using flashing lights to stimulate a person in REM-sleep has been shown to be effective by several researchers [2]. In one study, flashing lights were administered through goggles worn by the sleeper, inducing lucidity 33 times over a total of 58 nights with 44 subjects (LaBerge, Levitan, Rich, & Dement, 1988) -- many of which had never experienced lucid dreams prior to the study. I urge you to look at LaBerge's article if you find this interesting, it is a wonderful read.

The more successful trials use various methods of electrophysiological techniques (i.e. EEG, EOG, EMG, MRI etc.) to detect rapid eye movement (REM) sleep in the subject and then stimulating their eyes with flashing lights. The lights would often manifest themselves in the subject's dreams as howling ambulances, lightning and such, which indicated to the subject that they were indeed dreaming, thus entering a lucid state. This seemed like a promising place for me to start. I am also planning to use aural stimulation by playing Edith Piaf's Non, Je Ne Regrette Rien (as made famous by the movie Inception), because it would be awesome to enter a lucid dream state on her que.

I went on to ask my mother, who used to work with EEG equipment back in the day, if she had any electrodes or other equipment of interest laying around. She did, and I managed to procure two EEG caps, some adhesive conductive electrode paste and a rather nasty abrasive compound. After studying the possible methods through which one can detect REM sleep, I settled on electrooculography (EOG) as my method of detection [3], as it looked fairly straightforward.

I'm glad you asked. This wonderful article explains everything in detail. Long story short: There is a standing potential in your eye between the cornea and the retina, which is in the range of 0.4-1.0 mV. This potential is caused by the higher metabolic rate in your retina. Biology aside, this means that every time you move your eyes, you are also changing the surface potential of the skin surrounding your eyes. This potential change is measurable, though you need a good electrical connection between your electrodes and the skin in order to suppress noise and allow the voltages to be visible. You also need a large amplification factor in order to be able to read this voltage with a "mortal" ADC like the ones you'll find in the generic MCUs.

Naturally, I am not the first to think of doing this kind of experiment. I stumbled across Jona Frank and Pranav Ravichandran's article on logging EOG data with an Arduino for a simple BCI system, as well as chipstein's Google Site regarding EOG in general and a few methods of home-use [4][5], collecting ideas for circuit designs. Their approaches are similar in design in that they use an instrumentation amplifier as a preamplifier stage before they drive the signal through some heavy filters, and finally amplifying the signal further with generic opamps. A big thanks goes to these guys for documenting and publishing their work for the general public.

I figured that, since I am not interested in the eye's absolute position in reference to the skull, three electrodes would suffice: One reference electrode on my forehead and two electrodes at either temple. This method restricts the system to being sensitive to lateral eye movement only, but after a rather disturbing YouTube session of watching people experiencing REM sleep, I decided that lateral eye movement would probably be enough to determine whether or not I am experiencing REM sleep.

It was necessary to rip open the electrode caps I had in order to extract the electrodes, which seem to consist of some semi-pliable metal which most likely offers excellent conductivity. The electrode paste, when sandwiched between my skin and the electrode disk, makes a great basis for EOG measurements. Without paste, the resistance between my temples were in the order of megaohms. With the paste and a tight headband to keep everything in place, I was down below 10 kiloohms, exactly where I wanted to be -- even in spite of the fact that the paste expired in '87. This stuff is fascinating.

Fastening the electrodes to my skin was initially done (rather crudely) by means of scotch tape and a hedband to keep everything in place. I later moved to using stretchy band aids and paper padding which greatly improved comfort and system stability (noise and baseline offsets from breathing and tossing about in bed). The abrasive compound does an excellent job of lowering the electrode impedance to well below 3 kΩ, but after getting a heavy rash on my temples and forehead, I switched to simply scrubbing the electrode sites with warm water. This does increase electrode impedance somewhat, but at least my skin won't fall off.

I also made a fun discovery: When I put the multimeter in continuity mode and measure across the electrodes in my temples, I can clearly see rapidly flashing lights emanating from the corners of my eyes. The effect persists if I close my eyes. This must mean that the weak current from the multimeter is stimulating the optic nerve somehow. It would be cool to directly stimulate the optic nerve in order to induce the flashing lights, but I am not sure sending current through my head is the best idea. I am learning all sorts of trivia about human biology through this project.

Electrodes, conductive paste and an abrasive compound (which gave me a nasty rash)

After diligently taking notes from the aforementioned articles and simulating everything in LTspice along the way, I designed the following circuit in CadSoft Eagle (click to enlarge):

I went with the AD620, a readily available instrumentation amplifier, as my preamp stage amplifier (I later changed this to the INA126PA which offers similar electrical characteristics, identical pinout but uses a different gain calculation). Apart from the electrodes and conductive paste, this SOIC is probably the single most expensive part of the project (my dignity not included). The resistor between the Rg pins set the gain of the amplifier to around 30. The signal is then high pass filtered with a 1st order HPF with a cut-off frequency of around 1 Hz. I chose to high-pass filter the signal here rather than at the end of the amplification track because simulation of the circuit in LTspice claimed that the latter choice would be unstable and prone to noise. Breadboard testing confirmed this. The signal is then amplified in a non-inverting amplifier with a gain factor of around 30 before it is passed through a 2nd order LPF with cut-off at around 17 Hz. This brings the total theoretical amplification of the circuit, not accounting for the filtering, to around 900.

All amplification and filtering is done in reference to virtual ground (denoted GND in the schematic above) which is generated by a voltage divider and a voltage follower. GND is also connected to the reference electrode in my forehead, thus grounding the circuit to my "baseline skull potential". The amplified and filtered signal is fed into the ADC of an ATMega168. According to LTspice, there should be very little harmonic distortion through the circuit. During initial tests I was using an Arduino Uno and a Diligent Analog Discovery 2 to program, probe, test and debug my circuit.

I was struggling with 50 Hz noise from the mains grid, as one generally does in high-gain circuits. Adding higher orders to my LPF was possible, but I found a much cleaner solution: I set the sample frequency of the ADC to 50 Hz, effectively rendering the noise moot. The 50 Hz noise is aliased into a DC (or a slow sine due to inaccuracies in the frequency from internal/external oscillators) which is killed by the aggressive 1 Hz high pass filter in my circuit. The EOG signals, ranging from around 3 to 10 Hz, are not affected as the sample frequency is well above the Nyquist frequency. This helped a great deal with all the noise my breadboard monster picked up.

One of the great aspects of differential amplifiers is that the signal wires, though only conveying millivolts, can be several meters long without much additional noise appearing in the circuit. Any induced emf on the signal wires will be equally distributed over the wires, thus cancelling it out. Hooking the electrodes to the breadboard with ribbon cable, I was able to sleep with the system logging my eye movements through PuTTY. This allowed me to study trends, amplitudes and timings, and devising a detection algorithm.

Initial testing was not pretty. It was effective, though.

LTspice simulation of the circuit. Input signals are in the order of 0.5 mV and are simulated with noise in the 30-50 Hz range. The green, blue, red and finally white signals are probed from successive points in the amplification stages.

Parallel to breadboard testing, I designed the circuit board with noise suppression in mind, trying to follow general guidelines for analog high-gain circuit design and PCB layout [6]:

  • Keep signal tracks short
    • trace width is .3048 mm, the smallest tolerance I can reliably handle with the laser etch method
  • Keep analog and digital tracks well seperated
    • I left a large gap between analog circuitry on the left and digital circuitry on the right
  • Keep analog and digital ground seperated
    • same as above
  • Don't run analog traces perpendicular to any noisy trakcs (e.g. RX/TX)
    • the final analog trace is running diagonally through the board
  • Use bypass capacitors where needed
    • 1 µF caps scattered throughout

Here is the layout I settled on:

Top view: Flodded plane carries V-. V+ is traced along the perimeter and is fed to the ATmega through a via and a trace on the bottom layer.

Bottom view: Flooded plane carries GND. Vias and traced allow current to be sinked from amplifier stage, well away from the digital part of the circuit.

The datasheet of the ATmega168 calls for an LC network supporting AREF pin, which I did not realize until after producing the circuit board. It doesn't seem like a problem, though; The ADC readings seem stable. I struggled a lot with the etching process. On my fourth try I succeded.

The finished PCB. Note the bodge on the voltage follower -- I had flipped the opamp in the schematic. It's fixed in the version provided.

One of the several failed etches. This method is very unforgiving.

The PCB proved to be much less noise-riddled than the breadboard test (unsurprisingly). Below you see the data from a short session of eye-exercises (blue) as well as the data from my REM sleep detection algorithm (red). This data validates the success of the amplification circuit as well as the feasibility of a reliable "eye movement" detection algorithm.

Below you see data from the morning of May 5th, showing what both I and my REM detection algorithm agree is the end of REM phase. Click image to expand.

At this stage in the project (May 15) I have a fairly reliable detection algorithm for REM sleep. I ordered some some bright, 0.5 W warm white SMD LEDs from eBay, and have implemented them into the system. They are sewn into the front part of the headband, and lie just a few millimeters away from my eyelids when I pull the mask down to sleep. The lights are flashed rapidly for 10 seconds whenever the ATmega decides that I am in REM sleep.

After sleeping with the system every night for nearly two weeks, though, I have yet to experience any lucid dreams or even remembering the flashing lights the morning after. The photo on the right shows the brightness of the LEDs, and I find it truly astonishing that I can sleep through such relentless visual noise without waking up. It's frustrating knowing that the system works perfectly, and that the problem is in the driver's seat. I think it's time to rethink my method of induction.

The lucid induction LEDs are fairly bright...

I have huge hopes for music-induced lucid dreaming -- there must be a reason why the production team behind Inception opted for audio rather than light for communicating through the dream levels! I have therefore written a short Python program which captures the serial data over USB and uses the VLC package to play a 30 second snippet of 'Non, Je Ne Regrette Rien' when the ATmega detects REM sleep. Below you see an image of the system as it is today (Sep. 19) after I added a 3.5 mm audio cable to the umbilical cord which connects the system to my computer. It consists of cables en masse, and the umbilical cord running from my head to my computer is getting rather unweildy. I'd love to redesign the project and base it around Bluetooth instead, eliminating all these pesky cables.

My main problem these days is Windows 10. No matter what I do, my computer decides to go to sleep after about half an hour after I go to sleep. Some update has wrecked the power management settings in the OS. This ruins my data logging, of course. It's now September 19, and I'm still fiddling with the settings.

On the upside, though, I have acquired some proper ECG electrodes from 3M which eliminates the hassle of electrode paste and band-aids. I will give them a go tonight.

I hate to admit it, but the system has gotten out of hand. There are too many weak points, in particular along the umbilical cord which connects it to the computer. Furthermore, the PCB I etched the circuit onto seems to be of low quality, and the copper plating has started to lift from the fiberglass in certain places (this might be related to the fact that I omitted all forms of strain relief on the cables, heh). A complete redesign is needed, and that's what I intend to do!

The new 3M electrodes work fantastically though, and I have recently been tinkering with the post-processing of the sleep data. Most notably I am using MATLAB to convert the raw ADC data into WAV which Audacity is more than happy to analyse. Previously I have loaded the CSV file directly into MATLAB and used the native plot functionality which is extremely sluggish both at laoding the data and at displaying it. The new method, though, can run through 4.1 million lines of CSV data and spit out a WAV file in less than 10 seconds. Not only is it significantly faster, but it allows me to perform more in-depth analysis of the data using tools intended for audio processing. Furthermore, I can listen to my eye movement activity if I crank the sample frequency into the audible regime. It's really bizarre.

Mark II of the lucid dream induction system will be based around BLE to get rid of all those cables. Stay tuned!

On the 28th of April our study programme held a stand at NTNU presenting ourselves to visiting High School students. One of my class mates and I were in charge of the stand, and I wore the EOG system as a way to demonstrate what one might expect to learn and do while studying ELSYS. I had a large computer monitor showing an oscilloscope trace from the last stage of the amplification circuit as well as the flowing data from the ATmega on-screen. The students were very intrigued (especially when I explained that I was trying to hack my dreams, Inception style), and it was a lot of fun.

After the stand I realized that PuTTY had logged everything my eyes did over the course of the ~2.5 hours we worked there, and the data is fascinating. I moved my eyes no less than 6715 times. A "move" was defined as an analog spike with an amplitude equal or greater to 17 from the ATmega ADC, which roughly equates to moving my eyes halfway across the screen of a 15.6" laptop at a comfortable distance. Below is an excerpt of the eye movement data (left) and the cumulative "gaze shift counter" (right). Click images to expand.

I also plotted the distribution of gaze shifts by how long time intervals there were between them, expecting the data to be normally distributed. Instead, it seems that the gaze shifts follow some sort of gamma distribution. I later learned that waiting-time processes generally follow such a distribution. I have no idea what to do with this data, though.

Click here to download the raw data (373 kB .rar). Please contact me if you find anything interesting in the data set.

[1] Lucid dreaming: https://en.wikipedia.org/wiki/Lucid_dream
[2] Stephen LaBerge, Ph.D. Psychophysiological Studies of Consciousness during REM Sleep. http://www.lucidity.com/SleepAndCognition.html
[3] Article explaining the basics of electrooculography: http://www.bem.fi/book/28/28.htm
[4] Jona Frank and Pranav Ravichandran. Tracking Eye movement with an Arduino and a Computer. http://onloop.net/hairyplotter/
[5] "chipstein". Homebrew Do-it-yourself EEG, EKG, and EMG. https://sites.google.com/site/chipstein/home-page
[6] Ron Mancini, Editor in chief, TI. Op Amps For Everyone http://web.mit.edu/6.101/www/reference/op_amps_everyone.pdf