Project: EOGee/EOGlass – Summary

For a quick overview of the final design, EOGlass2, please see the summary video here.

I’ve been working on EOGee, my electrooculography project, for almost a year and a half now. I feel like I’ve gotten to a point of marginal returns. There are a number of ways my work so far could be extended, but they each require significant investment in terms or time and/or money for potentially marginal gains. For this reason I have decided to de-focus from this project and focus my energy on new projects where I will learn faster. I may continue this project in the future but for now I want to document all of my efforts so far in one place.

EOGee 1

Introduction to Electrooculography

At the beginning of this project, I wasn’t sure how hard it would be to get even a basic electrooculogram. I had read a little about the topic: Electrooculography relies on the potential different between the retina and the cornea (“corneal-retinal potential difference”) resulting in a potential difference between the subject’s temples depending on the rotation of their eyes. This potential is typically around 500µV peak-to-peak difference between when the subject is looking fully to the left compared to the when the subject is looking fully to the right.

Animation showing how retinal-corneal potential results in a potential difference at the temples.

Circuit Designs

In order to get something I knew would work I decided to base my design on the SpikerShield design from Backyard Brains. This is a multipurpose bio-potential measurement PCB that is intended to connect to an Arduino, and Backyard Brains had examples showing it being used to capture an EOG. Helpfully they published a schematic online, however the output of their PCB is purely analog as it relies on the Arduino’s built in ADC to digitise the data.

The user is connected by a headphone jack to three electrodes – ground, left-channel and right-channel. The ground connection is typically attached to the user’s neck whiles the left- and right-channels are connect to the user’s temples. Silver/Silver-Chloride (Ag/AgCl) electrodes are typically used to connect to the user and are connected to the cable by snap-connectors.

Ag/AgCl electrodes on my temples and neck
SpikerShield V1.51 by Backyard Brains

The key component to this design is the AD8226 differential amplifier which is configured by the value of R6 to have a 4x gain. Input resistors R14 and R15 are protection to prevent dangerous currents into the user in the case of a power fault. This signal is fed into two amplification stages before being passed to the Arduino. The first stage is a 220x gain stage (set by the ratio of R8 and R7) with a 130Hz cut-off low pass filter (set by the values or R8 and C8) using an LMV321 which is a bog-standard op-amp. The signal is AC coupled between the AD8226 and LMV321 by C7. This is necessary as the DC offset would otherwise saturate the output of the LMV321 when amplified 220x times. Finally the signal is passed to the variable gain stage where the gain is set by the ratio of R3 and the potentiometer giving a gain of between 0x and 10x. Two more LMV321 amplifiers are used to generate midrail voltages from the input supply.

From an analog perspective, EOGee1 is identical to the SpikerShield, with the exception that RV101 is mistakenly connected to ground on pin 1 when it should be floating (this is easily fixed with a scalpel). Rather than being connected to an Arduino, EOGee1 is fully self sufficient. The power comes via USB which is filtered, as recommended by FTDI in Application Note AN146, and then dropped to 3.3V by the AP2210 voltage regulator – this should ensure a clean supply. The board also contains an STM32F042 microcontroller that digitises the signal with the built in 12-bit ADC and transmits the data over USB to the host computer.


When laying out the PCB, I didn’t have a clear goal of what I was trying to achieve. I ended up going for this long skinny design because I imagined I could put multiple boards side-by-side to get multiple channels, however ultimately on a 2-layer PCB this resulted in a really bad design from a power distribution and signal integrity standpoint. Nonetheless, the board was able to capture EOG signals, amplify them, digitise them and transmit them over USB.

EOGee1 PCB – clearly it has been reworked and probed multiple times. The coils are added for low inductance oscilloscope probing.

The PCB now shows the signs of all the testing and rework I did, but bringup of the PCB was fairly easy and the STM32 successfully streamed data at 732 samples per second over USB. There was a lot of 60Hz noise that was removed by applying a 60Hz notch filter to the digitised data. (Relevant articles are: Bringing up the analog circuit, streaming fake data over USB, streaming real data over USB, filtering the signal to remove 60Hz mains interference).


AC coupled data streamed via USB: Raw signal in red and filtered signal in blue

The electrooculograms generated by EOGee1 were AC coupled meaning that we only observed a signal when the eyes moved and got no information about the absolute location of the eyes. In the animation above we see a pulse in one direction, representing my eyes moving one way, and then an opposite pulse representing my eyes moving the other way.

Investigations and Experiments

I also compared the impact of using shielded vs unshielded cables which showed that even a small amount of unshielded metal, combined with a few kiloOhm of input impedance, could introduce a large 60Hz noise component. This testing required the design of the SigGenAdapter board that allowed me to inject signals from the signal generator and insert a variable impedance between the signal source and EOGee1. The SigGenAdapter connected to the industry standard snap connectors to mimic the connectors on standard Ag/AgCl electrodes. Because such connectors are not available off the shelf, I created a novel design based on a simple M2 bolt.


The design did, of course, have a number of short comings. The first was noise.

Beyond the 60Hz interference that is typical when sensing such a small, high-impedance signal, EOGee1 also had quite a large intrinsic hardware noise. By removing R108, the inputs of the system were disconnected and the noise contribution from the final gain stage and digital sampling could be isolated. I showed in a previous article that hardware noise could be dramatically reduced by transmitting data over a SPI interface rather than USB. Data transmitted over USB saw a peak-to-peak noise of approximately 30 counts (11µV) whereas data transmitted over SPI saw a peak-to-peak noise of approximately 4 counts (1.5µV). It was not clear whether SPI generated less noise at the input to the ADC than USB, however because the STM32 was the master of the SPI bus but only a device on the USB bus, it was possible to ensure no digital interactions occurred during analog sampling when transmitting data over SPI, whereas USB data transfer could occur at anytime and potentially during analog sampling. This issue was made worse by the poor PCB layout and the microcontroller selection.

Screenshot 2020-04-12 at 00.22.43
Sampled data with analog inputs shorted to ground when data is transmitted over SPI or USB

Because I had used the internal ADC of the microcontroller, and selected a version of the microcontroller with only one ground pin, it was clear that both the analog and digital currents were flowing through the same region of copper. Not to mention that because I was using a 2-layer PCB, the power distribution was pretty poor and the return currents constrained. All of this resulted in a large cross-talk between the analog and digital sections, resulting in the large noise we observed when USB operated at the same time as ADC sampling.

Illustration of analog (yellow) and digital (blue) current loops flowing through the microcontroller pins to the decoupling capacitors

AC vs DC Coupling

The biggest flaw of this design however is the AC coupled signal. As previously mentioned, a capacitor C113 is used to couple the signal between the first and second amplifiers in order to only let AC signals pass, which is effective in rejecting the offset voltages but also totally wipes out any DC signal, representing the true position of the eyes. This is necessary because with the huge amount of gain between the input and the ADC (up to 8800x), even a small DC offset signal would totally saturate the 3.3V amplifiers, but also means we only see a signal when the eyes move and are unable to measure an absolute position.

