Saturday, June 23, 2012

Sleep mask prototype assembly and initial testing (or, now that the hardware's built, it's only 90% of the project left to do)

The next step in the development of the Sleep Mask was fabricating the 'final' prototype, and doing some initial testing to make certain that there were no shorts.

The front and back of the assembled board (with battery and display attached) are shown below.  The smallest surface-mount parts (including the charger and headphone amplifier ICs) were placed on syringe-applied solder paste and 'baked' into place using a cheap electric skillet; the remainder of the parts were applied manually, using a conventional iron (the reason for this roundabout assembly method is detailed in a previous post; long story short, I bought the wrong paste).

Being extra-cautious, I checked each of the solder joints on the tight-pitch ICs before adding the rest of the components.  Being extra-paranoid, I introduced cuts into the power traces, so that I could monitor current usage as I re-connected different subsystems (this is evident in the backside image).

Front of assembled board; display not yet mechanically fixed
Back of assembled board; display not fixed; connector to mask lights/sensor at bottom

With everything reconnected and no programming loaded into the controller, the device drew 4.6mA; with phones plugged in (and, again, no programming and thus no signal being output), the device drew 44.5mA.  Even with the tiny battery I have connected now (450mAh), this is low enough to allow for a full night's use on a charge; of course, this doesn't take into account the power used by the IR REM sensor illuminator, the display or the extra power which may be expended to generate actual sounds with the headphones.  However, power use appears to be dominated by the audio system, so I am not too concerned right now.

I connected the assembled board to the mask (shown twice below); additionally, the display is scotch-taped to the board to secure it mechanically (but reversibly so).


The only things left for the hardware are to fix the board and battery to the mask and to install the red LEDs in the eyecups (these will be used to flash at the user during alarm conditions).  I'll also need to install a header to allow for repeated programming.  All that's left for the software... is everything.

Or course, this is the roughest sort of prototype, meant to prove the concept and develop the basic REM detection algorithms and the framework of the eventual overall program architecture.  In addition to about a million changes to the overall mechanics of the mask (formed neoprene base? injection-molded face for the buttons/display), the main board itself would undergo a lot of beneficial changes, mostly to decrease its size.  As I've commented before, the components I've used are ones I have a stock of locally; as such, they are rated for far more current/voltage/power/dissipation than needed for the current application.  Additionally, the controller is the easy-to-hand-solder TQFP, rather than the absolute smallest package available.  As a result, I suspect that a future version of the device, with all the same functionality but reduced part size, could be as small as one quarter of the area of this version.



Sunday, June 10, 2012

Project updates (or, trading a few milligrams of epidermis for a few milligrams of reflowed solder)

Due to travel (and actual, legitimate research), I've not been able to progress on these projects much in the last few weeks.  Additionally, getting the boards from Seeed took a little while (though it was worth it, 10 boards for 15$ is nothing to sneeze at; they're shown immediately below).


Today, I got back into things by trying out a little hot skillet reflow.  Going off of resources at SparkFun and this instructable, it seemed the cheapest method available to me.  To apply the paste, I didn't have the time, money or patience to do solder paste stencilling (shown in the previous links); so, I applied the paste manually, as at this site.  Unfortunately, I didn't realize that the paste formulations are different between stencil and syringe application; I loaded some stencil paste from Sparkfun (here) into a syringe and it was very tough to get it to come out.

One thing to be aware of with the stencil-type solder paste: it behaves a lot more like wet sand than any sort of easily-coaxed gel.  Syringe-type paste might behave a little better/differently.

In any event, I was able to reflow the majority of the components on the (hastily thrown together) helmet flasher board, shown below (apologies for the poor picture quality).  I have seen heating-element control boards for toaster ovens and skillets to get the perfect heat profile; in my case, cranking the thing up to max temp and waiting for the solder to turn shiny sufficed.  Note the blue wire fix; I forgot to connect the enable line for the step-up to a free pin on the controller.



Debugging revealed only two small errors in the reflow; two of the pins on the stepup controller were bridged (easily separated) and one of the resistors in the current controller didn't reflow (also easily rectified).  The step-up produces 'high voltage' (16.5V), the pots have all been manually set (one to set the high voltage level, the other two to set the maximum constant-current levels) and the controller talks to my programmer.

The next steps for this quick project are A) create a simple program for this thing, and B) assemble the in-helmet parts of the project (lights, switches and 2xAA battery pack installed, wiring routed).  There's also the more pie-in-the-sky goal of implementing the EL drivers (but I haven't quite sourced the transformers yet; not enough of my CFL bulbs have gone out yet).

