Categories
Projects

DNA origami split-ring resonator

I started writing this post in 2018, shortly following a class I took on nanofabrication. The class focused on two methods of nanofabrication: e-beam lithography and DNA origami. I originally intended on writing a detailed introduction to DNA origami, but I don’t think I remember enough to do that now. Instead, I’ll briefly describe DNA origami and then show the results of our attempts to fabricate a split ring resonator as a class project.

Brief introduction to DNA origami

In 2006, Paul Rothemund published a paper in which he combined the art of paper folding with DNA. A DNA molecule is a double-stranded helix. Each strand is a chain of four repeating molecules — cytosine, guanine, adenine, and thymine (C, G, A, and T, respectively). Cytosine and guanine are complements and so are adenine and thymine. A single-stranded DNA can bond to a complimentary chain. For example, the chain represented by the sequence GTCTA can bond to CAGAT, but not any other sequence. In this way, a long single-strand of DNA (derived from a bacteriophage) with it’s known base-pair sequence can be folded by selectively targeting two parts of the strand with a separate “staple” strand. Half the staple strand targets part of the longer strand while the other half targets a different part. This can be used to create (nearly) arbitrary shapes in both two and three dimensions. For a better overview of DNA origami, read this Wikipedia article, or better yet, the original paper I cited earlier.

Split-ring resonator

I’ll leave most of the details of split-ring resonators to the Wikipedia article. Essentially, a split-ring resonator is a LC circuit that resonates at a frequency defined by its geometry.

Split-ring resonator schematics. (Left) Geometric source of inductance and capacitance. (Right) The closest approximation we could make by folding DNA.

DNA origami is limited in several ways, most notably by the requirement of continuity for the long single-strand of DNA. For the split-ring resonator, we needed a way for the strand to cover the entire structure without it ever looping back on itself. We used a tool called cadnano to design the DNA implementation of the split-ring resonator. In the figure below, you can see the long single-strand represented by the blue line that starts in the top left corner and snakes its way across the structure. Staple strands (smaller lines of various colors) are placed where necessary to bind the structure together.

Image from cadnano showing the long DNA strand (light blue) held together by the shorter staple strands (various colors). From this design, we ordered the necessary staple strands.

The cadnano software is able to export the base-pair sequence information necessary to order the staple strands from a commercial supplier. With the necessary long-single strands and staple strands in hand (or rather, in solution), it is a relatively straightforward — albeit finicky — process of creating the DNA origami. The short of it is that the DNA is combined into a single solution, that solution undergoes polymerase chain reaction (PCR), the DNA combines/folds as it cools, and it is finally deposited on a silicon surface to evaporate so the structures can be analyzed.

I am amazed that this even works at all. The fabrication process is essentially random. It is like throwing a puzzle into a bucket, shaking it a bit, and expecting a nice picture to come out. Of course, the puzzle pieces are slightly attracted to where they are supposed to go, but they still have to bump into each other to stick.

DNA origami results

The main challenge with viewing the DNA origami is just that — viewing! How do you image something that is less than 100 nm square and about 2 nm thick? That is too small to resolve optically. We had two possible tools at our disposal: scanning electron microscopy (SEM) and atomic force microscopy (AFM). We were not able to get the necessary contrast with SEM, which required a conductive material be deposited on top of the sample. However, AFM did not require any preprocessing, since the sample was already on a flat silicon chip.

Two fully formed DNA origami split-ring resonator structures. Notice that even with these best examples, the structures are misshapen.
Several recognizable but malformed DNA origami split-ring resonator structures.
Most structures were partially formed and clumped in an unusable mess.

We were able to claim partial success in creating a DNA origami split-ring resonator. The DNA origami part worked about as well as can be expected. The split-ring resonators would also need to be metalized and arrange in an appropriately spaced array (both of which were out of the scope of the class). However, as you can see by the images above, the DNA origami did not maintain the required geometry. There are a couple reasons for this, but the main problem is that DNA is floppy. The DNA origami structure did not have enough rigidity to maintain the desired shape. This structure was great for learning about DNA origami, but would never have made a good split-ring resonator.

