Project help?? LED's as sensor LCD displaying wavelength!!

Hey looking for some help.

I am using an arduino Duemilanove board. Using a Bi-colour LED (Red&Yellow) as a light sensor (so in reverse). Since the output current of each LED was so small I have built op-amps. I now get milivolts output which changes with wavelength. I would like to take the outputs and and use them as inputs on the arduino. Then use the ratio between the inputs which will correspond to a specific wavelength which will be displayed on an LCD screen.

I have done all the measurements and circuit is built. Results below.

Red LED (mV) Yellow LED (mV) Ratio Wavelength (nm) -100.3 -55.8 0.556331007 571.8465 -121.15 -36.2 0.298803137 579.443 -145 -10.8 0.074482759 587.0395 -154.2 -7.6 0.049286641 591.5974 -166.15 -2.8 0.016852242 594.636 -161 -2.1 0.013043478 597.6746 -172.4 -1.15 0.006670534 602.2325 -175.05 0.3 -0.001713796 609.829 -151.8 0.5 -0.003293808 617.4255 -102.8 0.5 -0.004863813 625.022 -44.1 0.5 -0.011337868 632.6185

So the many questions I have are: Am I able to convert these ratios to a wavelength on th LCD? Can I do it all on the board itself or do I maybe have to amplify the outputs as they are milivots. Basically feel like I've hit a brick wall and any help or advice would be much appreciated. xxx

Am I able to convert these ratios to a wavelength

Sorry no. There is no corrilation between yor reading and wavelength.

There is correlation between my readings and the wavelength as these are the voltage readings I have taken at various wavelengths using a monochrometer.

I was hoping to find out if or how I could take the ratio of the voltages, and use this to display a number corresponging to that ration on the LCD.?

Please let me know if u want more info?

There is correlation between my readings and the wavelength as these are the voltage readings I have taken at various wavelengths using a monochrometer

Repeat the measurements but cut down the amount of light you get from your monochrometer with say a neutral density filter or blocking part of the light path. Do you still get the same ratio? If you do then you do have a corrilation until then I remain skeptical.

Yes I have done this with ND filters and unsing polarises both are linear, across the wavelength I am using the ratio is the same for any intensity.

I now the Physics behind this just struggling with microcontroller.

Mandy Xxx

So all you need to do then is to put your ratios into a look up table. It has a disorders input and output so one way is to have a two dimensional array of wavelength and the corresponding ratio. Then with an unknown ratio you search the array until you find a match or closest entry then that entry in the second dimension is the wavelength.

You can get cleaver and do an interpolation between the two closest ratios if you want.

Hi Mandy,

Interesting project,

Please read my multimap article on the playground - http://arduino.cc/playground/Main/MultiMap - Although it was meant for integers it can be rewritten easily to handle floats. Put the ratio’s and freq in the tables to get it working.

Furthermore you must amplify the signal to a 0…5Volt range so the ADC in the arduino can measure it more accurately.
The - http://www.arduino.cc/en/Reference/AnalogRead - function will return a value between 0 and 1023 for each LED and you can calc the ratio.

The code will look like below : - not yet complete but it should give you a start:

float ratios[10] = {......};
float frequencies[10] = { .....};

void setup()
{
  Serial.begin(115200); 
}


void loop()
{
  int red = analogRead(A0);
  int yellow = analogRead(A1);
  float ratio = (1.0 * red ) / yellow;   // this will be different values than in your table. and you must make a float of it!

  float freq = FmultiMap(ratio, ratios, frequencies, 10);
  Serial.println(freq, 2);
}
  

  
float FmultiMap(float val, float * _in, float * _out, uint8_t size)
{
  // take care the value is within range
  // val = constrain(val, _in[0], _in[size-1]);
  if (val <= _in[0]) return _out[0];
  if (val >= _in[size-1]) return _out[size-1];

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while(val > _in[pos]) pos++;

  // this will handle all exact "points" in the _in array
  if (val == _in[pos]) return _out[pos];

  // interpolate in the right segment for the rest
  return (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}

@robtillaart But that function simply takes the two end points of each of the ranges and maps them together like a rather simple minded linear mapping from the two points. It will not take into account any of the data in the middle of the table. I can't see it working at all.

THANKS GUYS

I'll give it a go and let you know how Im getting on.

Mandy xx

The ratios form an array of values; the frequencies form a list of values; These can be seen as points from a curve.

The curve is approximated (indeed) by a linear interpolation between the two points that are closest. These points are searched for by

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while(val > _in[pos]) pos++;

Please note that the ratios (_in) array must be from low to high => increasing values. The out array can take any “form” but the interpolation is linear. Add more points for a better approximation. Note that the values of the in array don’t need to be equidistant.

If the right interval is found there is a linear interpolation between these points and the value found is returned.

Run this example code to see it work!

void setup()
{
  Serial.begin(115200);

  for (int i = 80; i<512; i++)
  {
     Serial.println(sharp2cm(i), 1);
  }
}

void loop()
{
}
  
// for a sharp range finder
float sharp2cm(int val)
{
  // out[] holds the values wanted in cm
  float out[] = {150,140,130,120,110,100, 90, 80, 70, 60, 50, 40, 30, 20};
  
  // in[] holds the measured analogRead() values for that distance
  float in[]  = { 90, 97,105,113,124,134,147,164,185,218,255,317,408,506};
  
  return FmultiMap(val, in, out, 14);
}



float FmultiMap(float val, float * _in, float * _out, uint8_t size)
{
  // take care the value is within range
  // val = constrain(val, _in[0], _in[size-1]);
  if (val <= _in[0]) return _out[0];
  if (val >= _in[size-1]) return _out[size-1];

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while(val > _in[pos]) pos++;

  // this will handle all exact "points" in the _in array
  if (val == _in[pos]) return _out[pos];

  // interpolate in the right segment for the rest
  return (val - _in[pos-1]) * (_out[pos] - _out[pos-1]) / (_in[pos] - _in[pos-1]) + _out[pos-1];
}

You won't need to bump the signal up to 5V you can use the "analogReference" function to set the reference voltage to either INTERNAL (=1.1v) or the AREF pin and provide a reference voltage there.

More info here... http://arduino.cc/en/Reference/AnalogReference

Hi Mandy...

I'm really interested on your results from this project... I want to do the same, but for UVA light, using UV and blue leds... so if you could share your findings on this project I would really appreciate!!

Specially your wavelenght/microvoltage table would be really helpfull, since I don't have access to a monochrometer, like you! =)

:)