Teensy Fiber Photometry Neuroscience

Status
Not open for further replies.

ONECore

Member
Brief intro: I am looking for 2 sinusoidal outputs at 211 Hz and 531 Hz, with Vmin and Vmax between 0 and 5V, and record an analog input with maximum at 12V, with at least 16 bit accuracy and 12 ksamples/sec. Doing this will greatly advance science. Looking to use the Teensy 3.6.

Science background: There is a system to monitor specific neuronal cells within a population of a behaving animal called fiber photometry. It uses two high powered LED at different wavelengths to excite a protein called gcamp. When these lights hit gcamp, the protein will fluoresce and we can measure that with a photodetector. There are two wavelengths because the florescence at one wavelength changes in the presence of calcium and the other does not (Calcium is released when a neuron fires). Therefore, you can use two wavelengths to remove a lot of noise and understand when a specific cell is firing. We can learn a lot from this (!). In order to tease apart the florescence from each wavelength, we modulate the LEDs with a sinusoidal signal. This allows for FFT analysis after recording. We choose to modulate at 211Hz and 531Hz.

I therefore need to drive two LEDs at 211Hz and 531Hz, ‘rather smoothly’ (12 bit?). Simultaneously I need to record an analog signal from a photodetector, at probably 16 bit, 12 kHz, probably dumped to the serial port to record.

Voltages: the sinusoidal outputs need to go from near zero to 5V. But I also need to control the Vmin and Vmax. I believe I can use the Sparkfun PN TXB0104. But that is 4 bit. Does that mean that even if I output 12 bit analog signal, only 4 bits come out of the TXB0104. What else can I use? The Photodetector is 12 V. I think I can just use a voltage divider to bring this down to the 3.3 V of the Teensy, right?

I based my code thus far on https://www.pjrc.com/teensy/teensy31.html. But the frequencies seem inconsistent. (It’s a work in progress, I don’t have any analog read or serial dump yet). And I don’t understand why, but when I set the Vmin and Vmax to 3.3 V and 0 V respective, the output is a sine that looks more like a square wave (the sine is obviously going beyond the 3.3 and 0 V of the system, so the system clips).

I think that perhaps the best way to get true frequencies would be to abandon this code, and move to the Teensy Audio Library. But I was hoping for some reassurance that that could work from someone that knows that they are doing. I am a simple ME. Any thoughts or reassurance would be GREATLY APPRECIATED. Sorry for the long post.

HTML:
/*
   Fiber Photometry on a Teensy
   Optogenetics and Neural Engineering Core ONE Core
   University of Colorado
   3.Oct.17
   See optogenetic.ucdenver.edu for more information, including a detailed write up and BNC housing 3D Model
   y = a sin (bx+c)
*/

//////////// This section defines the pins on the Teensy. These are global variables. /////////////////////////////////////////
float twopi = 2 * 3.14159;
float thetaCh1 = 0.0;
float thetaCh2 = 0.0;
elapsedMicros usec = 0;

//The analog in through which we we will record from the photodetector. Photodetector outputs up to 12V, so run through a voltage divider.
//From the Photodetector, run through a 1 k Ohm resistor, divide into this pin and another resisotor of 2.61 k Ohm to ground.
//…? ADC0 (A0-A9) and ADC1 (A14-A22), they are multiplexed to 25 pins that we can access. Meaning you can access 2 pins at the exact same time.
///////////////////////////////////////////////////// INputs //////////////////////////////////////////////
#define bitOut 12        //Bit depth of the outputs
#define bitIn 16         //Bit depth of the input (from the Photodetector)
float voltz = 3.3;       //The max voltage output. The Teensy outputs only in 3.3V. LED drivers are looking for 5V. TXB0104 can change between the two.
float VmaxCh1 = 2.3;     //In volts, MAXIMUM of 3.3
float VminCh1 = 1.0;     //In volts
float freqCh1 = 211.0;   //In Hz
float VmaxCh2 = 2.3;     //In volts, MAXIMUM of 3.3
float VminCh2 = 1.0;     //In volts
float freqCh2 = 531.0;   //In Hz