You can do this at home

I’m not even joking. You really can do this at home! You can download cadnano, design a structure, order the staple strands and chemicals, cook them for PCR, and deposit the solution on a substrate for $100 to $200. After taking the class on nanofabrication, I really wanted to try this at home until I realized I would not have any way of determining whether the DNA folded correctly. So, before I try DNA origami in my kitchen, I will first need to build an atomic force microscope.

Categories
Tips

Quick tip: Publication worthy graphics with Mathematica

I am a huge fan of Mathematica for prototyping and quick one-offs. Most of the heavy lift analysis I do is with MATLAB or python, but sometimes I produce a graphic in Mathematica that I want to include in a publication. Here are a few tips on getting your Mathematica figures to look a little bit better.

I will use a sine wave with arbitrary labels as the example. A default labeled plot looks like this:

default = Plot[
  Sin[x],
  {x, 0, 2 \[Pi]},
  PlotLabel -> "Sine wave",
  AxesLabel -> {"Horiz. (unit)", "Vert. (unit)"}
]
Export["default.png", default]
Default formatted plot.

There are a few things I don’t like about this. First, the resolution is too low. Mathematica defaults to an image resolution of 72 dpi (dots per inch). Second, I want the text/axes to be black, not gray. Third, I think the labels for the axes should be to the left and below the figure, not at the positive ends of the axes. And finally, I would like for the horizontal axis to run along the bottom of the figure (and for the entire figure to be encapsulated in a frame).

Resolution

Both Plot and Export take the optional argument ImageSize. If we know the resolution of the image (which defaults to 72 dpi), we can use ImageSize to set the image to a specific width in inches. Here is the same figure resized to 3.2 inches (“ImageSize -> 3.2*72“):

res1 = Plot[
  Sin[x],
  {x, 0, 2 \[Pi]},
  PlotLabel -> "Sine wave",
  AxesLabel -> {"Horiz. (unit)", "Vert. (unit)"},
  ImageSize -> 3.2*72
]
Export["res1.png", res1]
Default plot with custom size. The print resolution is 72 dpi.

To increase the resolution of the image, we can use ImageResolution in Export. Plot does not take ImageResolution, so I tend to put ImageSize and ImageResolution in Export. This has the added benefit of not making the plots in Mathematica very large (since it still uses either 72 dpi or the screen dpi for display).

default = Plot[
  Sin[x],
  {x, 0, 2 \[Pi]},
  PlotLabel -> "Sine wave",
  AxesLabel -> {"Horiz. (unit)", "Vert. (unit)"}
]
Export["res2.png", default, ImageSize -> 3.2*300, 
 ImageResolution -> 300]
Default plot that should be 3.2″ wide and print at 300 dpi. Mathematica has a bug where scaling doesn’t work properly.

Well, that doesn’t look good! Unfortunately, there is a bug in how the PNG (and TIFF, and possibly other) exporters work. The axes/ticks don’t scale with image resolution. This is a known bug. One suggested solution is to export the plot as a PDF using ExportString and then immediately import it with ImportString. [Future me: The following may be the most important tip in this post.] I have found that including a PlotLegends will cause the scaling to work fine, even if the legend is not visible. I will typically do something like PlotLegends -> Placed["", {Right, Top}]. Using Placed makes the legend appear inside the frame, so that the width of the figure doesn’t change.

default2 = Plot[
  Sin[x],
  {x, 0, 2 \[Pi]},
  PlotLabel -> "Sine wave",
  AxesLabel -> {"Horiz. (unit)", "Vert. (unit)"},
  PlotLegends -> Placed["", {Right, Top}]
]
Export[res3.png", default2, ImageSize -> 3.2*300, 
 ImageResolution -> 300]
Fixed scaling by using an empty PlotLegends. Click for full resolution image.