This DC offset signal comes from a number of sources, but one key source is the voltage generated between the subject and the electrode due to the chemical reaction that occurs at the interface between the two. This reaction involves the transfer of electrons between the silver electrodes and the silver-chloride solution of the Ag/AgCl electrodes and allows the electron current of the measurement circuit to be translated into the ion current in the subject’s body.

Screenshot 2020-04-07 at 22.06.58

In combination with the subject’s skin, this creates a potential between the subject and the electrode. Because we are taking a differential measurement between the user’s temples, these potentials should theoretically cancel out resulting in zero net voltage, however the potential of each electrode is subject to small differences in the electrodes and the concentration of the silver chloride solution. This results in a small voltage difference between the two and a net offset voltage. In a previous experiment I was able to charge a pair of back-to-back Ag/AgCl electrodes up to 800mV – although such a large voltage would not occur in practice.

Screenshot 2020-04-07 at 22.14.27
The voltage potential between the electrodes and the user on each of the temples

In reality I was seeing offsets of around 10mV and though this may be considered “small” in absolute terms, it is still 20x larger than the biggest EOG signal. On a few occasions I was lucky enough to get the setup just right such that there was minimal offset voltage and by shorting C113 I could DC couple the signal and observe the true signal – I could clearly see that the eye position resulted in a strong and clear signal, proportional to the direction of the my eye’s which motivated me to solve this offset problem and come up with my next design – EOGee2.

One of my first DC coupled electrooculograms


EOGee2 was intended to be more of a development platform to enable DC coupling of the signal. As such it is a much larger board and also has a few more features than EOGee1, including many more test points to enable easy probing.


Key Changes from EOGee1

Firstly, EOGee2 fixed the USB noise issue from EOGee1 through a combination of improved layout (this design had much more space) and also component selection: although I was still using the internal ADC of the microcontroller, the microcontroller I selected had dedicated digital and analog ground pins allowing greater separation of the analog and digital current. This brought the noise down from 30 ADC (11µV) counts peak-to-peak to only 7 (2.6µV) (although in reality this is not a fair comparison as I include the full analog noise in the EOGee2 measurements whereas the EOGee1 measurement was only the final amplifier noise).

The design also replaced the potentiometer of EOGee1 with a digitally trimmed potentiometer, MCP41010, which allowed the gain of the system to be modified through firmware rather than with a screwdriver. Ultimately I did not use this feature much and left the gain at maximum setting most of the time.

The biggest change however was the use of the microcontroller’s DAC to generate a reference signal for the AD8226.

Enabling DC Coupling

EOGee2 signal chain

By feeding a signal back to the AD8226 Vref pin the offset of the output voltage could be controlled. Effectively this can be seen as adding or subtracting a voltage from the output of the AD8226, allowing us to remove most of the DC offset before feeding the signal into the following amplifications stages. Whenever the signal was too close to the maximum or minimum value of the ADC, the microcontroller would adjust the reference voltage to recenter the signal as illustrated below. The gain of each stage was also re-optimised to ensure as much gain as possible occurred at the beginning of the signal chain to minimise hardware noise – the gain of the AD8226 was bumped up to 67x from 4x.

The microcontroller recenters the signal by adjusting the DAC


Overall this approach was very successful and allowed me to capture electrooculograms that very clearly correlated to the eye movement. This is demonstrated in the following (low-quality) video in which I perform a number of large and small saccades as well as smooth pursuit. You can clearly see that my eye movements translate into the output voltage. In this case the glasses do absolutely nothing other than support the EOGee2 hardware, but are a preview of my next steps in developing EOGlass1 – the first totally head mounted version of EOGee.


After proving out the DC coupling concept I wanted to spend some time on miniaturisation to show how EOG data could be collected in a minimally invasive way. The first step was to fit the EOGee2 system into a head-mounted form factor that looked like a normal pair of glasses – EOGlass1.

Miniaturisation and Glasses Design

Wireframe rendering of EOGlass1

I designed a pair of glasses in Fusion360 to be 3D printed in three parts, the face and the two arms, and then held together with bolts. On the right arm I created space for the PCB as well as two connection points for the right-temple electrode and the ground electrode. On the left arm was the connection point for the left-temple electrode.

The wire from the PCB (on the right arm) to the left-temple electrode (on the left arm) was passed through a channel in the face of the glasses so that it was invisible when worn.

Wire routing between the electrodes and the PCB

In order to maintain a natural-looking form factor the PCB had to be shrunk down to only 25x11mm. While this was achievable using the same components as EOGee2 by moving to a 4-layer PCB, there was no space for mounting holes to attach the PCB to the glasses or for connectors to connect the electrode wires. This meant that the PCB was held in place only by a plastic clip and the electrode wires were also soldered in place in each corner. In general I aim to ensure that my designs are held together with screws/bolts and can be easily de-assembled and re-assembled for prototyping and repair but in this revision it was not possible without changes to the electronics.

EOGlass1 PCB Top side
EOGlass1 PCB Bottom side

Rather than continuing to use Ag/AgCl electrodes, I decided to test out gold cup electrodes from OpenBCI. These have the advantage of being smaller and less obtrusive. They are also reusable, although they require a conductive paste such as Ten20 to attach them to the user. The electrodes mounted via snap connectors like those used on Ag/AgCl electrodes and I used M2 bolts (as described previously) as connection points for the snap connectors on the arms of the glasses.



Electrically the design is identical to EOGee2 and even runs the same firmware. In the following video I demonstrate the EOG data resulting from a number of saccades and smooth pursuits. We can see that, other than the wires, the glasses look relatively normal. The EOG data is also fairly clean however the software did not quite fully compensate for changes in reference voltage due to DC drift and this can be observed as occasional short spikes as the reference voltage changes to keep the signal voltage in the ADC input range.

While this design was a big step towards creating an unobtrusive EOG device and I was overall pleased with the form factor, using wet electrodes was still a significant barrier to a good experience. On the next design I wanted to solve this problem, as well as some of the issues I highlighted above.


The primary goal of EOGlass2 was to use dry electrodes instead of wet electrodes in order to simplify use. Designing these electrodes was primarily a mechanical design exercise and I went through a number of prototypes.

Temple Electrode Design and Iteration

In order to get a good EOG signal, the temple electrodes need to make consistent contact to the user’s temples. However, the distance between the arms of the glasses and the user’s temple changes, both in terms of user-to-user variation as well as for a single user when the glasses move slightly on the user’s head. It was clear that the electrodes needed to have some mechanical compliance as well as apply some force towards the user’s head to keep consistent contact.

To begin with I designed a 3D printed hinge that would allow me have the electrode on a pivot. The pivot was made of two pieces – the base and the rotor. The base was simply a flat plate with two vertical rings. The U shape of the rotor allows it to be compressed to insert the two flanges into the two rings. The total volume of the hinge is only 7x7x11mm which could be improved by using other materials and processes to manufacture it, however this was adequate for my requirements.

