UV-vis Notebook Example

Al Fischer
Janaury 02, 2020

Download a Template on GitHub:

  1. Go to the link using Chrome or Firefox (not Safari or Internet Explorer/Edge).
  2. Right click and choose Save As.
  3. Make sure the name says lab1_uv-vis_template.ipynb and nothing else. If there is a .txt shown delete it.
  4. Save the file to your UV-vis lab notebook folder.
  5. Go to Jupyter Lab, browse for the file within Jupyter Lab, and double click it to open it.

Introduction

Insert your introduction here.

Write a short paragraph about the purpose of the lab, the technique(s) you're using, the samples you're analyzing, and any additional background information you can think of that will help frame the purpose of the lab. At minimum you should include and overview (not detail) of:

  • What the sample is
  • The technique(s) you are using

Materials and Methods

Fill in all of the exact details necessary for you to repeat the study without any additional resources.

Much of this section should be filled in during lab!

Materials

  • A stock solution of 104.9 ppm quinine (from quinine sulfate - Fisher Lot No. 563887) in 0.05 M sulfuric acid was used to create the standards.
  • A second solution of 103.6 ppm quinine (from quinine sulfate - Sigma Batch No. 010K0895) in 0.05 M sulfuric acid was used to create the standards.
  • Double distilled sulfuric acid was used to create the 0.05 M sulfic acid solution.
  • All blanks were composed of 0.05 M sulfuric acid in ultrapure water.

Sample Preparation

  1. Store-bought tonic water was degassed by leaving the bottle open overnight.
  2. An aliquot of the tonic was placed undiluted in a 1-cm plastic cuvette for analysis using a plastic transfer pipette.

Standard & QC Preparation

Standards

  1. A 20 mL volumetric pipette was used to deliver 20.00 $\pm$ 0.03 mL of the first stock solution to a 25 mL volumetric flask.
  2. The solution was brought to volume using 0.05 M sulfuric acid. This is the High Standard. (Total volume 25 $\pm$ 0.06 mL)
  3. A 1:2.5 dilution was performed by using a 10 mL volumetric pipette was used to deliver 10.00 $\pm$ 0.02 mL of the high standard into a 25 mL volumetric flask and brought to volume using 0.05 M sulfuric acid. This is the Medium Standard.
  4. A 1:2.5 dilution was performed by using a 10 mL volumetric pipette was used to deliver 10.00 $\pm$ 0.02 mL of the medium standard into a 25 mL volumetric flask and brought to volume using 0.05 M sulfuric acid. This is the Low Standard.

Quality Control

  1. A QC was prepared by diluting 10.00 $\pm$ 0.02 mL of the second stock solution into 50.00 $\pm$ 0.05 mL 0.05 M sulfuric acid.

Standard and QC concentrations are shown below to following chunk.


In [112]:
###### Load function #################################################################
## Leave the function alone 
function concentrations = serialDilution(stock, pipettes, flasks)
    concentrations =[];
    for i = 1:length(pipettes)
        if i == 1
            concentrations(i) = stock * pipettes(i)/flasks(i);  # calculate first dilution
        else
            concentrations(i) = concentrations(i-1) * pipettes(i)/flasks(i); # calculate all other dilutions
        end
    end
    concentrations = flip(concentrations)'; # reverse the vector from lowest to highest and transpose to column vector
end
########################################################################################

In [113]:
####### Use function - insert standard info here #######################################
concentrations = serialDilution(104.9, [20 10 10], [25 25 25]); # conc in ppm, volume of pipettes in ml, vol of flasks in ml 

disp("Standard Concentrations (in ppm) = ");
output_precision(4); # only display 4 significant digits
disp(concentrations);

######## Insert QC Info Here ############################################################
qc_stock   = 100.6;  # units: ppm, insert concentration of the stock soln. used for QC
qc_pipette = 10;     # units: ml
qc_flask   = 50;     # units: ml (must be same length and units as 'qc_pipette')
########################################################################################

qc_conc    = qc_pipette / qc_flask * qc_stock;
disp("QC Concentration (in ppm) = ");
output_precision(4); # only display 4 significant digits
disp(qc_conc);


Standard Concentrations (in ppm) = 
   13.43
   33.57
   83.92