(Please note, that for these larger resolution images I am artificially restricting their display size to be the same as the original 72 dpi image, which I’ve increased to be close to 3.2 inches on my display. This is because I want them all to be 3.2 inches in print, but on a screen DPI doesn’t mean anything. In fact, I don’t even think PNG files keep track of DPI. When actually exporting for a journal/publication, I recommend using TIFF or EPS. With a vector format, you don’t even need to worry about all this ImageResolution nonsense. You can see the full resolution images by opening them in a new tab or saving them.)

Black text, labels, and frame

Thankfully, we can fix my remaining three complaints by turning off the axes and using a frame (Axes -> False and Frame -> True). I use BaseStyle to set the default font size for both the axes labels and the tick labels. FrameLabel sets the labels for all four sides of the frame in the order bottom, left, top, right. FrameStyle is used to set the frame to be black (which prints much better than the default gray).

frame =
 Plot[
  Sin[x],
  {x, 0, 2 \[Pi]},
  BaseStyle -> {FontSize -> 12},
  PlotLegends -> Placed["", {Left, Top}],
  FrameLabel -> {"Horiz. (unit)", "Vert. (unit)", 
    Style["Sine wave", 16], None},
  Axes -> False,
  Frame -> True,
  FrameStyle -> Black
]
Export["frame1.png", frame, ImageSize -> 3.2*300, 
 ImageResolution -> 300]
Plot with a black frame, proper axis labels, and custom size/resolution. Click for full resolution image.

Bonus: Legends and color

I mentioned needing to use PlotLegends to get around a scaling bug. I also talked about Placed, but I’d like to say a bit more about that. By default, Mathematica places the legends outside of the frame. In most cases, this is not desirable. You can place the legends inside the frame with Placed[legends, {horiz. pos., vert. pos.}]. I used to get confused if I should say {Top, Right} or {Right, Top} until I realized the first was for horizontal positioning and the second was for vertical positioning. Also, please don’t use the default Mathematica colors in print.

frame2 =
 Plot[
  {Sin[x], Cos[x]},
  {x, 0, 2 \[Pi]},
  PlotStyle -> {Blue, Red},
  BaseStyle -> {FontSize -> 12},
  PlotLegends -> Placed[{"Sine", "Cosine"}, {Left, Bottom}],
  FrameLabel -> {"Horiz. (unit)", "Vert. (unit)"},
  Axes -> False,
  Frame -> True,
  FrameStyle -> Black
]
Export["frame2.png", frame2, ImageSize -> 3.2*300, 
 ImageResolution -> 300]
Added a legend and custom line colors, and removed the title. Click for full resolution image.

Do you have any Mathematica tips for making better figures? Please share them in a comment to this post. Thanks for reading!

Categories
Projects

Dead simple PPG

Photoplethysmography (PPG) uses light to detect small changes in blood volume and is most commonly used for measuring heart rate. It is possible to buy a PPG-in-a-package that is smaller than a pinky nail. The MAX30101 comes in at just 5.6 mm x 3.3 mm and it doesn’t just measure heart rate — it does pulse oximetry as well. What I demonstrate here isn’t nearly as small or as capable, but you can build it with parts from your junk bin.

Pulsatile signal from dead simple PPG. I’m alive!

This dead simple PPG needs just an LED, a light dependent resistor (LDR), two resistors, and a power supply. The LDR and one of the resistors make a voltage divider across the power rails (5 V in my case). The LED is powered from the same supply, with the final resistor acting to limit current. The resistor that forms the voltage divider with the LDR was chosen to be somewhere in the middle of the LDR’s resistance swing. I used an oscilloscope to view the pulse waveform, but a microcontroller with an ADC would do as well. The breadboarded circuit and schematic can be seen below.

Breadboard layout of circuit.
Circuit schematic of the dead simple PPG.

This design can be greatly improved — or scrapped and redesigned from scratch. A photoresistor is not the right sensor for the job. It isn’t as sensitive as a photodiode and its current consumption (at least in this circuit) isn’t anything to write home about. The best signal I measured with this setup was 15 mV (peak-to-peak). Some signal conditioning (amplification) before sample acquisition would be beneficial.