3D Printed Pivot

This design could then be mirrored two times to produce a four-bar linkage. The idea was for the bottom linkage to be part of the glasses arm and the top linkage to be the electrode in contact with the user’s temple. This allows for a variable distance between the glasses arm and the user’s temple.

3D printed four-bar linkage

In order to maintain pressure on the user’s temple, I experimented with 3D printed springs however in the end I found that they required too much volume to enable any significant compression without being too easily damaged.

I also found that a four-bar linkage was not a very optimal design due to the fact that the top and bottom linkages are always parallel, whereas the user’s temple is usually at a slight angle relative to the arm of their glasses which meant that a four-bar linkage would not make good contact. To resolve this, I removed the third-linkage, which allowed the electrode surface to have a variable angle and displacement relative to the bottom linkage. I then used copper tape on the electrode surface and connected it via more copper tape to the M2 bolt which allowed me to electrically connect to EOGee2 PCB via a snap connector.

3D Printed three-bar linkage with spring to maintain pressure on the user’s temple

After a few optimisations I finally settled on a slightly shorter electrode which resulted in a better overall contact to the user’s temple.

Near-finalised 3D printed electrode mechanical design

Mechanically, very little has changed from this design however I went through a second optimisation process to find the best design for the electrode itself.

To begin with the electrodes were simply 3D printed with copper tape stuck to the surface contacting the user’s temple. To make electrical contact to this electrode I either used more copper tape or soldered a wire to it. This was not very robust or easy to construct. In an attempt to rectify this I tried gluing a 0.6mm PCB onto the 3D printed base with the pivot, rather than using copper tape. This made it easier to cover the whole top surface with metal and also allowed me to easily attach wires or connectors on the back side of the electrode, however I found that the mismatch in rigidity between the PCB and the 3D printed back resulted in the two peeling apart very easily. I also experimented with conductive rubber, crudely cut to shape, however I found this to give a very poor EOG signal. Next I tried formulating my own conductive rubber by combining carbon fibre with two part silicon mix as described here, and putting it into a 3D printed mould. This did not turn out well and I ended up with a very sticky mess.

Finally I settled on a wax casted metal electrode design.

Left to right: 3D printed electrode with copper tape, 3D printed electrode with thin PCB glued on top, 3D printed electrode with PCB and conductive rubber, 3D printed mould for creating conductive rubber electrodes, wax casted solid silver electrodes with U.FL connector mounted on small PCB.

The final design is manufactured by ShapeWays who are able to create the part from my CAD files. The whole electrode is a solid piece of silver or copper, onto the back of which I solder a small PCB with a U.FL connector. This allows for a very robust connection as well as enabling small and complex geometries – the user side of the electrode is filleted to prevent sharp edges causing discomfort. This design works very well as it is very rigid, however it is expensive (about $30 per electrode) and has a long lead time (1-2 months), so I haven’t iterated on this design.

Final electrode design

In order to make the hinge design more robust, I also redesigned the pivot. The previous design relied on mechanical deformation in order to fit the pivot into the rings on the glasses arm and on the electrode, however this was not very robust and required a reasonable amount of force to the get the pivot in or out, often resulting in breaking parts while doing so. To solve this I moved to a multipart pivot design which was constructed from two 3D printed pieces with 3 holes in each of them. A single M2x10mm set-screw held them together through the central holes. A pair of M2x4mm set-screws connected the pivot to the electrode and another pair connected the pivot to the glasses arm. This design enabled me to de-assembled and re-assembled the design easily by removing the set-screws which was much more controlled.

Temple electrode exploded view

Not shown here is the spring between the arm of the glasses and the electrode. I experimented with a number of springs and found that the optimum design, at least for me, was part number PC013-156-8000-MW-0630-C-N-IN from the spring store. This is a 16mm length spring of 8 coils with an outer/inner diameter of 4mm/3mm providing a force of 0.42N/mm compression.

Nose Electrode Design

As well as the two electrodes on the user’s temples, we also need a third ground electrode. The natural position for this is on the bridge of the nose and so I investigated a number of different nose electrode designs.

Copper tape on the bridge of the glasses

My initial concept was just to cover the nose of the existing glasses with copper tape in order to make contact with the user’s nose. This design was functional, however there is not very much contact area between the nose and the glasses resulting in poor and intermittent contact. To help improve contact I tried to use conductive rubber however this suffered the same contact area issues.

I decided to redesign the glasses to use a more tradition nose bridge, which I ordered from ZoyEyeglasses Parts (part TP-113).

TP-113 Nose bridge from ZoyEyeglasses Parts

To begin with I used standard plastic nose-pads covered in copper tape. This copper tape made contact to the user’s nose and also to the bridge of the glasses which could be connected to ground. Overall this made a good grounding electrode as the nose-pads were on a pivot which allowed them to make a large and stable contact to the user’s nose. To make this solution more elegant I designed some solid metal nose pads and again had them manufactured from silver and copper by ShapeWays.

Node pad design

In a side-by-side comparison, as shown below, it is clear that the traditional nose-bridge design makes superior contact to the user’s nose due to the pivot on the nose pads.

Side-by-side comparison of the three designs on my face. (No attempt made to make this flattering).

User Detection and Electrode-Skin Impedance Measurement

While this final design was fairly successful, it was still not as good of a grounding electrode as a wet electrode such as the Ag/AgCl electrode used previously. This meant that after the user put on the glasses, it took some time for the impedance between the electrode and the user to drop to a sufficiently low level to allow for a clean signal. During this initial time between putting on the glasses and the impedance dropping the signal was mostly unusable and so I wanted a way to detect when the user was wearing the glasses, and when the impedance between the electrodes and the user (electrode-skin impedance) had dropped sufficiently.

To achieve this I took advantage of the fact that the nose electrode design had two contact points to the user – the left and right sides of the nose. The idea is to use only one of the electrodes to ground the user and the second as a sense electrode to detect when the user is wearing the glasses and has a low impedance connection to the electrodes. This is accomplished by driving a sine wave onto the electrode through a 1MΩ resistor. This means that when the electrode is not in contact with anything, the waveform on the electrode is just the same sinusoid, however when the electrode makes contact to the user, and as the electrode-skin impedance drops, more current flows into the user (microamps) resulting in a voltage drop across the 1MΩ resistor and the waveform on the electrode becomes smaller.

Sense Electrode Circuit

The image above shows the circuit. A DAC is controlled by the microcontroller to generate a 300Hz waveform between 0 and 3.3V which is then buffered by an amplifier and connects to the sense electrode via a 1MΩ resistor. We use a 300Hz waveform because it is a multiple of both 60Hz and 50Hz which are the frequencies of mains electricity around the world which makes the demodulation process less susceptible to mains interference which can be a big problem, especially when the user is not very well grounded. The signal on the electrode is then buffered via a second amplifier before being fed into an ADC. The ADC samples the data at the output of the buffer and then uses IQ demodulation to calculate the magnitude of the 300Hz signal. This value is then fed back to the host computer via USB. Because the system is running on a 30kHz main clock, we use 100 samples per period to generate and sample the 300Hz waveform, however we collect 500 samples before we perform demodulation. This means we calculate a new sense signal value 60 times per second and feed this data back to the host computer.