Of course, just because the project has barely started doesn't mean I'm not already thinking about version 2; specifically, I'd want to implement the following changes:
A: source smaller components, with specs sized more appropriately for this project.
B: add a LiPolymer battery and charger circuit to allow the controller module to be more monolithic and allow it to be charged over micro USB.
C: figure out a better connector solution between the helmet and the controller; the 0.1" headers I'm using were chosen for inventory convenience.

Saturday, May 12, 2012

Implementation of a supervised discretization algorithm (or, I'm almost certain that I had a reason for this when I started)

Oftentimes, you have a set of data and want to use it to make a prediction about the future (e.g., predicting tomorrow's weather, based on today's weather) or about an unobserved system (e.g., predicting the presence or absence of metal ores underground, based on the local magnetic field).

In order to make that prediction, we need to set up some sort of mathematical framework describing the possible relationships between the data and the prediction.  If we have first-principles knowledge of the system under question, we can make a model of the system and use the available data to set any free parameters the model has.  However, we often have no idea about the system between the data and the prediction.  In these cases, we need to propose a sufficiently complicated and unbiased model so that, after setting the model's parameters according to the observed prediction/data relationships, the model accurately reflects the unknown system between the data and the variables to be predicted.

There is an enormous literature describing many different structures for generic predictors.  However, many of these rely on the input data being discretely-valued; that is, instead of taking on any value in a continuous range (like a distance, 12m, 5.43m, 1m, 0.333205m), they can only take on a discrete number of values (like 'number of fingers' is an integer between 0 and 12, inclusive).  In order to leverage these discrete-input predictors, it is necessary to 'discretize' continuous inputs; that is, to assign ranges of values to a single class (e.g., temperatures 0 to 10 degrees are now '0', 10 to 25 are now '1', 25 to 40 are now '2', etc.).

There is a smaller literature describing and analyzing methods for chosing how to perform this discretization.  In the future, I might put together a post reviewing these methods (at least, from a layman's perspective, as I am not a member of the machine learning research community).  Here, I will share my implementation, in MATLAB, of the method created/communicated by Marc Boulle in 2006; this was the method I found the most compelling after performing a review of the discretization literature.

The implementation

The algorithm is described (and derived, and analyzed, and experimentally compared with other methods) in "Boulle, Marc (2006). MODL: A Bayes optimal discretization method for continuous attributes. Machine Learning, 65:131-165."  The algorithm consists of a criterion which allows one to compare different potential partitionings of the data and a method for attempting to find the best partitioning, based on this criterion.

My implementation uses two 'linked lists' (in quotation marks, because they are implemented as the MATLAB generic array data type, instead of a distinct linked-list data type).  The first list contains the data on the partition intervals in the data; this information includes the total number of instances of the sample data in the interval, the number of instances of the sample data from each output class in the data, and the identity of the first an last member of the data set in each interval.  The second list points to adjacent pairs of the intervals in the first list, and is sorted according to how much the criterion would be improved by the merger of the pointed-to intervals.  The algorithm proceeds by merging the 'best' pair of adjacent intervals, then updating the lists to reflect that merger.  The algorithm is called 'greedy', as it always chooses the most immediately obvious 'best' merger, even though that may not lead to a universally optimum solution.

My implementation of this algorithm (including some support functions) is included in this archive.

A quick test

Here's some example data I generated, along with the optimal discretization returned by the algorithm (as implemented in MATLAB).  The 1000 sample data points were drawn from equal-variance gaussian distributions whose means were different and determined by their output class value.  The 1000 sample data points are plotted below; the y-axis is an individual data point's continuous value, and the point's color corresponds to its output class value.  The horizontal lines show the edges of the  intervals determined by the algorithm; as you can see, the classes (colors) are well-segregated by the edges.  Intuition suggests that there would be four edges (separating the five output classes); in the case below, there is an additional edge separating the contentious transition region between the dark blue and cyan classes.

Sunday, May 6, 2012

Project updates (or, why is it that the least interesting parts of a project make up most of the effort?)

In the last few weeks (since I tested out the OLED display), I've been getting all of the last little details in place to move forward with the sleep mask project.  Specifically, since the circuits have been finalized, I have been laying out the printed circuit board and making certain that I have all of the necessary components on hand (and putting together an order for those I do not).

The cheapest service I could find is Seeed Studio's Fusion PCB service.  For a mere 10$ you get 10 5x5cm boards; an extra 15$ gets you 5x10cm.

After completing the board layout (shown below), I found that it was more than 5x5cm.  It is larger than I had hoped, but still reasonable relative to the size of the sleep mask.  A large part of its... largeness... is due to the fact that I was designing based on the parts I already had in my inventory.  Those parts, in turn, were chosen to be usable across many projects; as a result, they are usually rated for much higher voltages, currents, and dissipated energies than are strictly necessary for this project.  This is okay for a prototype, but any future hardware revisions will involve specifying more appropriately-sized resistors and capacitors.

Since I was going to have to pay for an extra 5cm of board, I decided to make the best of it and add a circuit for a project I've had on the back burner for a while.  Specifically, I want to build some flashing lights into my bicycle helmet for safety; some of the lights will be ordinary LEDs, but eventually I want to build some EL wire into the helmet to give a real Vegas feel.  To do this, I need 'high voltage' (about 20V) to step up to 120V using transformers.  While I am still collecting the transformers (I take them out of burned-out CFL lightbulbs, as transformers or even bare magnetics of appropriate size have proven difficult to source), I am going to move forward with getting this board, including the 20V step-up and LED constant-current drivers, layed out and ordered.  It is also shown in the image below.


The REM sleep mask board is on the left; the microcontroller is in the middle, with the micro USB connector above, battery charger above right, buck converter right, REM detector bottom left, headphone amplifier left and OLED display top left.  The helmet flasher/boost board is on the right; boost top left, EL wire switches bottom left, microcontroller bottom right and LED drivers top right.

Saturday, April 21, 2012

SPI OLED A-OK (or, I would like to apologize to my readers for the preceding title)

I've reached another milestone in the development of my sleep mask: the OLED module works.

This section of the project was relatively straightforward: basically nothing more complicated than establishing a serial connection to the device and starting it up appropriately.

The Hardware

This is identical to my original design, which was, in turn, copied from the module datasheet.  This is the same hardware as is sold by Adafruit Industries; I acquired mine from another source, without the breadboard-friendly PCB attached.  It has an on-board capacitor charge pump to provide the high-voltage (~7.5V) necessary to drive the OLED pixels.  The serial interface is identical to the Serial Peripheral Interface (SPI) with a Command/Data select line and a Reset line in addition to the usual Chip Select line.

The Software

The stripped-down testing firmware I used is posted here.  It's not much to look at; it just starts up the SPI on-chip peripheral and sends the necessary command bytes (while manipulating the control lines appropriately) to start up and activate the display module.  It then starts sending out data bytes to change what is shown on the display.  The commands sent are outlined in the module controller's data sheet (the Solomon Systech SSD1306).

The controller continuously updates the pixels in the display by reading from an internal display memory.  When data is written to the device, it is used to update the contents of this display memory.

The folks at Adafruit have also implemented some software to drive this display module.  My software is largely the same, with one noticeable difference.  The controller contains twice as much display memory as needed for the module (to make it capable of driving larger displays); when writing to this memory over the serial link, the memory is all written over in turn before restarting at the beginning.  The Adafruit software just writes zeros onto that second half of the driver memory; however, there is a command which allows you to set the limits of the memory to be written.  By setting this command to only write over the usable half of the memory, my software doesn't need to write the entire memory every time, only the half that is actually visible.  In this way, I don't need to devote as much of my computational resources to updating the display.

The Goods

The test hardware setup is shown below.  As usual, I used my oh-so-refined soldering and fabrication skills to gain access to the tiny pads on the end of the display's ribbon connector.  The connections are relatively simple; a few decoupling caps between power pins to ground, some pass-throughs for the serial link, and the two capacitors for the charge pump.


To prove that I actually got this to work, here is a short video of the device (and ATXMEGA controller) as power is applied; first the display is told to turn all the pixels on, then it displays from the display memory (which is, initially, full of noise; this is in contrast with the data sheet, which states that the RAM should be blanked after a reset cycle).  Then, the controller starts sending alternating frames of display data.



The firmware source containing the specification of the alphabet/symbols is here.

Sunday, April 15, 2012

REM detection hardware, firmware and software tests (or, I honestly had some doubts that this would work so well)

On the REM-detecting, white-noise-generating, potato-julienne-ing project front, I have finalized the hardware (and toyed with the firmware) for the REM detector subsystem.

To recap this project: I am developing a sleep mask which will be able to detect the REM (rapid eye movement) phase of sleep, and wake the user up at the 'optimal' point in their sleep cycle.  Additionally, it will be able to record the timing and duration of REM sleep phases (potentially useful for improving sleep) and it will be able to generate white, pink or red noise through speakers at the ears to improve sleep.

I mocked up the hardware and some firmware which sends acquired REM detector samples over a serial channel; I also had to put together some software to acquire, interpret and plot this serial information.  The results of this effort have allowed me to finalize the hardware design for the REM detector subsystem.  As it stands, all I have left to finalize of the hardware is the display and the USB interface hardware; once these two things are nailed down, I can design and order the boards and fabricate the hardware, moving to the firmware-only phase of the project.

Finalized hardware

The hardware has been modified from the schematics I presented originally.  These changes are due primarily to two factors: the microcontroller has an internal gain (negating the need for a second external gain stage) and the desire to used a switched-emitter topology (that is, the illumination of the eye for REM detection will only be on for a small percent of the time to save power).

As seen in the schematic below (the left op-amp), the current output from between the phototransistors on the mask is fed into a transimpedance amplifier whose output is fed directly into an ADC pin on the microcontroller.  This single-ended signal can eventually be used to set the emitter amplitude.  This signal is also fed into the positive side of a differential ADC (with gain); the negative side is fed from a lowpassed PWM output.  This negative input can be used to bias the differential ADC channel to maximize dynamic range; the lowpass converts the oscillating PWM signal into a DC signal whose level is the rail voltage times the Duty Cycle of the PWM waveform.  The transimpedance amplifier feedback resistor is set to 40kOhm to maximize signal amplitude while preventing saturation under normal (and even some abnormal) usage conditions.
The driver circuitry has been significantly improved in this schematic.  Specifically, an op-amp is used to 'linearize' the current control.  Above, a sense resistor is used in negative feedback to set the current through the infrared emitter; the set point is determined by a lowpassed PWM fed through a voltage divider.  Without the 'linearization' of the sense resistor and negative feedback, the highly nonlinear nature of the emitter's current/voltage characteristic meant that only a few of the possible PWM output levels were 'useful' (that is, corresponding to levels of current we would want to drive our emitter with).

Additionally, the op-amp makes driving the emitter simpler; its high input impedance simplifies the design process for the lowpass-PWM easier.  Additionally, it makes it simple to add an enhancement N-FET to allow for switching the emitter on and off (by tying the control input of the op-amp to ground).

Firmware/Software for debugging

To debug the REM detector hardware, I needed to implement a firmware to sample the REM detector input channel and transmit that data to my laptop.  I also needed to create software on my computer to acquire and plot the transmitted serial data.  The firmware and software are contained in this zip archive.

The big questions I needed to answer were: what do I need to do to keep the differential channel biased appropriately, and how long does the emitter need to be on to ensure that the phototransistor signal is stable before sampling.

The firmware samples the single-ended and differential ADC channels.  It then updates the PWM bias setting on the negative input of the differential channel to keep the differential signal centered.  It then formats a couple of serial bytes according to the ADC data and sends them to the computer.

To plot this serial stream, I made a function in MATLAB that opens the serial port and continuously samples the incoming bytes, breaking up the stream into sequences, translating them into floating-point numbers and displaying them on the screen, as seen below.  The blue trace is the single-ended ADC channel, the green trace is the differential channel, and the red is a moving-average of the green.

I waggled my eyes at the beginning and middle of the plotted waveform; you can see that the signal is well-modulated by eye-waggling, which is necessary for detection of REM.
I used a USB oscilloscope (the Hantek DSO-2090, highly recommended) to check out the settling time for the phototransistor signal in response to switching the emitter.  At the end of the day, I established that a switched emitter could be timed to allow for detection of REM using the specified circuit, so I have finalized that circuit and am moving on to validating the USB and display subsystems.

Wednesday, April 4, 2012

Plotting bars, whiskers and bridges in MATLAB (or, too much time spent getting the spacing just right)

I needed to plot the mean and variance of some data, and indicate pairs of data points which were significantly different.  I searched and searched, but there was no easy plot function in my environment of choice (MATLAB), so I made one myself.

The look of the plot is shown below; basically, you've got clusters of mean+variance data (or whatever you want to represent with a bar and whisker).  Within each cluster, there are pairwise relationships you want to indicate.  Relationships can be further specified by a variable number of marks above the bridges.
The function is here.  It takes three arguments: the first two are (number of clusters)-by-(number of bars per cluster), and represent (respectively) the height of the bars and the length of the whiskers.  The third argument is (number of bars per cluster)-by-(number of bars per cluster)-by-(number of clusters) and indicates whether a bridge should be drawn between a pair of bars; a nonzero value indicates that a bar should be drawn, and integers greater than one indicate that extra indication (in the form of circular marks) should be made above the bridges.

It's not the prettiest, but it works and it got the job done well enough for me.  Besides, any fine-tuning is going to be done in your vector editor of choice, so all that's important is getting the actors arranged on the stage.