//Math on INputs
double statez = pow(2, bitOut);                   //Top bit corresponds to max voltage, 5 V. That is, (0 to 5 v) is (0 to states) bits.
float VmaxCh1bitOut = (VmaxCh1 / voltz) * statez; //The Vmax of Ch1 in bits
float VminCh1bitOut = (VminCh1 / voltz) * statez; //The Vmin of Ch1 in bits
float VmaxCh2bitOut = (VmaxCh2 / voltz) * statez; //The Vmax of Ch2 in bits
float VminCh2bitOut = (VminCh2 / voltz) * statez; //The Vmin of Ch2 in bits

float AmpCh1bitOut = VmaxCh1bitOut - VminCh1bitOut;     //The Amplitude of Ch1 in bitOut
float offSetCh1bitOut = AmpCh1bitOut / 2 + VminCh1bitOut;   //Offset of Ch1 in bitOut
float AmpCh2bitOut = VmaxCh2bitOut - VminCh2bitOut;     //The Amplitude of Ch1 in bitOut
float offSetCh2bitOut = AmpCh2bitOut / 2 + VminCh2bitOut;   //Offset of Ch1 in bitOut


///////////////////////////////////////////////////// Setup //////////////////////////////////////////////
void setup() {
  Serial.begin(38400);

  //  pinMode(TTL1, OUTPUT);
  //  pinMode(buttonPin, INPUT_PULLUP);

  analogReadRes(16);            //Can be from 0-16. Should match CPU speed??
  analogReference(EXTERNAL);
  analogReadAveraging(16);      // ???????????????????????average this many readings
  analogWriteResolution(bitOut);  //Can be from 0-16. Should match CPU speed?? See https://www.pjrc.com/teensy/td_pulse.html. Don't use pins 16 or 17.
}

//This is the code that the Teensy loops through.
void loop() {
  //Serial.println(offSetCh1bitOut);
  //Serial.println(AmpCh1bitOut);
  float Ch1OutPut = AmpCh1bitOut * sin(thetaCh1) + offSetCh1bitOut;  //Sin calculates the sine of an angle (in radians). The result will be between -1 and 1.
  float Ch2OutPut = AmpCh2bitOut * sin(thetaCh2) + offSetCh2bitOut;  //Sin calculates the sine of an angle (in radians). The result will be between -1 and 1.

  analogWrite(A21, (int)Ch1OutPut);  //Labeled as DA0 on board
  analogWrite(A22, (int)Ch2OutPut);  //Labeled as DA1 on board

  thetaCh1 = thetaCh1 + 0.002;
  thetaCh2 = thetaCh2 + 0.02;

  if (thetaCh1 >= twopi) thetaCh1 = 0;
  if (thetaCh2 >= twopi) thetaCh2 = 0;
  while (usec < 500) ; // wait
  usec = usec - 500;
}
 
There's people on here who know a lot more than me and I might just add to the confusion, so I'll hold off with any technical suggestions.

Out of curiousity, do the neurons actually fire (action potential) when stimulating as such? I thought, for instance, that all the calcium channels open simultaneously with optogenetics, which wouldn't allow the typical action potential propogation.
 
You'll probably get much better sine wave results using the audio library. It has a standard/fast sine wave that uses very little CPU time, with a lookup table and interpolation. There's also a high res sine function which uses Taylor series to compute highly accurate samples. A bug was recently fits in the stereo dac output code, so make sure you use 1.40-beta.

If you really want to do it this way with loop, consider the sin() function can take a different amount of time for different parts of the waveform period. At the very least, compute the two amplitudes, do the wait, and then write the 2 values to the DACs right after the wait.

Also, use sinf() rather than sin(). The extra "f" means it computes in fast 32 bit float. The standard sin() uses slow 64 bit double.
 
There's people on here who know a lot more than me and I might just add to the confusion, so I'll hold off with any technical suggestions.

Out of curiousity, do the neurons actually fire (action potential) when stimulating as such? I thought, for instance, that all the calcium channels open simultaneously with optogenetics, which wouldn't allow the typical action potential propogation.