In order to have two electrodes rather than one, the nose bridge from ZoyEyeglasses Parts is cut into two and each half is soldered on a PCB called the Nose PCB.

Nose bridge soldered to the Nose PCB on the glasses
Two Nose PCB’s connected together in the design

The Nose PCB is a very simple design that mounts a U.FL connector and connects the ground to one pad and the signal conductor to another pad. These pads can then be used to mount the two arms of the nose bridge. I included a zero ohm resistor in series with signal to add some flexibility in case I chose to add some resistance or capacitance down the line.

Data captured from the Sense Electrode

Above is plotted some data collected from the sense electrode. Before the glasses are put on, the signal sits at about 1945 counts which represents a maximum signal. The glasses are put on after around 3 seconds and the signal begins to drop. The signal continues to drop as the resistance between the electrodes and the user drops. After about 100 seconds it has mostly levelled out however it takes more than 5 minutes to settle to zero.

We see the line does have some sinusoidal component and this is due to the 60Hz mains noise. Although theoretically the signal should not be sensitive to 60Hz noise due to the demodulation settings described above, there is always some error between the frequency of the mains power and the glasses resulting in a low frequency noise signal. This could be improved with more filtering of the input signal to remove the 60Hz component, however this is only intended to be a low fidelity measurement of how low the electrode-skin impedance is to indicate signal quality and so some level of error and noise is acceptable.

Overall this design is successful in detecting when the glasses are on the user’s head and detecting when the impedance of the electrodes to the user’s head has reduced enough to result in a good grounding.

Circuit and PCB Design

In order to incorporate all of the improvements from our electrode designs, the EOGlass2 design needed to change quite significantly from EOGlass1.

In order to create more space on the PCB I removed the the variable gain capability (enabled by the digital potentiometer MCP41010) as I had not found it to be a useful feature. I also changed microcontroller from a STM32F072 in a 7x7mm QFP package to an STM32L412 in a 5x5mm QFN package. This also came with the benefit of having an ARM Cortex M4 core as opposed to the Cortex M0 core in the STM32F072 which will enable more complex algorithms to run on device.

Contrary to these space changing decisions, I also decided to use a dedicated DAC and ADC to generate the DC offset voltage and measure the EOG signal and also to use separate voltage regulators for the digital and analog voltage supplies. This was intended to minimise noise by separating the digital and analog portions of the board, however it also required additional space for these chips.

Despite more than doubling the number of chips on the board from 5 on EOGlass1 to 11 on EOGlass2 I managed to route them all in the same 25x11mm space and also include mounting posts to connect the PCB to the glasses and U.FL connectors on the backside to connect to the electrodes without soldering the wires. (Although admittedly I don’t really like the mounting posts as they use solder joints for mechanical support).

EOGlass2 PCB Top Side
EOGlass2 PCB Bottom Side

The separation between the analog and digital portions is best seen on the 3rd layer of the PCB which is the power plane layer. Here we can see a clear separation between the the analog and digital domains that is only crossed by the DAC and ADC chips in the lower left quadrant of the PCB.

Power planes of the PCB demonstrate the separation between analog and digital power

Because the electrical design is so different to EOGlass1, the firmware required significant work. Firstly I had to support ADC and DAC transactions over SPI, rather than using the internal ADC and DAC of the microcontroller. With the sampling rate of 30kHz I only had about 30µs to send and receive data to both of the two ADCs and two DACs on board. I discovered that the SPI driver that STMicro provide for the STM32 had too much overhead to send all of this data and had to modify them to avoid some of that overhead.


In order to enable easier debugging I also included programming pads on the backside of the board. This was intended to allow me to connect a software debugger to the device in order to more efficiently debug my code. In order to connect to these pads I designed a secondary board called the Programmer Board which featured a number of pogo pins which made contact to these pads.

The Programmer Board sat atop a small 3D printed base to hold it above the table and the EOGlass2 PCB was screwed onto the bottom side such that the pogo pins made contact to the programming pads and the USB port poked through the cutout in order to enable a USB connection. The programming signals were then broken out to the 6×2 0.1″ connector at the top and to the reset and boot buttons to reset the device and enter the bootloader if necessary.

The board also featured a pair of headphone jacks for the EOG signal and the electrode-skin impedance measurement signal. These were connected via the U.FL connectors on the backside of the PCB.

EOGlass2 PCB mounted on the back of the programmer board

Although the programmer was very useful in early stages of bringup as it allowed me to treat it much like an EOGee2 board, I found that I also wanted the ability to upload firmware whilst the PCB was in the glasses. In order to do so I needed to boot into the bootloader however this required pulling the boot-pin to 3.3V whilst powering up the board which is not easy when it’s inside the glasses. To resolve this, I modified my firmware to enable it to enter bootloader mode through software via a USB command and this allowed me to upload firmware via USB without disassembling the glasses.


While the EOGlass2 glasses are very similar in style to the EOGlass1 design, in order to support the new electrode changes and new PCB, some modifications were required.

Assembled Glasses CAD

With the new integrated electrodes, the glasses are almost fully self contained, except for the USB connection to supply power and transfer data. In fact, when wearing the glasses they are almost indistinguishable from normal glasses, but for the missing lenses and 3D printed construction.

The connection for the right-temple electrode is achieved with a 50mm coaxial cable with diameter 0.81mm and a U.FL connector on each end. This connects from the back of the main PCB to the PCB on the back of the electrode provides good shielding and a robust connection. Meanwhile the connection for the nose electrodes and left-temple electrode passes through the arm and into the face of the glasses.

Wire routing for the electrodes (connections of the back side of the PCB) – right-temple electrode in blue, left-temple electrode in red and nose-electrodes in green

The coax cable for the nose electrodes travels through a channel in the back of the face of the glasses to the U.FL connector on the Nose PCB, while the cable for the left-temple electrode continues to the left arm of the glasses.

Wire routing for the nose electrodes (green) and left-temple electrodes (red)

Finally the coax cable for the left-temple electrode passes back onto the left arm of the glasses and connects to the PCB on the back of the electrode.

Wire routing for the left-temple electrode


I don’t have much to show in terms of results for EOGlass2, and that is because I immediately starting working on electronic improvements that became EOGlass2.1.


After the shift to dry electrodes I found that drift was a really big problem again. Even though I had implemented the DC offset solution in EOGee2, I found that with dry electrodes this was not always enough to get the signal back into the range that system could measure. My first suspect was voltage offset due to bias current in the differential amplifier flowing through the high impedance between the user and the electrodes.

Bias Current Improvements

The problem with the current design was the relatively high bias current of the AD8226 differential amplifier at the input of the device. There are two variants of the AD8226 but both variants have a nominal bias current of 20nA and a maximum bias current of 27nA at 25˚C. This may not sound large, however it can generate a very large voltage (relative to the EOG signal) when flowing through a large resistance.

