A first attempt at figuring out the MAX30105 Air Particle Sensor

A project log for Iteration 8

Science in your hand. A pocket-sized instrument capable of visualizing and exploring the world around you. (Iteration 8)

peter jansenpeter jansen 03/27/2017 at 03:574 Comments

One of the areas of sensing that I don't have a lot of experience with is atmospheric sensing. While I've become familiar with sensors for temperature, pressure, and humidity, I am largely inexperienced with the array of sensors available for sensing various gasses or air quality metrics -- in large part because they've appeared too large or too power hungry for a handheld device, and/or generally having issues with accuracy. But clearly measuring air quality is an important social topic, and very useful for science education, and so it'd be great to be able to do this reliably in a small handheld instrument in one's pocket.

I was excited last autumn to see Maxim release the MAX30105 Air Particle Sensor, an extremely small (~6x3x2mm) surface mount sensor listed as being able to detect air particles (they give the example of smoke detection on the product website). I was eager to see how this might work for detecting air particle measures like ambient dust level, or particle counts (e.g. PM2.5, a measure of how many particles are in the air that have a diameter of less than 2.5 microns), so I thought I'd run a few experiments.

A quick first pass

In order to see how well the MAX30105 compares with traditional air quality sensors, I ordered a few common air quality sensors (the DSM501A, above, and one of the popular Sharp line of sensors), and quickly cobbled together a MAX30105 breakout board to get a sense of what the data coming off the sensor looked like by eye. After about half an hour of recording in open air, I could easily notice changes in particle density from the DSM501A when (for example) opening up a window, but was not easily able to see these changes reflected in the MAX30105 data.

The MAX30105 has 3 LED channels (red, IR, and green). Above are histograms of the counts coming off each channel. Before seeing this, I hypothesized that particle detection might appear as follows:

The above distributions look very close to unimodal Gaussian distributions -- so no extra overlapping distributions to support Hypothesis 1. The means also didn't seem to reflect Hypothesis 2, but I had very little data, and given the width of the distributions, any number of other issues could be at play -- noise from ambient light (though there is supposed to be some ambient rejection), improper mechanical placement, and many other issues.

The MAX30105 datasheet is very light on details about the particle sensing application, so I e-mailed technical support with my data to see if any additional help or application notes were available. They were only able to say that the MAX30105 requires "very smart algorithms" to function, and that they were happy to sell those algorithms through a third-party distributor. It seems unusual to me to sell an air particle sensor without describing how it can be used for particle sensing, but hopefully with some work one can characterize what air particle sensing tasks it's useful for, and how well it performs at those tasks.

A less quick second pass

To help control for as many variables as easily possible, I constructed a mount for the sensors to help (a) reduce the effect of ambient light on the sensor readings (if any), (b) contain all three sensors being tested, and (c) help ensure that all three sensors were being exposed to similar atmospheric conditions (without knowing enough about fluid dynamics to control for things like air flow). I ended up with this plumbing pipe from Home Depot, that contains a mount with the sensors in the middle, and two elbows on either end to dramatically reduce the ambient light inside the tube. An Arduino Uno using the open drivers for these sensors controls everything.

The mount (placed inside the tube) has the Sharp sensor mounted at the front, followed by the DSM501A sensor, and the Sparkfun breakout for the MAX30105 sensor last.

The tube also contains a fan on the bottom elbow that (very slowly) moves air through the tube, as well as the cables from all the sensors.

Data collection

I collected data from a small handful of locations:

The above dataset is available here in csv format (3 channels MAX30105, 2 columns from Sharp, and 4 columns from the DSM501A. The Sharp and DSM501A have both raw and interpreted values -- see code below).

For the sampling protocol:

Ideally the sampling would have been simultaneous between all sensors, but for speed I was making use of the open drivers -- so here the readings between sensors may be delayed by as much as a minute or more. To reduce this effect, I throw out most of the 10,000 MAX30105 samples, comparing only the first 1,000 samples to the most recent Sharp and DSM501A data (hopefully delayed by only 10-60 seconds).

Here are the relevant configuration bits for the MAX30105 driver that this test used:

// The following are relevant configuration snipits for the MAX30105 from the test code

// MAX30105 Configuration