Despite the improvements that this simple design is desperately begging for, it demonstrates two things. First, I have a pulse. Second, anyone with 10 cents worth of components can measure their own pulse. (The oscilloscope is handy, but an Arduino would do in a pinch.) Hopefully, this project will inspire you to get started with (simple and safe) biohacking.

Categories
Projects

DIY Hot Wheels speedometer

My nephew’s birthday was coming up in a couple days and I wanted to build or (3D) print him something. He loves Hot Wheels, so I thought I’d make him a speedometer with a digital speed readout. I envisioned two LEDs illuminating two photoresistors. When the car speeds by it would block one photoresistor and then the other. Simple! Well, suddenly it was a year or two later and his birthday was coming up again. I don’t remember why I didn’t finish the project the first time, but now I was determined. (I think for that previous birthday I printed him a rocket, so I wasn’t a complete failure of an uncle.)

Speedometer schematic.
Speedometer circuit schematic. Each photoresistor forms a voltage divider so that the voltage the analog pin sees varies with light level.

The figure above shows the circuit schematic for the speedometer. I used an Arduino Nano, a 9 V battery, two cadmium sulfide photoresistors, two 220 Ω resistors for the voltage divider, two 5 mm white LEDs, two current limiting 450 Ω resistors, an 8×32 LED display with MAX7219, and a 4 cm x 6 cm perfboard. A switch was added later. Most of the connections were made with 2- and 3-pin JST connectors as opposed to direct soldering, since this is still pretty much a prototype. You can see the assembled board in the figure below. Sorry, I didn’t take any underside photos.

Pre-enclosure photo of the assembled speedometer. I added a switch later, after an embarrassing “duh” moment.

I designed a very simple enclosure for the electronics. The important part is the separation of the light/photoresistor pairs. In my model this distance is 100 mm. I didn’t have time to come up with a secure latching mechanism for the lid (because I only had time to print it once). My choice of small posts, each with a bump, seemed OK in theory, but were much to small. Within the first week my nephew dropped the device onto carpet and all the posts broke. While I’m working on an updated model, the lid is being held in place with clear tape. Also, the part that holds the perfboard in the original model was made slightly longer than it should have been. The board still fits, but barely. You can download the STL here. Hopefully, I’ll update this post when I fix the design.

The assembled speedometer. I didn’t do a great job organizing the inside, but everything fits. The switch and Dupont header on the display touch, so the switch should really be moved.
The speedometer in action!

The Arduino code for the speedometer is below. It is adapted from an example in the MD_MAX72XX Arduino library (github), which you will need to compile the sketch. It is very basic. It simply finds a moving average for the ADC values associated with each photoresistor voltage divider, and triggers the next state when the instantaneous ADC value goes above two times the average. The speed in inches per second is found by dividing the length (3.9 inches) by the time between triggering the two photoresistors. This is sent to the display using the logic from the MD_MAX72XX example.

To summarize this project: it’s ugly, but it works!

// Code modified from the MD_MAX72XX example to display text from serial.
// Hot Wheels Speedometer
// kylelarsen.com

#include <MD_MAX72xx.h>
#include <SPI.h>

#define PRINT(s, v) { Serial.print(F(s)); Serial.print(v); }

// Define the number of devices we have in the chain and the hardware interface
// NOTE: These pin numbers will probably not work with your hardware and may
// need to be adapted
#define HARDWARE_TYPE MD_MAX72XX::FC16_HW
#define MAX_DEVICES 4

#define CLK_PIN   13  // or SCK
#define DATA_PIN  11  // or MOSI
#define CS_PIN    10  // or SS

// SPI hardware interface
MD_MAX72XX mx = MD_MAX72XX(HARDWARE_TYPE, CS_PIN, MAX_DEVICES);

// Text parameters
#define CHAR_SPACING  1 // pixels between characters

// Global message buffers shared by Serial and Scrolling functions
#define BUF_SIZE  75
char message[BUF_SIZE] = "Ready!";
bool newMessageAvailable = true;