I wanted to understand the typical resistance between a dry electrode and the user and so I connected a multimeter across the two temple electrodes and put the device on my head. Initially when the glasses are put on the resistance overloads the multimeter as the resistance is too high, however after about 20 seconds the resistance becomes measurable again at 50MΩ, the maximum resistance my multimeter can measure. Over the next 2000 seconds (about half an hour) we see the resistance continues to drop and eventually levels out around 190kΩ.

Plot of temple-temple resistance over time

In this case, because we are measuring the temple-temple resistance, we are measuring two resistances in series and so we can make the assumption that the two resistances are approximately equal. This indicates that our electrode-user resistance can easily vary between more than 25MΩ and 95kΩ. Of course, this will vary user-to-user and over different environmental conditions but this is a very large range.

When we take these resistances in conjunction with the 20nA of bias current from the amplifier we expect a voltage of between 3mV and 500mV which is far larger than the EOG signal at only 500µV. Of course, if the same voltage is generated at each temple then they will cancel out as this is a differential measurement, however in reality there will always be some mismatch between the resistance of the two electrodes.

If we consider that the input offset voltage must not exceed 25mV before the DC offset voltage is unable to compensate for it, this means we cannot have a mismatch between the two electrodes of more than 1.25MΩ before fully saturating the ADC. While 1.25MΩ may sound large, it seems quite possible to occur, especially in the first 30 minutes of use when the skin resistance has not dropped sufficiently.

Illustration of the electrode resistances and input current to the differential amplifier

In order to investigate and prove out this effect further I built a test board, called the Bias Tester board, to compare the sensitivity to source resistance of the AD8226 and a similar chip, the AD8220. The AD8220 is very similar in operation however it has a max bias current that is 4 orders of magnitude smaller than the AD8226, at only 10pA using the B Grade variant.

Bias Tester Board with AD8226 and AD8220 mounted on separate breakout boards

The Bias Tester has three 1MΩ potentiometers to simulate the resistance of the three electrodes in the EOG measurement. The inputs of the AD822x chip were then connected to ground via these resistances and the output was amplified 2211x times to generate measurable resistance. The AD8226 and AD8220 chips were mounted on small breakout board that made it easy to switch out the device under test.

Output Voltage vs Resistance mismatch between positive and negative inputs

The results plot the output voltage after the 2211x gain against the mismatch between the two potentiometers at inputs of the AD822x device. We can see that the green line, representing the voltage generated by the AD8226 chip, is very steep and saturates from 0V to 3.3V in a span of only 80kΩ, due to it’s larger bias current flowing through the potentiometers. The blue line, representing the voltage generated by the AD8220 chip, is very shallow and the output voltage is relatively insensitive to the mismatch in resistance of the two inputs.

Back calculating the bias current from the slope of the two lines we calculate that the bias current of the AD8226 was approximately 21nA while the bias current of the AD8220 was only 10pA which lines up with our expectations.

This experiment also illustrated the important of cleaning the flux off of your PCB after soldering. The red dots represent this experiment repeated with AD8220 board that has not been cleaned – the flux provides a leakage path that is significantly greater than that of the chip itself.

Finally, this also confirmed that the resistance of the ground electrode has very little impact on the output voltage which is intuitive as any current through the ground resistance generates an equal voltage relative to ground on each of the left- and right-temple electrodes.

PCB Design

With this new finding I decided to spin a new version of the EOGlass2 with the AD8220 chip instead of the AD8226. While the two chips are technically pin compatible, the AD8220 operates on a minimum voltage of 4.5V while the EOGlass2 PCB supplied only 3.3V to the AD8226. Therefore I needed to add a new 4.5V voltage rail to the design in order to supply the AD8220 which required adding a new voltage regulator.

EOGlass2p1 Layout Differences from EOGlass2

This would be impossible if I continued to use the AP2210K family of chips that I often use as they come in a SOT-23 package which is relatively large. Instead I managed to fit two LP5907 voltage regulators in the same space as the 3.3V analog voltage regulator. These two chips, one generating 3.3V and the other generating 4.5V, are truly tiny at only 0.645×0.645mm and show the benefit of moving to chip scale packages for saving space.

LP5907 chip vs a Quarter

A comparison of data taken from EOGlass2 compared to EOGlass2.1 illustrates the improved performance due to the reduced bias current. We can see that the green line, representing EOGlass2, settles to a value much further from zero and continues to drift during the data collection. Meanwhile the blue line, representing the data from EOGlass2.1, settles to approximately zero and stays quite stable for a longer time.

Comparison of data collected with EOGlass2 vs EOGlass2.1

Characterising Noise Performance

Now that I had reduced drift due to bias currents I wanted to understand the sources of noise. In particular, I want to ensure that the noise contribution of the hardware is much smaller than the noise from the signal itself. I also wanted to ensure that the hardware noise was approximately as expected. So I performed a noise analysis of the circuit.

Overall the calculated contribution to noise of each of the stages is broken down as so:

SourceInput Referred Noise
Input Resistors557nV
Differential Amplification Stage328nV
Second Amplification Stage22nV
Final Amplification Stage2.4nV

The total expected noise (referred to the input) is 647nV RMS which corresponds to 1.43mV RMS at the ADC or 1.8 ADC counts. Assuming a +/-3σ range we would expect to see a 10 ADC count peak to peak noise which agrees well with out observations.

We can see that the majority of the noise is generated as thermal noise by the 47kΩ input resistors. This is because this noise is injected right at the input of the signal chain and is therefore amplified by 2211x times before it reaches the ADC, whereas sources of noise later in the signal chain are less amplified. We can see that we could almost half the noise by removing these resistors and connecting the inputs directly to the user. However, ignoring safety concerns, we also likely wouldn’t see any benefit in performance. This is because the noise on the signal itself is much higher than 10 ADC counts peak to peak and so the hardware noise is swamped by the noise of the signal itself.

Characterising Frequency Response

As well as characterising noise I wanted to characterise the frequency response of the signal chain too. I did this through simulation as well as through measurement.

In order to measure the frequency response I needed a way to inject signals into the input of the EOGlass2.1 PCB. I had previously done this on EOGee1 using the SigGenAdapter board, however this was not very controlled as it required that the signal generator output signals that were small enough to be measured by EOGee1 which meant that the signal generator had to be turned right down so it was not possible to measure the input signal and the signal was also very distorted.

Instead I designed the FakeEyes board which takes a 0-3.3V signal from the signal generator and reduces it by 2211x times so that when the signal is amplified by EOGlass2.1 it exercises the full range of the ADC.

FakeEyes PCB injecting signals into EOGlass2.1

This allowed me to inject a sinusoidal waveform and sweep over frequency to measure the amplitude of the signal reported by EOGlass2.1. I could then compare this to simulation to confirm expectations.