byte ledBrightness = 0x7F; //Options: 0=Off to 255=50mA
byte sampleAverage = 1; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 3; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
int sampleRate = 1000; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; //Options: 69, 118, 215, 411
int adcRange = 4096; //Options: 2048, 4096, 8192, 16384

// Sharp, DSM501A drivers ...
// Setup() ...

// Main Loop
unsigned long loops = 0;
void loop() {

  samplesTaken = 0;
  loops += 1;
  particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
  while (samplesTaken < 10000) {
    particleSensor.check(); //Check the sensor, read up to 3 samples

    while (particleSensor.available()) {

      if (ENABLE_SERIAL_OUT == 1) {     
        Serial.print(voMeasured);        // Sharp      
        Serial.print(dustDensity, 3);    // Sharp
        Serial.print(lowpulseoccupancy); // DSM501A O1
        Serial.print(concentration);     // DSM501A O1
        Serial.print(lowpulseoccupancy2);// DSM501A O2
        Serial.print(concentration2);    // DSM501A O2

      if (ENABLE_SD_OUT == 1) {
        dataFile.print(dustDensity, 3);

      particleSensor.nextSample(); //We're finished with this sample so move to next sample
  //particleSensor.setup(0, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings

  // Poll sharp sensor
  for (int i=0; i<10; i++) {

  // Poll DSM501A sensor

  // Flush SD card

Data Analysis

I chose three methods for the analysis, based on the above hypotheses for how the measurements might reflect air quality. They're all based on determining the correlation between various measures from the MAX30105 and the Sharp and DSM501A sensors using Spearman's Rho. Assuming that the data from each of these sensors is linearly related, a correlation of 0 means that the below measures from the MAX30105 are returning completely different information than the measures from the Sharp and DSM501A sensors, and a correlation of 1 means that they're returning exactly the same information. I chose this measure because it should help control for issues like the relative sensitivity between each of the sensors. It would not control for cases where the data from the sensors has a non-linear relationship (e.g. exponential), but hopefully we'll be able to verify this by plotting the data.

Method 1: Correlations (Mean values of 1000 Red/IR/Green samples)

With this first method, I take the mean value of 1000 samples of the red, IR, and green channels from the MAX30105 (nominally about 1 second of data), and determine the correlation with the most recent output from the Sharp and DSM501A sensors.

Interpretation: Unfortunately in this case it doesn't look like the mean MAX30105 data is strongly correlated with the Sharp or DSM501A sensors. The small correlations on individual datasets wildly change magnitude and direction, further reenforcing this. This makes Hypothesis 2 unlikely -- that the air quality data is reflected in the mean of the distribution.

It's also interesting to note that there isn't much of a correlation between the Sharp and DSM501A sensors (or, between the two DSM501A channels, for that matter) -- further reenforcing the idea that these are measuring two different things (e.g. overall air dust level vs particle size counts).


Data Set 1: Beside an open window at home while the neighbours were barbequing

MAX RED10.92
MAX IR10.840.49-0.160.05
MAX GREEN10.42-0.24-0.30
DSM501A 0110.10
DSM501A 021

Data Set 2: Several hours of heavy woodshop use at the local makerspace (from an adjoining room)

MAX RED10.18
MAX IR10.02-
MAX GREEN10.39-0.58-0.51
DSM501A 0110.42
DSM501A 021

Data Set 3: As above, but directly inside the shop

MAX RED10.640.290.330.170.52
MAX GREEN10.55-0.51-0.09
DSM501A 0110.57
DSM501A 021

Data Set 4: Outdoors on the back porch of the Makerspace

MAX RED10.500.90-0.77-0.17-0.33
MAX IR10.21-0.520.59-0.36
MAX GREEN1-0.59-0.48-0.45
DSM501A 0110.57
DSM501A 021

Example Data:

Above is a plot from data set 2 (near the wood shop), comparing the red channel from the MAX30105 with one of the DSM501A channels. Here the data is really all over the place -- It'd be very hard to draw a straight line that captures the relationship between these two sets of data, so the correlation is low.

Method 2: Correlations (Standard Deviation of 1000 Red/IR/Green samples)

My second method is largely a guess -- if the mean value doesn't appear to reflect the air particle level, perhaps the amount of variance in the distribution (i.e. the standard deviation) on short timescales (i.e. 1 second at 1000 samples/second) contains some of this information. This is largely a guess -- I can come up with a few physical reasons why this might be the case, but perhaps also just as many for why it likely wouldn't be the case (so definitely a post hoc test). Let's see what happens.

Interpretation: DSM501A: We actually do see a moderate-to-strong (0.52 to 0.75) correlation between the red channel of the MAX30105 and the DSM501A Output Channel 2 across all four datasets. There are also smaller correlations with the green channel of the MAX30105. There does not appear to be a correlation with the IR channel -- which is interesting, as it's my understanding that the Sharp and DSM501A sensors use an IR LED/photodiode for their detection (though perhaps of a significantly different wavelength).

Sharp: There does not appear to be a correlation between the standard deviation of the MAX30105 measurements and the value of the measurement from the Sharp sensor.

Data Set 1: Beside an open window at home while the neighbours were barbequing

MAX RED1-0.170.710.270.280.58
MAX IR10.08-0.12-0.03-0.06
MAX GREEN10.260.230.65
DSM501A 0110.10
DSM501A 021

Data Set 2: Several hours of heavy woodshop use at the local makerspace (from an adjoining room)

MAX RED10.040.82-0.400.770.69
MAX IR10.14-0.08-0.01-0.04
MAX GREEN1-0.300.580.57
DSM501A 0110.43
DSM501A 021

Data Set 3: As above, but directly inside the shop

MAX RED10.600.720.060.560.75
MAX IR10.770.350.080.43
MAX GREEN10.290.110.38
DSM501A 0110.57
DSM501A 021

Data Set 4: Outdoors on the back porch of the Makerspace

MAX RED1-0.400.950.050.470.52
MAX IR1-0.26-0.52-0.78-0.79
MAX GREEN1-0.190.420.43
DSM501A 0110.57
DSM501A 021

That looks promising -- let's combine these four datasets into one, and have a look at the data to see if the relationship between the MAX30105 RED channel and the DSM501A O2 looks roughly linear:

Note, the zeros from the DSM501A reflect 10 second sampling periods where no particles were detected. These are automatically removed from the data set before running the correlation, and are likely an artefact of the very short (10 second) sampling period used for the DSM501A. With simultaneous sampling of the MAX30105 and DSM501A, these sampling periods could be increased quite a bit without having to worry about the sensors sampling different conditions.

Aside from the zeros (outliers) that floor the distribution, the remainder of the distribution does give the impression that there is a linear relationship between the MAX30105 RED channel and the DSM501A O2. The correlation on this combined dataset (0.71, below) also seems to support this.

Concatenated Data Set: Most of all of the above datasets

MAX RED1-0.120.82-0.110.630.71
MAX IR10.020.10-0.21-0.14
MAX GREEN1-0.100.440.58
DSM501A 0110.38
DSM501A 021

Method 3: Only looking at the tail mass

In spite of the above, I still feel like hypothesis 1 -- that particles moving in front of the detector should create a bimodal distribution, much like the detection methodology of the DSM501A sensor -- is a likely source of signal, and that we should be able to detect these cases by masking out the main bulk of the distribution, and looking only at the outliers. Histograms like the one below, where a small number of samples appear to the right (higher reflectance) of the main distribution, only make me think this might be where the majority of the signal is hiding, and that the standard deviation is just leaking some of this information through.

Masking out the main bulge (+/-5 bins from the center), and summing the remaining mass, this is the plot we get over ~80 sampling periods (below, using dataset 2, a long collection near the woodshop). If this truly reflects air particle level, it would be suggesting that there was a gradual dip around time point 30, and a steady increase up until point 80. This would make some physical sense, since (anecdotally) the woodshop probably became dustier as more folks came in to work on their projects.

Unfortunately this isn't clearly reflected in the distribution from the conventional air quality sensors (the Sharp and DSM501A) in the plot below, or in the correlations between this measure and the Sharp/DSM501A values. To give a sense of this data, the DSM has a lot of high-frequency changes:

Where the Sharp generally reports a value that oscillates around a mean value:

And, to verify that the mean value of the Sharp sensor changes depending on the environment, let's have a look at the means for the different data sets:

DataMean ADC ValueMean Dust Density (mg/m^3)*
Data set 1 (indoors beside window at home)244.70.104
Data Set 2 (near busy woodshop)287.20.140
Data Set 3 (inside busy woodshop)287.40.142
Data Set 4 (outside in dusty parking lot)264.20.124

(* the open source driver uses the characterization from to derive the dust density)

Next Steps

This is a promising first step -- it looks like the MAX30105 may deliver measurements similar to the particle measurements from one of the outputs of the DSM501A (which I believe is sensitive to PM2.5 levels, though the datasheet is a little unclear about this).

There is a great post on Make by Tim Dye who characterized several inexpensive sensors with a professional air particle reference instrument, and showed that some inexpensive sensors tend to have a strong correlation of 0.7-0.8 with the reference instrument he used, under different particle conditions. If we consider this characterization of the MAX30105 as a promising first step, then ideally a similar characterization using a proper air particle reference instrument (rather than these inexpensive sensors) can yield a more full characterization of the MAX30105's capabilities under a variety of different particulate scenarios, and help enable inexpensive and millimeter-scale air quality characterization instrumentation.

Thanks for reading.


Keith wrote 01/20/2018 at 15:25 point

Love your work so far with the Max30105, I just order one of these boards. I also was eager to see how this might work for detecting air particle from smoke. I contacted the vendor and they also directed to a 3rd party for any algorithms. The only thing I got out of them was "Each type of particle reflects the three light wavelengths in different ratios, which can be used to identify particle type and concentration". Not much help. 

Please keep me updated with any new developments. Again, great start keep going!

  Are you sure? yes | no

JTLiphardt wrote 06/16/2017 at 05:51 point

Hi Peter - great job. I had a quick look at your dataset, and here are some impressions. 

1/ You need to thermally compensate all three channels first - presumably that is why the MAX30105 has a temp register (0x1F–0x21). 

2/ As a first step, subtract off the Mean[] from each data trace for the 3 optical channels. 

3/ Run the channels through an ExponentialMovingAverage. You should see a nice modulated signal. 

4/ Note that the sensor is based on differential scattering from differently sized particles, based on Mie scattering. So everything will be based on ratios, as with all devices of this type for the last century. Follow steps 1-3 for your dust4_xc _outsidebackdoor.csv dataset and then compute Ch1/Ch2. Enjoy.

Here are some compensation parameters for your dust4_xc _outsidebackdoor.csv

Background CH1: -46.6 + 68.55*Exp[-4.14^-6 x]

Background CH2: -24 + 38.26 Exp[-5.036*10^-6 x]

Background CH3: -6.48 + 20.49 Exp[-0.0000150077 x]

For each channel, subtract off the background, and then 

particleDensity = (ch1corr + 30)/(ch2corr + 12.7).

I have absolutely no idea what units that is in; someone will need to figure out the actual temp comp parameters for the sensor, and then use calibrated particles to create a calibration lookup table for the sensor. I recommend to try to figure out the temperature compensation first.

The is another thing - the Datasheet for the sensor gives the quantum efficiency of the sensor. QE near 0.62 at 750 nm, worse left and right of that. Somehow the QE will need to be taken into account, too. The first step would be to read off the QE from the PHOTODIODE QUANTUM EFFICIENCY vs. WAVELENGTH plot in the data sheet, for the three colors, and then correct the sensor channels for the different QEs.


  Are you sure? yes | no

Ken Biba wrote 05/26/2017 at 23:14 point

Great work.   I am looking at using this sensor to measure dust levels in the atmosphere using rockets and/or balloons rather than the bulkier Sharp sensor.   Keep it up!

  Are you sure? yes | no

Rodrigo wrote 04/19/2017 at 00:56 point

I was researching some material on particle detection using the MAX30105 and I found you.
I am a student from Brazil and I want to use this sensor to identify particles, in the datasheet of the sensor it is informed that it is possible from 2μA to 16μA. You did a bele job, how can I keep up with the developments? Because I ordered a module in the sparkfun store.
My contact is

Thank you friend,


  Are you sure? yes | no