// Distance between sensors
// LDR = Light dependent resistor

// Distance between LDRs
float ldr_dist = 3.937; // inches

int ldrA_pin = A3;
int ldrB_pin = A0;

// ADC values
unsigned int ldrA = 0;
unsigned int ldrB = 0;

// Last time LDR was triggered
unsigned long ldrA_time = 0;
unsigned long ldrB_time = 0;

// Number of points to average for baseline. Cannot go too high because of limited memory
const int     ldr_avg_num = 128;
// TO DO: Am I going to use this array for anything besides average?
unsigned long ldrA_avg_arr[ldr_avg_num];
unsigned long ldrB_avg_arr[ldr_avg_num];
unsigned long ldrA_avg    = 0;
unsigned long ldrB_avg    = 0;
unsigned int  ldr_avg_idx = 0;

// Simple state machine.
//  WAIT_A - waiting for the car to pass the first LDR
//  WAIT_B - waiting for the car to pass the second LDR
enum Status {WAIT_A, WAIT_B};
Status status = WAIT_A;

void printText(uint8_t modStart, uint8_t modEnd, char *pMsg);

void setup()
{
  mx.begin();
  mx.control(MD_MAX72XX::INTENSITY, 1);

  Serial.begin(57600);  
}

void loop()
{
  if (newMessageAvailable)
  {
    // Send message to display
    printText(0, MAX_DEVICES-1, message);
    newMessageAvailable = false;
  }

  // Read the values for the LDRs
  ldrA = analogRead(ldrA_pin);
  ldrB = analogRead(ldrB_pin);

  // Add to rolling average array
  ldrA_avg_arr[ldr_avg_idx] = ldrA;
  ldrB_avg_arr[ldr_avg_idx] = ldrB;

  ldr_avg_idx++;

  if (ldr_avg_idx >= ldr_avg_num)
  {
    ldr_avg_idx = 0;
  }

  // Do the rolling average
  int i;
  ldrA_avg = 0;
  ldrB_avg = 0;
  for (i = 0; i < ldr_avg_num; i++)
  {
    // If we reach a value that is exactly 0 then the ldrN_avg_arr hasn't filled up yet.
    if (ldrA_avg_arr[i] == 0 || ldrB_avg_arr[i] == 0)
    {
      break;
    }
    
    ldrA_avg += ldrA_avg_arr[i];
    ldrB_avg += ldrB_avg_arr[i];
  }

  ldrA_avg /= i; // ldr_avg_num;
  ldrB_avg /= i; // ldr_avg_num;

  // The trigger threshold is two times the average
  if (status == WAIT_A && ldrA > 2*ldrA_avg) {
    ldrA_time = millis();
    status = WAIT_B;
  }

  // Again, the trigger threshold is two times the average,
  // but the car must have already passed the first LDR.
  if (status == WAIT_B && ldrB > 2*ldrB_avg) {
    ldrB_time = millis();

    float dt = ((float)(ldrB_time - ldrA_time) / 1000 ); // seconds

    // Speed = Distance / time    
    sprintf(message, "%d in/s", (int)(ldr_dist / dt));
    newMessageAvailable = true;
    
    status = WAIT_A;
  }

  // Ten second timeout
  if (status == WAIT_B && (millis() - ldrA_time) > 10000)
  {
    status = WAIT_A;
    ldrA_time = 0;
  }

  // View with arduino or other plotter
  Serial.print(ldrA);
  Serial.print(",");
  Serial.print(ldrB);
  Serial.print(",");
  Serial.print(ldrA_avg);
  Serial.print(",");
  Serial.print(ldrB_avg);
  Serial.print("\n");
  
  
  delay(5);
  
}