There are two filters at play in EOGlass. First is the 131Hz single pole low pass filter in the signal chain and the second is the digital filter in the firmware. This is actually just a simple averaging filter whereby the ADC is sampled at 30kHz and then sets of 32 samples are averaged in order to reduce the data rate to only 937.5Hz.

Simulated frequency response of the different filters compared to the measured frequency response

The simulated frequency response is just the result of multiplying the frequency response of the digital and analog filters. Comparing the simulated frequency response (purple) to the measured frequency response (blue) we can see that the two overlap very closely. While this is good news, it also reveals that the current filtering is not sufficient because even at 1250Hz we only see an 80% (-14dB) reduction is signal and the roll-off doesn’t reach 99% (-40dB) attenuation until around 1600Hz, however with a sample rate of 937.5Hz the highest frequency we can measure is around 468Hz and therefore any signals observed above that value will be aliased to lower frequencies. This can either be fixed with a more aggressive anti-aliasing circuit to prevent higher frequencies reaching the ADC or with a better digital filtering algorithm to reject the higher frequencies before downsampling to the lower sampling rate.

Mobile Measurement Setup

Ideally, running the EOGlass from batteries and reporting data wireless would improve the signal fidelity. This is because batteries are a very low noise power source (unlike the 5V USB supply) and also by decoupling the power supply from earth ground we would reduce 60Hz noise interference. Running from batteries also allows more mobility while taking measurements which makes taking long measurements less difficult, however I have little interest in developing a wireless and battery powered solution as I don’t think this requires much innovation and is just work to be done.

My temporary solution to this is to use a raspberry pi powered from a battery bank to connect to EOGlass2.1 and capture the data. I can then transmit the data over WiFi to my main computer. While this does in general appear to reduce 60Hz noise, there is a relatively high level of noise at higher frequencies which I expect is due to the switch mode power supplies inside the battery bank which generate the 5V supply. A cleaner solution is needed.

The portable EOGlass setup consists of the headset, a Raspberry Pi and a battery bank

Searching for Drift

Despite the reduced bias current, there is still a large drift occurring on the signal, though not as bad as before. Overall I see two main types of drift which I call startup drift and drift. Startup drift occurs when the glasses are first put on and is typically much faster than normal drift and takes about 20 minutes to flatten out.

Data collected with dry copper electrodes on the temple and dry silver electrodes on the nose.

Originally I theorised that the startup drift was caused by a combination of the electrode impedance and some kind of warm-up effect where the hardware took some time to settle it’s offset voltage and bias currents to the rated value. I ran a simple experiment where I allowed the glasses to run for some time before putting them on my head and observed that startup drift still occurred.

Data collected with (green) and without (blue) a hardware warm up period

This implies that the warmup of the circuit is likely a negligible contributor to startup drift.

Given the very small bias current of the AD8220 and the resistance data previously collected over 2000 seconds the startup drift appears too large to be due to the bias current of the input amplifier. To generate such a large drift the resistance mismatch of the two electrodes would need to be approximately 165GΩ which is far larger than measured.

To further prove this out, I created a small PCB to test the bias current of the EOGlass2.1 system by connecting a 1MΩ potentiometer between the electrode signal and ground. As expected, the variation in signal as the resistance is swept is undetectable due to the ~10pA bias current.

PCB for applying variable impedance to ground to EOGlass inputs via U.FL connector

Despite these two pieces of evidence to the contrary I also theorised that there could be some additional leakage inside the PCB due to the proximity of the signal trace to power rails in some locations – this is very hard to avoid in such a miniaturised design with a four layer PCB. I could not find an adequate value for the resistance of the FR4 material in PCBs other than that it was more than 10GΩ, however even at 10GΩ a voltage of 1V would result in a current of 1nA which is 1000x larger than the bias current of the AD8220.

To test this theory I designed a small interposer board that could sit between the previously discussed Bias Tester board and the AD8220 and was intended to increase the surface area between the signal trace and the power rail by running the signal trace on a long path through an internal layer sandwiched between power planes.

One of the internal layers of the interposer PCB

Repeating the Bias Tester experiment with this interposer, I saw no measurable extra drift when the resistance mismatch was increased to 1MΩ, indicating that this source of leakage was likely not significant enough to create the drift we are seeing.

To test for thermal effects I placed the EOGlass2.1 in front of my electric heater and recorded voltage with the inputs shorted to ground.

Drift over 27 minutes when placed in front of an electric heater

This showed that thermal effects (at least on the scale that might be generated close to my head) had only a very small impact on signal drift as a total drift of around 30 counts was observed.

My main theory for the source of the drift is that it is generated at the contact between the electrode and the user. This is because dry electrodes are generally classed as Polarisable which means that a voltage can be developed across the electrode. “Bioelectrodes”, the simply named paper by Eric McAdams, provides a good overview of bioelectrode types and related phenomenon.

In order to test this theory I compared the drift when using dry copper electrodes to when using standard Ag/AgCl electrodes which are typically considered relatively non-polarisable designed an adapter to connect standard Ag/AgCl.

Snap connector to U.FL connector adapter to enable using Ag/AgCl electrodes on EOGlass

In the comparison can see that the Ag/AgCl electrode has significantly less drift than the copper electrodes and also has significantly fewer spikes which I expect are motion artefacts and are mitigated by the adhesive between the Ag/AgCl electrode and the user.

Comparison of drift for dry copper electrode (blue) compared to an Ag/AgCl electrode (green)

It is clear that more work needs to be done to understand and solve this problem fully. The “Bioelectrodes” paper and the papers that it cites are good resources, for example “Evaluating Major Electrode Types for Idle Biological Signal Measurements for Modern Medical Technology” by Anas Albulbul.

Firmware and Software Overview

Before diving into the software explanation, we need to define some terminology. In the system there are two DACs and two ADCs.

First is the Signal ADC – this is the ADC that measures the EOG signal after it has been amplified and filtered. The signal chain also requires the Vref signal that defines the signal offset to enable DC coupling. This voltage is controlled by the Ref (or Reference) DAC.

Second is the sense electrode. This requires one DAC, the Drive DAC, which generates a 300Hz signal that is fed into the electrode through a 1MΩ resistor. The signal is then read back by an ADC, the Sense ADC, so that the signal can be demodulated to decide if the user is wearing the glasses and how low the impedance is between the electrodes and the user.

After booting, the microcontroller first checks to see if the bootloader flag is set, and if so it jumps to the bootloader rather than beginning the program (we will discuss how the bootloader flag is set later). This enables us to enter the bootloader and flash new firmware from software rather than having to access the boot pin, as mentioned previously.

After beginning the main timer counting (which is used to trigger the sampling processes), the microcontroller then enters a main loop during which it polls for flags before acting upon them.

First, the microcontroller checks to see if there is enough data from the sense electrode to transmit over USB – it requires 500 samples for demodulation which is equivalent to 16.7ms of data. If so, it takes the available data, demodulates it using IQ demodulation, and transmits the final value over USB to the host. The microcontroller then checks to see if there is enough EOG data from the signal ADC in the buffer – it transmits the data in packets of 16 samples or 32 bytes. If so, it transmits the signal data to the host before also transmitting the ref buffer data. The ref buffer holds the value of the Ref DAC at the time that each signal sample was measured so the host knows how much offset to apply to the data – this is another 16 samples or 32 bytes.