QC Concentration (in ppm) = 
 20.12

Instrumentation

Samples were analyzed with a Vernier SpectroVis in fluorescence mode. Table 2 shows complete instrument parameters.

Students: Fill in the instrument settings table. Look up the values on the Vernier website.

Table 2: Instrument Settings
Parameter Value
Make & Model Vernier SpectroVis
Source (fluorescence)
Optical Resolution
Wavelength Range
Data Acquisition Software

Methods

  1. A Vernier SpectroVis was placed in fluorescence mode (405nm excitation).
  2. The instrument was calibrated using the blank solution and a plastic 1-cm cuvette.
  3. Each standard or unknown was transferred to the cuvette using a plastic transfer pipette.
  4. Standards were run from lowest concentration to highest concentration, and the cuvette was rinsed with deionized water between each sample/standard. The blank, QC, and sample were run in triplicate by discarding the cuvette contents, rinsing the cuvette, and refilling with a new aliquote of sample.

Results and Data Analysis

Pre-processing

Data were saved in CSV files. The columns alternate wavelength, intensity_1, wavelength, intensity_2, ..., and so on.

Note to students: you can view the full data file by double clicking it in the Jupyter file browser.


In [114]:
#### Import the data
X = csvread('data/20200102_tonic_fluorescence.csv'); ## import data
X(1:2, :) ## print to screen to make sure data imported OK (optional)


ans =

 Columns 1 through 7:

     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000
   380.8000     0.0530   380.8000     0.0588   380.8000     0.0576   380.8000

 Columns 8 through 14:

     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000
     0.0552   380.8000     0.0589   380.8000     0.0546   380.8000     0.0316

 Columns 15 through 21:

     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000     0.0000
   380.8000     0.0307   380.8000     0.0300   380.8000     0.0176   380.8000

 Columns 22 through 24:

     0.0000     0.0000     0.0000
     0.0180   380.8000     0.0149

The data imported correctly, but could use some cleaning up. The first step will be to remove the duplicate wavelength columns.


In [115]:
wavelengths = X(:, 1); ## extract wavelength column to it's own vector
X = X(:, 2:2:end); ## extract even columns (intensity columns) and discard wavelength columns
X(1:2, :) ## print to screen to make sure clean up worked as expected (optional)


ans =

 Columns 1 through 8:

   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000   0.00000
   0.05305   0.05879   0.05765   0.05523   0.05893   0.05465   0.03160   0.03067

 Columns 9 through 12:

   0.00000   0.00000   0.00000   0.00000
   0.03005   0.01761   0.01805   0.01489

Looks better. The columns are:

  1. Blank-1
  2. Blank-2
  3. Blank-3
  4. Low Std
  5. Med Std
  6. High Std
  7. QC-1
  8. QC-2
  9. QC-3
  10. Sample 1-1
  11. Sample 1-2
  12. Sample 1-3

In [116]:
##### Plot the emission spectrum

plot(wavelengths, X(:, 5), 'DisplayName', 'Medium Standard');
xlabel('Wavelength (nm)');
ylabel('Intensity (arbitrary)');
xlim([380 700]); ylim([0 0.25]);
hold on
plot(wavelengths, X(:, 9), 'DisplayName', 'Tonic Water');
legend();
hold off

##### find max emission wavelength #######################
[max_values indices] = max(X(:, 5));
lambda_max = wavelengths(indices);
disp("Wavelength of maximum emission (in nm) = ");
output_precision(0); # only display to nearest nm
disp(lambda_max);


Wavelength of maximum emission (in nm) = 
  461

The peak emission, $\lambda_{e-max}$, for quinine occurs at 461 nm, so only this wavelength will be used for analysis. The expected maximum wavelength is 450 nm; the difference might indicate a significant miscalibration of the spectrophotometer. A wavelength standard will be needed to verify this.


In [117]:
disp("The intensities at the analytical wavelength are:")
intensity_values =  X(wavelengths == (lambda_max), :)


The intensities at the analytical wavelength are:
intensity_values =

 Columns 1 through 11:

   0.00   0.01   0.01   0.06   0.23   0.70   0.11   0.11   0.11   0.15   0.14

 Column 12:

   0.14


In [118]:
##### Define function to calculate linear fit and R2 ###############################
##### Leave this section alone