void printText(uint8_t modStart, uint8_t modEnd, char *pMsg)
// Print the text string to the LED matrix modules specified.
// Message area is padded with blank columns after printing.
{
  uint8_t   state = 0;
  uint8_t   curLen;
  uint16_t  showLen;
  uint8_t   cBuf[8];
  int16_t   col = ((modEnd + 1) * COL_SIZE) - 1;

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::OFF);

  do     // finite state machine to print the characters in the space available
  {
    switch(state)
    {
      case 0: // Load the next character from the font table
        // if we reached end of message, reset the message pointer
        if (*pMsg == '\0')
        {
          showLen = col - (modEnd * COL_SIZE);  // padding characters
          state = 2;
          break;
        }

        // retrieve the next character form the font file
        showLen = mx.getChar(*pMsg++, sizeof(cBuf)/sizeof(cBuf[0]), cBuf);
        curLen = 0;
        state++;
        // !! deliberately fall through to next state to start displaying

      case 1: // display the next part of the character
        mx.setColumn(col--, cBuf[curLen++]);

        // done with font character, now display the space between chars
        if (curLen == showLen)
        {
          showLen = CHAR_SPACING;
          state = 2;
        }
        break;

      case 2: // initialize state for displaying empty columns
        curLen = 0;
        state++;
        // fall through

      case 3:  // display inter-character spacing or end of message padding (blank columns)
        mx.setColumn(col--, 0);
        curLen++;
        if (curLen == showLen)
          state = 0;
        break;

      default:
        col = -1;   // this definitely ends the do loop
    }
  } while (col >= (modStart * COL_SIZE));

  mx.control(modStart, modEnd, MD_MAX72XX::UPDATE, MD_MAX72XX::ON);
}

Categories
Projects

Sine wave line shading

TL;DR: Convert a bitmap image into an SVG with sine wave line shading. See the code here: https://github.com/0not/laser_tools/

I recently built a laser engraver/cutter with a 30 W diode laser module and an OpenBuilds ACRO positioning system. I wanted a way to engrave moderately detailed images without having to deal with the slow speed of raster engraving. I ran across a video of an Inkscape plugin that could convert an image into a series of sine waves. (I can’t find that video or plugin now, but I do remember the plugin was associated with a Russian site). The plugin could change the frequency and amplitude (and a few more things) along each sine wave in order to realize a brighter or darker area of the image. Here is my attempt at a similar technique, but with only altering the frequency. I used Python and a Jupyter notebook for this project.

The algorithm is fairly simple: take an image then group and average adjacent rows to achieve some target output number of lines; convert the intensity at each pixel along each row into a frequency; accumulate the phase of each row/line to generate the output sine wave; and finally, display and save the waves as a vector image.

(Left) Grayscale version of input image. (Right) Representation of row-averaged image with 32 rows. The intensity across each row will be converted to frequency.
Here is astronaut Eileen Collins line shaded with 32 sine waves. This output was saved as a PNG (not SVG), so some of the fidelity was lost. It is possible to get even more detail with more than 32 rows.

The trickiest part about this project was properly accounting for phase as the frequency of the sine wave is changed. Here’s an example of what we don’t want:

x  = np.linspace(0, 50, 1000)
y1 = np.sin(1.1*x[0:len(x)//2])
y2 = np.sin(3.0*x[len(x)//2:])
plt.plot(x, np.hstack((y1, y2)))

In this example, the first half of the wave is at one frequency and the second half is at another. At the halfway point, these two waves have different phases, so we get a sharp transition.

To fix this problem, we need to accumulate the phase so that at the transition it is correct. Here is an example that accomplishes this:

x   = np.linspace(0, 50, 1000)
fs  = len(x) / x[-1]
f1  = 1.1*np.ones(len(x)//2)
f2  = 3.0*np.ones(len(x)//2)
f   = np.hstack((f1, f2))
# ex: np.cumsum([1, 2, 3, 4]) = [1, 3, 6, 10]
phi = np.cumsum(f) / fs
plt.plot(x, np.sin(phi))

I used the cumulative summation function from numpy to accumulate the phase from the lists of the two frequencies. The phase needs to be dimensionless and to account for having more than one sample per frequency, I divide by the sample frequency.

Once each sine wave is built up, I stack them vertically with (hopefully) the correct spacing and export the plot as an SVG. Using any number of tools, the SVG can be converted into g-code. I have mostly been using LaserWeb and cam.openbuilds.com.

Here is the first image I actually “engraved” on cardboard. The power was a bit too high, but the image is still visible:

In the darker areas the top layer of cardboard was burned through, but most of the image turned out well.

Give the Jupyter notebook a try using mybinder.com. The code is hosted at github.com. The code is useable, but hardly more than a proof-of-concept. Feel free to make something of it. Go wild!

A higher fidelity baboon than is in the example images.

Categories
Projects

Easy spectroscope

In 2018 I posted a design of a simple spectroscope to Thingiverse. I figure I’ll re-post it here to try and reach a wider audience. This project was inspired by the Nanomaker course on MIT OpenCourseWare.

Spectrum of fluorescent light
Spectrum of fluorescent light.

Summary

This project will teach you how to build a simple DIY spectroscope with an old CD, an empty paper towel roll, and (optionally) a 3D printer. Print the two different end caps, glue or tape the diffraction grating (part of an old CD with the metallic top layer removed) into the cap with the larger hole, and place both caps on the end of the paper towel roll. If you don’t have a 3D printer, you can use cardboard (e.g. from a cereal box) or thick cardstock. Cut slits similar to those of the 3D printed end caps.

Look through the end with the larger hole and the CD diffraction grating at different light sources to see their spectra.

Download the files from Thingiverse or here.

Materials

  • Empty paper towel roll.
  • Old, unwanted CD-ROM.
  • Glue or tape.
  • Scissors.
  • (Optional) 3D printer.
  • (Optional) If you can’t 3D print the end caps, use cardboard or dark and thick cardstock to create them.

Tips/Build steps

  • It might be tempting, but please don’t look directly at the sun, even through the spectroscope.
  • Pick a CD you don’t want anymore 😉
  • Use sharp scissors to cut out a portion of an old CD.
  • Tape (like duct tape) can help peel off the top metallic layer from the CD. Just stick the tape to the top surface and peel up.
  • The radial direction of the CD (the direction from the center of the CD to the edge) should be oriented parallel to the long dimension of the filter hole.
  • The two end caps should be rotated so that the two rectangles are perpendicular.
  • The previous two tips are to ensure that the diffraction pattern (the rainbow) is most visible. See the image of the diffraction pattern for an example of what the spectrum of a fluorescent light can look like.
  • Double-sided tape can be used to affix the CD to the end cap temporarily while adjustments are made.

Don’t have a 3D printer? Don’t worry — use cardboard for the end caps! The slit should be no more than about 0.5 mm wide. The other end cap doesn’t matter so much, just make a window for your diffraction grating/CD.

For bonus points, add a webcam and turn this into an easy spectrometer. (The difference between a -scope and a -meter is that a -scope just sees things whereas a -meter can measure things.)

Background information

With a spectroscope you can view the individual colors from a light source. The diffraction grating works like a prism in that it separates out these individual colors. The pattern caused by this separation is called a spectrum (plural spectra). The purpose of the slit is to help in distinguishing components of the spectrum. Try holding the diffraction grating up to your eye as you look at a room light. You’ll notice that without the slit, the diffraction patterns look like a rainbow version of the light source. What we want to see is just a series of lines corresponding to the colors in the light or a continuous rainbow if the light contains all colors. Different light sources have different spectra. The sun is considered white light — it contains all colors. Rainbows are the spectrum of the sun. Incandescent light bulbs also produce white light. You can see this continuous spectrum by looking through the spectroscope at an incandescent light bulb. Other light sources, like LEDs or fluorescent light bulbs, produce light that is missing some colors (or, only contains certain colors). The spectra of such light sources are called discrete, meaning you see distinct lines of colors in the spectrum. The image I attached to this project shows the spectrum of a fluorescent light. I hope you learn something new with this simple CD-ROM paper towel roll spectroscope!