In order to differentiate between sense data, signal data and reference data the top four bits of each 16-bit value are used, as the data itself is only 12-bits in length.

Microcontroller Main Loop

The main loop of the program is only responsible for relaying data from memory to the host. Simultaneously, in order to initiate data data sampling, the main timer is triggering an event every 33µs

Timer Output Compare routine

Every 33µs, the timer triggers the “Timer Output Compare” interrupt which simply initiates the SPI transaction to update the Drive DAC to the next value in the sequence. The sinusoidal signal is stored as 100 samples in an array in memory and each time this timer triggers we send the next value in the array, before looping back to the start. In order to keep track of events we set the com_sequence variable to zero at this time. This routine then completes and the SPI transaction has begun. Once the SPI transaction is complete (ie we have written the new value to the Drive DAC) the SPI hardware will throw a new interrupt.

SPI Transaction Complete Routine

The SPI Transaction Complete routine is where the majority of the logic takes place. The SPI Transaction Complete routine is called each time a SPI transaction is completed and therefore is called four times every 33 microsecond – once for each ADC and DAC in the system. In order to handle this, it uses the com_sequence variable to keep track of the current state of operation.

When the SPI Transaction Complete routine is called for the first time, the com_sequence variable will have a value of zero which indicates that the Drive DAC has been updated and the routine should begin sampling the Signal ADC to collect a sample of EOG data. The routine then increments com_sequence and ends until the ADC sample is complete and the routine is called once again.

When the routine is called for a second time, we know that an ADC result is available because com_sequence is equal to one. We take this ADC result and divide it by 32 before adding it to the signal accumulator and incrementing the signal_counter variable. This keeps track of how many samples we have added to our signal_accumulator and once it reaches 32 the value of the accumulator is equal to the average of the previous 32 samples. If the signal_counter is equal to 32 we add the accumulator value to the signal buffer. We also add the value of the reference voltage, Vref, to the ref buffer to keep track of the value of Vref for each sample that is reported.

When we have 16 samples in the signal and reference buffers, we then set the signal packet ready flag to be equal to one so that the main loop will know that data is ready to be transmitted. We then use these samples to check whether the EOG signal has drifted and if so we calculate the new value of Vref in order to bring the signal back to mid-scale. Now we have finished handling the Signal ADC, we begin reading the Sense ADC, increment the com_sequence variable and the routine ends.

The routine is called once again when the Sense ADC read is complete. We take the result and add it to the sense buffer. If the sense buffer is full we then set the sense data ready flag for the main loop to handle. Finally, we begin the Ref DAC write, increment the com_sequence variable and finish the routine. The value that we write to the Ref DAC is the updated value that we calculated in the previous steps to recenter the EOG signal.

The routine is called a final time when the Ref DAC write is complete, though no action is taken. This whole process repeats after 33µs when the timer ticks once again.

The final part is the routine to handle USB data received from the host.

// Callback for when data is recieved via CDC, called from usbd_cdc_if.c
void receive_cdc_data(uint8_t* buf, uint16_t len)
	if(len == 1)
		if(buf[0] == 'c')
			ref_calibration_mode = !ref_calibration_mode;
		if(buf[0] == 'm')
			drive_enable = !drive_enable;
		if(buf[0] == 'r')
			reset_bootloader_flag = 0;
		if(buf[0] == 'b')
			reset_bootloader_flag = reset_bootloader_magic_number;

The data sent from the host computer to the device is very limited and is intended only to control simple functions. Characters ‘c’ and ‘m’ are used to enter a reference calibration mode and to disable/enable the drive signal. When an ‘r’ character is received, the device performs a soft reset and jumps back to the start of the software. When a ‘b’ character is received, the bootloader flag is set to the magic number before soft resetting the microcontroller. This way, when the software starts again it will know to jump into the bootloader and we can upload a new firmware version.

Demo Video

Now that we have thoroughly explained the development and operation of EOGlass2 we have a demo video giving an overview of the design as well as some captured data and demonstrations.


Reference DAC Spike Removal Algorithm (LOST)

As we have previously seen, the reference DAC is necessary to keep the EOG signal inside the ADC measurable range – however when the reference DAC changes code, there is a noticeable spike in the EOG data. This is because the simple correction algorithm assumes that the change in EOG signal due to the reference DAC change is instantaneous and equal to a known step size.

Top: Raw data from ADC, Middle: Reference DAC code, Bottom: Combined ADC and DAC value

In reality, after the DAC has changed code, it takes some time for the EOG signal to settle to its final value. This results in a short period of over-correction when the signal is still settling. In order to correct this behaviour I have created an algorithm called the Learn Offset Step Function algorithm (or LOST).

When the glasses are first turned on, the software doesn’t know the relationship between the DAC code and the ADC signal. Therefore the first time the DAC code changes, the software does not know how to compensate for that in the EOG signal. However, by assuming that the EOG signal should be static, we can assume any change over the next few samples is due to the DAC code transition which we can record. Over time, the software observes multiple DAC code transitions and saves them individually to memory. Over time we can assume that the average of each of these steps is equal to the true step response of the DAC.

The ADC signal immediately after a DAC code transition over multiple occurrences. Average shown in black.

Now that the software knows what the impact of a DAC code transition is, it can compensate in the future.

Combined ADC and DAC data before (blue) and after (orange) the LOST algorithm

The results are plotted above and we can see that the algorithm is very successful in removing the large spikes. This algorithm is very ideal because it does not rely on any kind of per-device factory calibration and can be learnt in real time which can take into account device-to-device variation as well as lifetime shifts.

Eye Tracking Application and Algorithms

It is clear that drift is a significant issue for eye tracking using electrooculography and therefore it is unlikely to be an acceptable solution by itself. Nonetheless, over short periods of time it may be stable enough to track eye location. Therefore I am interested in studying its application in combination with traditional camera-based eye tracking. Camera-based eye tracking is very robust to drift and can be very accurate, however it requires multiple cameras, glints and a lot of processing power. Combined with the high sampling rates and low latency required to provide a good user experience (up to 1000FPS) this results in a very high power solution that does not easily fit in a pair of glasses for all-day use.

In contrast, EOG based eye tracking is very susceptible to drift and noise, however it can easily achieve sampling rates in the kHz range and requires minimal processing which lends itself to a low power implementation.

A combined EOG and camera-based eye tracking solution can strike a balance between the two designs resulting in a high performance eye-tracker on a low power budget. This comes at the cost of extra hardware to implement both approaches, but may still be preferable given the savings in battery volume, weight and heat dissipation requirements.

An example implementation may use the camera to track the eye location at a low sample rate, for example 1Hz. The EOG signal provides a very high sample rate signal, for example 1000Hz. The low frequency camera data can be used to remove drift from the EOG signal while the EOG signal allows fast saccades to be captured and processed in low latency.