function [fit_params, r2, fitline] = fitlm(x, y)
    X = [ones(length(x), 1) x];
    fit_params = (pinv(X'*X))*X'*y;
    # watch this video to understand this code: https://www.youtube.com/watch?v=w2FKXOa0HGA
    ss_tot = sum((y - mean(y)).^2);
    ss_reg = sum(((X*fit_params) - mean(y)).^2);
    r2 = ss_reg/ss_tot;
    fitline = [x, X*fit_params];
end
#####################################################################################

In [119]:
standards = intensity_values(4:6) .- intensity_values(1); ## subtract blank reading

##### Plot Data

plot(concentrations', standards', '*', 'DisplayName', 'Experimental Data');
xlabel('Concentration (ppm)');
ylabel('Intensity (arbitrary)');

##### Calculate linear model / cal curve
[fit_params, r2, fitline] = fitlm(concentrations, standards');

##### Plot cal curve
hold on; % this keeps our previous plot of the training data visible
plot(fitline(:, 1), fitline(:, 2), 'b--', 'DisplayName', 'Linear regression')
legend('location', 'northwest')
hold off % Don't put any more plots on this figure

##### print values to screen
output_precision(4); # only display to 4 sf
disp("Slope =")
disp(fit_params(2))
disp("Intercept =")
disp(fit_params(1))
disp("R2 =")
disp(r2)


Slope =
 0.009120
Intercept =
-0.07149
R2 =
 0.9998

Determine Concentrations


In [120]:
###### Calculate concentration of samples & QC

samples_qc = intensity_values(7:12) .- mean(intensity_values(1:3)); ## subtract blank reading
concs = (samples_qc - fit_params(1))/fit_params(2);

In [121]:
###### Calculate mean QC value
mean_qc = mean(concs(1:3));
sd_qc = std(concs(1:3));
qc_percent_diff = (mean_qc - qc_conc)/qc_conc*100;

disp("Avearge  [Quinine] in QC (in ppm) = ");
disp(mean_qc);

disp("Expected [Quinine] in QC (in ppm) = ");
disp(qc_conc);

disp("QC Difference in percent = ");
disp(qc_percent_diff);

if qc_percent_diff < 5
    disp("QC PASS!")
else
    disp("QC FAIL!")
end


Avearge  [Quinine] in QC (in ppm) = 
 19.41
Expected [Quinine] in QC (in ppm) = 
 20.12
QC Difference in percent = 
-3.525
QC PASS!

The QC Passed at -3.525% difference.

Now, moving on to calculate sample concentrations.


In [122]:
###### Calculate mean sample values

mean_samples = mean(concs(4:6));
sd_samples = std(concs(4:6));

disp("Avearge  [Quinine] in sample (in ppm) = ");
disp(mean_samples);
disp("SD [Quinine] in sample(in ppm) = ");
disp(sd_samples);
disp("RSD [Quinine] in sample (in %) = ");
disp(sd_samples/mean_samples*100);


Avearge  [Quinine] in sample (in ppm) = 
 22.99
SD [Quinine] in sample(in ppm) = 
 0.08494
RSD [Quinine] in sample (in %) = 
 0.3694

Determine Limits of Detection and Quantitation

The limit of detection is defined as:

$$ LOD = \frac{3\sigma_{blank}}{m} $$

and the limit of quantitation is defined as:

$$ LOQ = \frac{10\sigma_{blank}}{m} $$

In [123]:
mean_blank = mean(intensity_values(1:3));
sd_blank   = std(intensity_values(1:3));

disp("Limits of Detection and Quantitation (in ppm) = ")
LOD = (3*sd_blank)/fit_params(2)
LOQ = (10*sd_blank)/fit_params(2)


Limits of Detection and Quantitation (in ppm) = 
LOD =  1.372
LOQ =  4.573

Conclusion

Insert your conclusion here. You should state what you found and whether or not the results seem accurate. Be sure to include the percent composition of your sample in the conclusion. Also discuss the polarity the compounds relative to each other.

References

[1] Lawson-Wood, Kathryn, and Kieran Evans. “Determination of Quinine in Tonic Water Using Fluorescence Spectroscopy,” (Application Note: Fluorescence Spectroscopy) Link