Optogenetics uses light to manipulate neurons. With optogenetics, you take an opsin protein (similar to what is in your eyes; it reacts to light and causes the neuron to fire) historically from (get this) algae, put it in a virus, and insert it into a mammal (it's human safe). The protein will only express in certain cells (think dopamine cells). When you shine light through a fiber optic, you can cause only these cells to fire (or alternatively not-fire when they typically would). An action potential/cell fire: Calcium actually enters the cell and a neurotransmitter (dopamine) flows out and the next cell is 'spoken to'. The opsins used are their own channels, and are not specific to calcium, really, more so smaller and membrane potential holding ions. Optogenetics is a huge advance to study very specific cells very fast.

Fiber Photometry is a very inexpensive (and even more so if I can figure this out!) way to record cell activity. The light used here is only to monitor very specific cells. These cells express fluorescing proteins. The proteins only fluoresce when light is shown (think very very fast glow in the dark, it requires light input). The amount that they fluoresce is dependent on calcium.
 
Just a few thoughts to consider...

Does the modulation "have to be" sinusoidal? And are you thinking "amplitude modulation" of the LED beam intensity? Likelyhood is that the light intensity will not be linear if it is "voltage driven". Even "current driven" might be non linear at low levels.

If you can tolerate a square wave to modulate, then the creation of your 211 Hz and 531 Hz could be much more precise - and much easier to accomplish. The Flexible Timer Modules (FTMs) could generate frequencies to fractions of a Hz in accuracy. You could vary the intensity by pulse width modulation easier too - now that probably would be more linear (being time dependant rather than amplitude dependant). You might also want to explore the variation with frequency, and creating different frequencies again will be very easy to do using FTM timers.

If you are doing FFT and analysing the frequency spectrum, then with a precise square wave frequency, the harmonics of a square wave should be easy to identify (exact multiples of the base frequencies).

Something to consider.
 
Just a few thoughts to consider...

Does the modulation "have to be" sinusoidal? And are you thinking "amplitude modulation" of the LED beam intensity? Likelyhood is that the light intensity will not be linear if it is "voltage driven". Even "current driven" might be non linear at low levels.

If you can tolerate a square wave to modulate, then the creation of your 211 Hz and 531 Hz could be much more precise - and much easier to accomplish. The Flexible Timer Modules (FTMs) could generate frequencies to fractions of a Hz in accuracy. You could vary the intensity by pulse width modulation easier too - now that probably would be more linear (being time dependant rather than amplitude dependant). You might also want to explore the variation with frequency, and creating different frequencies again will be very easy to do using FTM timers.

If you are doing FFT and analysing the frequency spectrum, then with a precise square wave frequency, the harmonics of a square wave should be easy to identify (exact multiples of the base frequencies).

Something to consider.

Thanks for your consideration!

The rise and fall times of the LEDs typically used in research are quite slow, and therefore a square wave would be quite far from perfect. The FFT analysis would then be thrown way off. You could potentially record the optic output of the LEDs to assist with the FFT analysis, but that might require another $900 photodetector and another analog in. Alternatively, you could use some of the fancy new lasers, but that equipment is on the order of $5k, rather than these inexpensive LED systems. Doable, and interestingly so, but perhaps expensive.

The teensy will output an analog voltage to an LED Driver (thorlabs LEDD1B), which outputs the current to the LED. Controlling Vmin and Vmax output from the Teensy is required to alter the optic output of the system, constant over a trial. I wouldn't necessary call that amplitude modulation. Careful choices for Vmin and Vmax (ex: staying above the forward current of the LED) can result in very good (linear) optical output.

You have given me much to think about. Thank you.
 
The rise and fall times of the LEDs typically used in research are quite slow, and therefore a square wave would be quite far from perfect.
This means that the LEDS act as low-pass filter. So you have the fundamental (your sinusoid) and some harmonics that are attenuated by the LED.
The FFT analysis would then be thrown way off.
why? it would extract the fundamental frequency (which is the same of the sinusoid) and some harmonics you are not interested in.

If you can afford some experimentation, I would simply tray it.
 
This means that the LEDS act as low-pass filter. So you have the fundamental (your sinusoid) and some harmonics that are attenuated by the LED.

why? it would extract the fundamental frequency (which is the same of the sinusoid) and some harmonics you are not interested in.

If you can afford some experimentation, I would simply tray it.

Thanks for the thoughts, but the LEDs would not act as a low pass filter. They output optically with a almost 50% loss over the time course of a 511 Hz pulse. Because of this, it is not simply harmonics of the fundamental. In theory, you could measure the FFT of this applied pulse, and use this information to demodulate the measured output, but each LED is different, so that could require the addition of very expensive equipment. ...Maybe. Perhaps you could use a mirror prior to a trial, and assume that it doesn't change over time. I'll try that today.

Slow LEDs.jpg
A perfect square wave input to the LED results in some delayed optical output. The delay can result in 50% less power than if it was perfect (rise time is slower the fall time).
 
Thanks for the thoughts, but the LEDs would not act as a low pass filter. They output optically with a almost 50% loss over the time course of a 511 Hz pulse. Because of this, it is not simply harmonics of the fundamental. In theory, you could measure the FFT of this applied pulse, and use this information to demodulate the measured output, but each LED is different, so that could require the addition of very expensive equipment. ...Maybe. Perhaps you could use a mirror prior to a trial, and assume that it doesn't change over time. I'll try that today.

View attachment 11733
A perfect square wave input to the LED results in some delayed optical output. The delay can result in 50% less power than if it was perfect (rise time is slower the fall time).

Well, I would call the lower figure as the upper figure pass through an RC (single pole LP filter). (but this may be only semantic)
 
My vote goes with WMXZ... if you lose 50% at 531 Hz (your original post - not 511 Hz), then you cannot guarantee that a sinewave is going to be any more predictable than a square wave. In fact a square wave has probably more predictable performance. The ability to vary the input linearly (which you can do with a sq wave) and see how the output behaves, will tell you more than varying the amplitude of a sinewave.

I looked up the manual for the Thorslab LEDD1B LED driver product. You can drive this with a TTL signal rather than a sinewave and control the power by using Pulse Width Modulation, and although the Teensy pin outputs are 0 - 3.3 volts, this is above the TTL threshold, so should work fine.

All that to one side...

As an academic exercise, I decided to code for 211 Hz and 531 Hz square waves - just to see how hard it would be. There are a few ways how this might be done but I decided in the end to use just one FTM timer (FTM1). I would be interested to hear any other suggestions.

Looking at the maths, 211 Hz has a period of 4,739 uSecs, and 531 Hz has 1,883 uSecs. So one easy way is to create a 1 uSec ISR routine and to keep a tally of two counters inside that routine which controls two digital output pins. Increment the counters on each pass of the ISR, so every count then equals 1 additional uSec. Set the outputs HIGH when the counters are zero and flip the outputs LOW at some intermediate count/time, before the elapsed time of each respective period has been reached. The value of the intermediate count will then dictate the mark/space ratio of the resulting square wave at the digital output pins.

The control over the "energy" in the two output waves (effectively pulses) will accordingly be very fine indeed (better than 1 part in 1000). And it should be linear over a large part of the range.

The resultant waveforms from pin21 (211 Hz) and pin22 (531 Hz) are shown in the next two pictures. The frequency measurements are shown in the top right hand corner. I was pleased to see the results of 211.016 Hz and 531.071 Hz - both accurate to better than one tenth of a Hz.

NewFile1.jpg NewFile2.jpg

Running the ISR at such a fast rate, one thing that worried me was "will the ISR have time to complete" before the next interrupt happens. This is answered in the next picture, which shows the output from the FTM timer raising the interrupt (CH1 Yellow trace) and pin20 (CH2 Blue trace) which is set HIGH and LOW as the first and last statements in the ISR. You can see that the interrupt code is being actioned after only 80 nSecs and it completes after approximately 500 nSecs, leaving the rest of the time for any code to be actioned inside the main loop. Teensy 3.6 performance on ISR handling is very impressive here !! (Note - the ISR fires on both +ve and -ve edges of the FTM1 signal.)

NewFile3.jpg

To test how much processor time is really available for things other than generating the square waves, I added a "LoopCount" (LC) into the Main Loop and printed this every second out to the Serial Monitor. It typically reports 570,000 passes of the loop every second. This design is not the most efficient way to use processing power, but it is simple and it is accurate.

I suppose that a "Periodic Interval Timer" (PIT) might also be used to generate the interrupts for the ISR code in place of an FTM timer. The design could also cut down on the number of times the ISR is called if you use a longer interval than 1 uSec for each count. This depends on how close you need the frequency accuracy to be.

-----

My project code is attached here...

Code:
//Teensy361 - Generate precise 211Hz and 531 Hz
//=============================================
//Author: TelephoneBill
//Date: Thu 12 OCT 2017
//240 MHz CPU speed = 60 MHz Peripheral Clock speed (16.667 nS cycle).
//FTM page in Reference Manual - Page 783.

//NOTES
//-----
//Teensy PINS:
//Pin16 = output - 500 KHz reference sq wave.
//Pin20 = output - 1 MHz strobe pulse (ISR time) - ISR fires on both +ve and -ve edges of FTM1.
//Pin21 = 211 Hz output.
//Pin22 = 531 Hz output.

//Keyboard Command Keys: (case sensitive) Entered via serial monitor
// "q2000" will set 211 Hz to 2 mSec "on" duty cyle
// "q" alone will print current 211 Hz duty cycle (uSecs)
// "a1000" will set 531 Hz to 1 mSec "on" duty cyle
// "a" alone will print current 531 Hz duty cycle (uSecs)

//declarations
#include  <stdint.h>
#define  LED_ON     GPIOC_PSOR=(1<<5)
#define  LED_OFF    GPIOC_PCOR=(1<<5)

bool ControlOn, DisplayOn; //false=0x00, true=0x01
int Byte1, Byte2, Byte3, Byte4, Byte5;   // for Keyboard input via incoming serial data
volatile unsigned int MilliSecs, Secs, DispSecs, MOD1Value, FTM1CountOVFlow, IntCount, dIntCount, LoopCount, dFTM1CountOVFlow, dLoopCount;
volatile unsigned int Output211Count, Output531Count, Output211Control, Output531Control;

//Main Program Setup
//------------------
void setup() {
  //initialise general hardware
  PORTC_PCR5 = PORT_PCR_MUX(0x1);   //LED PC5 pin 13, config GPIO alt = 1
  GPIOC_PDDR = (1<<5);              //make this an output pin
  LED_OFF;                          //start with LED off
  pinMode(20, OUTPUT);              //pin 20 as digital output
  pinMode(21, OUTPUT);              //pin 21 as digital output
  pinMode(22, OUTPUT);              //pin 22 as digital output
  digitalWriteFast(20, 0);          //set pin 20 low
  digitalWriteFast(21, 0);          //set pin 21 low
  digitalWriteFast(22, 0);          //set pin 22 low
  Serial.begin(250000);             //setup serial port
  
  //initialise Flextimer 1
  MOD1Value = 59;      //modulus = 59 (gives count = 120 on each half cycle roll-over) - 60 MHz divided by 120 = 500 KHz)
  FTM1_MODE = 0x05;     //set write-protect disable (WPDIS) bit to modify other registers
  FTM1_SC = 0x00;       //set status/control to zero = disabled (enabled in main loop)
  FTM1_CNT = 0x0000;    //reset count to zero
  FTM1_MOD = MOD1Value; //set modulus value 
  FTM1_C0SC = 0x14;     // CHF=0, CHIE=0 (disable interrupt, use software polling), MSB=0 MSA=1, ELSB=0 ELSA=1 (output compare - toggle), 0, DMA=0
  FTM1_C1SC = 0x0c;     // CHF=0, CHIE=0 (disable interrupt, use software polling), MSB=0 MSA=0, ELSB=1 ELSA=1 (input capture - rising or falling edge), 0, DMA=0
  FTM1_C0V = 0;         //compare value = 0 for CH0

  //enable FTM1 interrupt within NVIC table
  NVIC_ENABLE_IRQ(IRQ_FTM1);

  //lower Systick priority and raise IRQ_FTM priority
  SCB_SHPR3 = 0x20200000;             //Systick = priority 32 (default was zero - highest priority)
  NVIC_SET_PRIORITY(IRQ_FTM1, 0);     //raise FTM1 IRQ to priority 0

  //configure Teensy FTM1 output compare channels
  PORTB_PCR0 |= 0x300; //MUX = alternative function 3 on FTM1_CH0 = Teensy Pin 16
  //(Note - This makes TEENSY Pin 16 a 1 MHz output reference signal)
  
  //enable system clock (60 MHz), no prescale
  FTM1_SC = 0x48;       // (Note - FTM1_SC [TOF=0 TOIE=1 CPWMS=0 CLKS=01 (System Clock 60 MHz) PS=000 [no prescale divide])

  //initialise general variables
  OSC0_CR = 0x02;       //decade incremental slower digital capacitor setting (0x02 = -3.109)
  FTM1CountOVFlow = 0;
  IntCount = 0;
  DisplayOn = true;
  Output211Control = 2370;  //default control value for 211 Hz
  Output531Control = 941;   //default control value for 531 Hz
  
  //blink 4 times
  Blink();
  delay(400);
  Blink();
  delay(400);
  Blink();
  delay(400);
  Blink();
  delay(400);

  //initialise counters and controls
} //end of setup

// ISR routine for FlexTimer1 //FASTRUN puts this code into RAM to run twice as fast
//---------------------------
FASTRUN void ftm1_isr(void) {
  //ISR latency time = 80 nanoSecs after interrupt flag set by FTM1 Timer Overflow
  digitalWriteFast(20, 1);            //set pin 20 high
  
  //reset FTM1 overflow flag
  if ((FTM1_SC & FTM_SC_TOF) != 0) {  //read the timer overflow flag (TOF in FTM1_SC)
    FTM1_SC &= ~FTM_SC_TOF;           //if set, clear overflow flag
  }

  //adjust FTM1 counters
  FTM1CountOVFlow++;                  //increment overflow counter (shows total number of interrupts)
  IntCount++;                         //increment interrupt counter

  //adjust Output211 and Output531 counters
  Output211Count++;
  if (Output211Count>=4739) {
    Output211Count = 0;
    digitalWriteFast(21, 1);
  }
  if (Output211Count>=Output211Control) {
    digitalWriteFast(21, 0);
  }
  Output531Count++;
  if (Output531Count>=1883) {
    Output531Count = 0;
    digitalWriteFast(22, 1);
  }
  if (Output531Count>=Output531Control) {
    digitalWriteFast(22, 0);
  }

  //test for reset of interrupt counter (and update Secs, milliSecs)
  if (IntCount>=1000) {               //max value (999)
    IntCount = 0;                     //reset interrupt counter
    MilliSecs++;                      //increment MilliSecs
    if (MilliSecs>=1000) {            //MilliSecs has reached max value
      Secs++;                         //increment Secs
      MilliSecs = 0;                  //reset MilliSecs counter
    }
  }

  //ISR end timing
  digitalWriteFast(20, 0);            //set pin 20 low
}

//Main Program Loop
//-----------------
void loop() {
  //read key input (if any)
  KeyInput();                         //read key input (if any)

  //update loop counter
  LoopCount++;
  
  //display data on each new second
  if (Secs!=DispSecs) {               //check for Secs update to display data
    DispSecs = Secs;
    CopyData();                       //freeze a copy in case data changes before being displayed
    if (DisplayOn) {
      DisplayData();                  //display data in serial monitor
    }
    Blink();
  }  
} //end of main loop


//SUBROUTINES
//===========

//Blink Routine
void Blink() {
  //blink the LED
  LED_ON;
  delay(10);
  LED_OFF;
  delay(10);
}

//Copy Data Routine
void CopyData() {
  dIntCount = IntCount;
  dFTM1CountOVFlow = FTM1CountOVFlow;
  dLoopCount = LoopCount;
}

//Display Routine
void DisplayData() {
  //print to serial monitor
  Serial.print("Secs ");
  Serial.print(Secs);
  Serial.print(", OVC = ");
  Serial.print(dFTM1CountOVFlow);
  Serial.print(", LC = ");
  Serial.print(dLoopCount);
  Serial.println();
  Blink();
}

//KeyInput Routine
void KeyInput() {
  //blink the LED
  if (Serial.available()>0) {
    //read the incoming byte
    Byte1 = Serial.read();
    if (Byte1>0x40) {
      switch (Byte1) {
      case 'q':  //q - set duty cycle on period for 211 Hz in microSecs
        //task goes here...
        if (Serial.available()>=4) {    //watch out for CRLF chars included
          Byte2 = Serial.read();
          Byte3 = Serial.read();
          Byte4 = Serial.read();
          Byte5 = Serial.read();
          Output211Control = ((Byte2-48)*1000) + ((Byte3-48)*100) + ((Byte4-48)*10) + (Byte5-48);
          if (Output211Control>4739) {Output211Control = 4739;}
        }
        Serial.print("211 Hz on period (uSecs) = "); Serial.println(Output211Control);
        Blink();
        break;
      case 'a':  //a - set duty cycle on period for 531 Hz in microSecs
        //task goes here...
        if (Serial.available()>=4) {    //watch out for CRLF chars included
          Byte2 = Serial.read();
          Byte3 = Serial.read();
          Byte4 = Serial.read();
          Byte5 = Serial.read();
          Output531Control = ((Byte2-48)*1000) + ((Byte3-48)*100) + ((Byte4-48)*10) + (Byte5-48);
          if (Output531Control>1882) {Output531Control = 1882;}
        }
        Serial.print("531 Hz on period (uSecs) = "); Serial.println(Output531Control);
        Blink();
        break;
      } //end of switch statement
     } //end of Byte1>0x40
  } //end of if Serial Available
}
 
Last edited:
Curious about the "losing 50%" comment... Do you mean that the LEDs take time to respond, so cannot react to the leading edge? Or do you mean that a sq wave is at 0 volts for half the time? If the latter, then add a "DC component" to the square wave to offset it positive (op amp and pot), and then feed this signal into the same input as the sinewave would go. However, can't see that this will help the FFT any.

(Thinking aloud... you could also use the ISR to modulate the DAC outputs directly going between two "fixed values - full and half", rather than use digital output pins. If you really want to get sexy, you could use the ISR to look up an array which converted to sine - if you really feel that its necessary - I'm not convinced).
 
Last edited:
A perfect square wave input to the LED results in some delayed optical output.

How do you know whether the delay and rise time is due to the LED, or whatever optical sensor & measurement technique you're using?

Regarding the LED side, are you measuring the actual LED current (or voltage across a resistor in series with the LED)? The type of circuit driving the LED could have an effect. If you only measure the signal from Teensy and not the LED current, you might not be giving yourself a clear idea of the real LED drive.

LEDs (and diodes in general) tend to have wide bandwidth when forward biased. But many optical sensors, especially resistive materials and photosensitive transistors, are notorious for slow response times.
 
How do you know whether the delay and rise time is due to the LED, or whatever optical sensor & measurement technique you're using?

Regarding the LED side, are you measuring the actual LED current (or voltage across a resistor in series with the LED)? The type of circuit driving the LED could have an effect. If you only measure the signal from Teensy and not the LED current, you might not be giving yourself a clear idea of the real LED drive.

LEDs (and diodes in general) tend to have wide bandwidth when forward biased. But many optical sensors, especially resistive materials and photosensitive transistors, are notorious for slow response times.

I am using a Thorlabs DET10A Si photodetector with reported 1 ns rise time. I trust the timing of this device; using it to measure output with optical mechanical shutters (near perfect on/off timing) is well detected.

An interesting point about measuring the LED current. Thus far I have only been looking at the output of the Teensy and comparing that against the optical output. I would expect that there could be a delay/phase shift (I am OK with that), but no change in the waveform of the signal. But I guess I don't know that for sure.
 
Curious about the "losing 50%" comment...

I mean that the LEDs take time to respond. In Optogenetics, you must think about applying an optical power for a set time to activate a set percentage of Opsins (light activated proteins). Often the researchers report this power incorrectly because they measure the power at 100% duty cycle and assume that the power is the same when they pulse the LEDs. But in looking at the optical power (as measured with a fast response Photodetector), you can see that the LED might not reach it's 100% power over the pulse, and even if it does, the delay results in less power than a perfect system. This can be overcome with fancy lasers or mechanical shutter systems.

20171012_091919.jpg
 
My vote goes with WMXZ... if you lose 50% at 531 Hz (your original post - not 511 Hz), then you cannot guarantee that a sinewave is going to be any more predictable than a square wave. In fact a square wave has probably more predictable performance. The ability to vary the input linearly (which you can do with a sq wave) and see how the output behaves, will tell you more than varying the amplitude of a sinewave.

There is a delay in the optical output of the sine waves, but they are highly predictable. 531 Hz (sorry for the slip with 511!) and 211 Hz pictured. Channel 1 (yellow) is a sinusoide from a function generator driving the LED Driver. Channel 2 (blue) is the optical output as measured with a DET10A photodetector:
20171011_131420.jpg20171011_131511.jpg

As an academic exercise, I decided to code for 211 Hz and 531 Hz square waves - just to see how hard it would be. There are a few ways how this might be done but I decided in the end to use just one FTM timer (FTM1). I would be interested to hear any other suggestions.

Amazing! This will take me time to digest/understand (may never happen).

Because the optical output is not a perfect square, the FFT spectrum is complex. It might be possible to measure this before a trial and assume it doesn't change during a trial (an OK assumption). (Kind of like a calibration file). You could then demodulate the fluorescent signal with the optical output FFT spectrum (calibration file). But, because of how the optics flow through the system, you cannot simply measure the output FFT (even with a mirror as I previously hinted). You need something that fluoresces (and that must be near instantaneous). I am not sure if this is a thing, I'm going to check with my microscope experts.
 
Thanks for taking the trouble to record your scope pictures. They help enormously for comprehension. Yes, I can appreciate why you are nervous about using pulses rather than sine waves. That said, it is difficult to know if the FFT analysis would be better or worse (at this time). You might be surprised.

If you want to play safe and stick with sine waves, then Frank's #4 and #11 suggestion of Audiolib is a good avenue to explore. I'm not familiar with using this library. This may be able to level shift for you (??). Maybe others can help here.

Just an interesting note from your pictures... Your input is CH2 not CH1 (CH1 lags CH2). Which means that for your 212 Hz wave, the input is circa 150 mV pk-pk and output is 200 mV pk-pk (a gain through the opto system). But with the 555 Hz picture, both input and output are 750 mV pk-pk (no gain). This means that the system is frequency dependant - a low pass filter (higher freqs attenuated compared to lower). The exponential edges of the square wave confirm this. The cause of this is the LED driver product - the manual suggests the bandwidth to be 1 KHz for TTL input and 5 KHz for the sine input. I found this odd when I read it - would have expected TTL to be better or at least the same.

You may wish to come back to pulsing in the future. As you correctly point out, the power level is reduced by the modulation. Total energy is instant power integrated over time. So pulses may not be a problem after all - and starting LED emission and stopping might be easier with pulses - this could act as your "shutter" mechanism (and maybe easier to calculate total energy?).

When you do the FFT analysis, that will tell you more about your system design and its "fitness for purpose". Frequency stability will be important to get clean spectral lines, and the width of the frequency bins will be another factor. Too wide and they may blur the results - and if the frequency stability is too "shaky" that too will blur as "spectral spread" of the peaks (less contrast between the two LED signals).
 
Last edited:
Status
Not open for further replies.
Back
Top