Unfortunately, in order to fully study this approach I need access to a well characterised and high performance eye-tracker which cost upwards of $15k and are not within my budget for this project.

Nonetheless, in order to test this concept I have developed an alternative method of removing drift from the signal. During my testing, I can periodically look at known targets and press a button on my keyboard. This way the system knows where I am looking and can use this to remove drift from the signal. This demo is called the EyeKeyboard (poorly named).

Eye Keyboard interface

In the EyeKeyboard, there are two white reference dots on each side of the display. Periodically I can look at each of these reference dots and press the left or right arrow keys on my keyboard to tell the software where I am looking. In the intervening time the glasses try to track where I am looking (assuming my head is kept steady) and draws a red line in the centre of my view.

EyeKeyboard in action shows my gaze (in red) darting between the reference dots (white) and the target point (grey)

By adding target points I can evaluate the accuracy of the eye-tracking. These points are similar to the reference dots except that I press a different keyboard button indicate that I am looking at them and the algorithm uses these locations to evaluate the eye tracking accuracy, rather than to adjust the estimation.

In the simplest case, all I have done is to have the two reference dots on each side of the screen and then to estimate the accuracy of a central gaze.The resultant data looks like so:

Data captured on the EyeKeyboard

We can see that my gaze is shifting between the two reference dots at the edge of the screen and the single target dot in the centre. The black lines indicate when I press the left or right arrow keys on my keyboard indicating that I am looking at a reference dot, while the grey dotted line indicates that I am pressing down arrow key to indicate that I am looking at a target. The algorithms job is to use the two reference locations in order to calibrate itself and then estimate the eye location when I am looking at the target dot.

With no knowledge of the drift, other than at the exact times that I am looking at the reference dots, the algorithm must make some assumptions about the behaviour of the drift in the intervening time.

In order to evaluate different algorithms, I wrote a playback framework to playback data that was recorded on the EyeKeyboard and feed it sample by sample into the algorithm. This provides a simple template for writing an algorithm (sample comes in, estimate goes out) and ensures the algorithm does not accidentally use future data when estimating the eye location.

Constant Drift and Gain Algorithm

As well as estimating the drift, the algorithm needs to estimate the relationship between voltage and eye-rotation which we call the gain. This can be described by the following equation, where A is the eye rotation in degrees, y is the signal observed by the ADC in volts, d is the signal drift in volts and G is the ratio between the eye rotation and the EOG voltage in degrees per volt (˚/V).

In reality, both G and d are time dependent variables. However in the simplest algorithm we can assume that these two values are constant. Therefore, in order to estimate the value of G and d we need exactly two known eye positions (A1 and A0) and corresponding ADC samples (y1 and y0). We can then solve the equations for G and d using the most recent two known locations.

When we implement this algorithm, we update our drift estimate each time I look at a reference dot. The drift estimate is plotted below as the orange line.

We can then evaluate the estimated eye rotation at each target dot and compare that to the true value. The error is then plotted below as a histogram.

Error distribution with Constant Drift and Gain algorithm

Overall we can see that the majority of the points lay within 2˚ of error but some points are as high as 5˚ error.

Linear Drift and Constant Gain Algorithm

Given that we know drift is not constant and changes over short time scales we can try to improve on this algorithm by allowing for a constant drift. In this case we use the previous three reference dots in order to calculate a constant drift. This time we can see that in between the reference dots (black lines) there is a constant gradient in the drift.

Once again, plotting the error as a histogram we see than the accuracy actually gets a little worse.

Quadratic Drift and Constant Gain

Taking it one step further we can also have a quadratic drift which uses the last four reference dots.

Once again, plotting the error histogram the worst case error increases.

Overall we have seen that adding a more complex estimator does not necessarily improve error. This could be explained by the fact that there is no reason to believe that the drift would behave in a linear or quadratic fashion. I expect these results could be improved with a more intelligent algorithm which may require a better characterisation of typical drift behaviour. Increasing the frequency at which reference points are observed would likely also improve performance as it leaves less time for the measurement to drift – this would be more simple with a camera based approach.

Improvement and Future Work

In this project I have demonstrated a portable and convenient platform for capturing horizontal EOG data. There is still a significant amount of work required to productise this technology. The simplest application would probably be to enable human-computer interaction using only the eyes, potentially for people with limited ability to use traditional input devices such as a mouse and keyboard. As previously discussed it could also find its use in eye tracking for AR/VR in combination with a camera. There are future developments I would like to investigate if, one day, I come back to this project or anyone else wants to use this as a basis of their project:

  • Perhaps the most obvious would be to implement a vertical EOG measurement to give full two dimensional eye tracking. This would require some innovation in electrode placement.
  • As earlier pointed out, the frequency response of the system is not adequate to remove all aliasing in the signal. This could be improved by implementing a proper FIR filter in the firmware, rather than a simple averaging and downsampling.
  • The design of the nose electrodes is not as reproducible as I would like. Currently it relies on parts from – a website I’d never heard of and have no idea how long it will exist. This would just require finding a suitable way to manufacture the bridge of the glasses – ShapeWays may be able to build these parts (as well as the nose pads and temple electrodes).
  • Unlike most glasses, EOGlass does not fold up. I did play around with integrating traditional glasses hinges into the arms, however it made the wire routing tricky and I wasn’t in the mood for flakey connections.
  • Implementing a battery and wireless communication would allow the device to be completely standalone. As well as being more convenient I would expect this to improve signal quality as the device would be more decoupled from earth ground, resulting in reduced mains noise.
  • These glasses have only been tested on my head. While the spring loaded temple electrodes are intended to guarantee contact to the head, I’m sure person-to-person variation is likely large enough to cause issues in some cases. Having said that, I didn’t heavily optimise these for my head specifically and they just seem to work, so it may be a pretty robust design already.
  • While the wires from the electrodes and the PCB are hidden from the outside view, they are visible if you remove the glasses and look closely. I experimented with a method of embedding these wires into the glasses by gluing a cover over the wire channels and sanding it until it was flush. This worked pretty well, but it permanently attached the wires in place which is not desirable in a prototype but would look pretty good in a final device.
  • I believe the majority of issues (drift and noise) are exacerbated by the high impedance between the electrodes and the user. This is generally a draw back of using dry electrodes, which are critical if this were to ever become a consumer device. However, there are various designs of dry electrodes that may improve performance by reducing that impedance. Examples of this may be to use a different material, a different geometry (e.g. dry comb electrodes that are often used in EEG measurement) or an increased force.
  • I have ideas for measuring, predicting and removing drift from the measurement that may significantly improve the characteristics of the signal.
  • As previously discussed, a combined camera + EOG approach to eye tracking could yield a good compromise between power and performance, however I don’t have the budget right now to invest in a camera-based eye tracker.

Design Files and Resourced

As always, my design files and code are uploaded to my GitHub.

One thought on “Project: EOGee/EOGlass – Summary

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s