diff --git a/src/Channel.hpp b/src/Channel.hpp
index fccdf227..4166aa8b 100644
--- a/src/Channel.hpp
+++ b/src/Channel.hpp
@@ -25,9 +25,9 @@ class Channel
           const SizeType globalIndex,
           const float conversion = 1e6f,  // uV to V
           const float samplingRate = 30000.f,  // placeholder
-          const float bitVolts = 0.000002f,  // least significant bit needed to
-                                             // convert 16-bit int to volts
-                                             // currently a placeholder
+          const float bitVolts = 0.05f,  // least significant bit needed to
+                                         // convert 16-bit int to volts
+                                         // currently a placeholder
           const std::array<float, 3> position = {0.f, 0.f, 0.f},
           const std::string comments = "no comments");
 
diff --git a/src/Utils.hpp b/src/Utils.hpp
index b8a29231..8f2681f9 100644
--- a/src/Utils.hpp
+++ b/src/Utils.hpp
@@ -1,12 +1,16 @@
 #pragma once
 
+#include <algorithm>
 #include <chrono>
+#include <cmath>
+#include <cstdint>
 #include <ctime>
 #include <iomanip>
 #include <sstream>
 #include <string>
 
 #include <boost/date_time.hpp>
+#include <boost/endian/conversion.hpp>
 #include <boost/uuid/uuid.hpp>
 #include <boost/uuid/uuid_generators.hpp>
 #include <boost/uuid/uuid_io.hpp>
@@ -71,6 +75,40 @@ inline std::shared_ptr<IO::BaseIO> createIO(const std::string& type,
   }
 }
 
+/**
+ * @brief Method to convert float values to uint16 values. This method
+ * was adapted from JUCE AudioDataConverters using a default value of
+ * destBytesPerSample = 2.
+ * @param source The source float data to convert
+ * @param dest The destination for the converted uint16 data
+ * @param numSamples The number of samples to convert
+ */
+inline void convertFloatToInt16LE(const float* source,
+                                  void* dest,
+                                  int numSamples)
+{
+  // TODO - several steps in this function may be unnecessary for our use
+  // case. Consider simplifying the intermediate cast to char and the
+  // final cast to uint16_t.
+  auto maxVal = static_cast<double>(0x7fff);
+  auto intData = static_cast<char*>(dest);
+
+  for (int i = 0; i < numSamples; ++i) {
+    auto clampedValue = std::clamp(maxVal * source[i], -maxVal, maxVal);
+    auto intValue =
+        static_cast<uint16_t>(static_cast<int16_t>(std::round(clampedValue)));
+    intValue = boost::endian::native_to_little(intValue);
+    *reinterpret_cast<uint16_t*>(intData) = intValue;
+    intData += 2;  // destBytesPerSample is always 2
+  }
+}
+
+/**
+ * @brief Method to scale float values and convert to int16 values
+ * @param numSamples The number of samples to convert
+ * @param conversion_factor The conversion factor to scale the data
+ * @param data The data to convert
+ */
 inline std::unique_ptr<int16_t[]> transformToInt16(SizeType numSamples,
                                                    float conversion_factor,
                                                    const float* data)
@@ -86,12 +124,7 @@ inline std::unique_ptr<int16_t[]> transformToInt16(SizeType numSamples,
                  [multFactor](float value) { return value * multFactor; });
 
   // convert float to int16
-  std::transform(
-      scaledData.get(),
-      scaledData.get() + numSamples,
-      intData.get(),
-      [](float value)
-      { return static_cast<int16_t>(std::clamp(value, -32768.0f, 32767.0f)); });
+  convertFloatToInt16LE(scaledData.get(), intData.get(), numSamples);
 
   return intData;
 }
diff --git a/src/nwb/NWBFile.cpp b/src/nwb/NWBFile.cpp
index 9a39d399..974fdeb5 100644
--- a/src/nwb/NWBFile.cpp
+++ b/src/nwb/NWBFile.cpp
@@ -34,17 +34,26 @@ NWBFile::NWBFile(std::shared_ptr<IO::BaseIO> io)
 
 NWBFile::~NWBFile() {}
 
-Status NWBFile::initialize(const std::string& identifierText)
+Status NWBFile::initialize(const std::string& identifierText,
+                           const std::string& description,
+                           const std::string& dataCollection)
 {
   if (std::filesystem::exists(io->getFileName())) {
     return io->open(false);
   } else {
     io->open(true);
-    return createFileStructure(identifierText);
+    return createFileStructure(identifierText, description, dataCollection);
   }
 }
 
-Status NWBFile::createFileStructure(const std::string& identifierText)
+Status NWBFile::finalize()
+{
+  return io->close();
+}
+
+Status NWBFile::createFileStructure(const std::string& identifierText,
+                                    const std::string& description,
+                                    const std::string& dataCollection)
 {
   if (!io->canModifyObjects()) {
     return Status::Failure;
@@ -62,6 +71,9 @@ Status NWBFile::createFileStructure(const std::string& identifierText)
   io->createGroup("/general");
   io->createGroup("/general/devices");
   io->createGroup("/general/extracellular_ephys");
+  if (dataCollection != "") {
+    io->createStringDataSet("/general/data_collection", dataCollection);
+  }
 
   io->createGroup("/specifications");
   io->createReferenceAttribute("/specifications", "/", ".specloc");
@@ -78,7 +90,7 @@ Status NWBFile::createFileStructure(const std::string& identifierText)
   std::string time = getCurrentTime();
   std::vector<std::string> timeVec = {time};
   io->createStringDataSet("/file_create_date", timeVec);
-  io->createStringDataSet("/session_description", "a recording session");
+  io->createStringDataSet("/session_description", description);
   io->createStringDataSet("/session_start_time", time);
   io->createStringDataSet("/timestamps_reference_time", time);
   io->createStringDataSet("/identifier", identifierText);
@@ -86,11 +98,6 @@ Status NWBFile::createFileStructure(const std::string& identifierText)
   return Status::Success;
 }
 
-Status NWBFile::finalize()
-{
-  return io->close();
-}
-
 Status NWBFile::createElectricalSeries(
     std::vector<Types::ChannelVector> recordingArrays,
     const IO::BaseDataType& dataType,
diff --git a/src/nwb/NWBFile.hpp b/src/nwb/NWBFile.hpp
index 99f09447..0ab8c4af 100644
--- a/src/nwb/NWBFile.hpp
+++ b/src/nwb/NWBFile.hpp
@@ -51,9 +51,13 @@ class NWBFile : public Container
    * @brief Initializes the NWB file by opening and setting up the file
    * structure.
    *
-   *  @param identifierText The identifier text for the NWBFile.
+   * @param identifierText The identifier text for the NWBFile.
+   * @param description A description of the NWBFile session.
+   * @param dataCollection Information about the data collection methods.
    */
-  Status initialize(const std::string& identifierText);
+  Status initialize(const std::string& identifierText,
+                    const std::string& description = "a recording session",
+                    const std::string& dataCollection = "");
 
   /**
    * @brief Finalizes the NWB file by closing it.
@@ -88,11 +92,14 @@ class NWBFile : public Container
    * new objects cannot be added, which can be checked via
    * nwbfile.io->canModifyObjects()
    *
-   *  @param identifierText The identifier text for the NWBFile.
-   *
+   * @param identifierText The identifier text for the NWBFile.
+   * @param description A description of the NWBFile session.
+   * @param dataCollection Information about the data collection methods.
    * @return Status The status of the file structure creation.
    */
-  Status createFileStructure(const std::string& identifierText);
+  Status createFileStructure(const std::string& identifierText,
+                             const std::string& description,
+                             const std::string& dataCollection);
 
 private:
   /**
diff --git a/src/nwb/ecephys/ElectricalSeries.cpp b/src/nwb/ecephys/ElectricalSeries.cpp
index a32ae7d4..f0c690f1 100644
--- a/src/nwb/ecephys/ElectricalSeries.cpp
+++ b/src/nwb/ecephys/ElectricalSeries.cpp
@@ -38,9 +38,11 @@ void ElectricalSeries::initialize(const IO::BaseDataType& dataType,
                          offset);
 
   // setup variables based on number of channels
-  std::vector<SizeType> electrodeInds(channelVector.size());
+  std::vector<int> electrodeInds(channelVector.size());
+  std::vector<float> channelConversions(channelVector.size());
   for (size_t i = 0; i < channelVector.size(); ++i) {
     electrodeInds[i] = channelVector[i].globalIndex;
+    channelConversions[i] = channelVector[i].getConversion();
   }
   samplesRecorded = SizeArray(channelVector.size(), 0);
 
@@ -50,6 +52,10 @@ void ElectricalSeries::initialize(const IO::BaseDataType& dataType,
                              SizeArray {1},
                              chunkSize,
                              getPath() + "/channel_conversion"));
+  channelConversion->writeDataBlock(
+      std::vector<SizeType>(1, channelVector.size()),
+      BaseDataType::F32,
+      &channelConversions[0]);
   io->createCommonNWBAttributes(getPath() + "/channel_conversion",
                                 "hdmf-common",
                                 "",
diff --git a/tests/reader.cpp b/tests/reader.cpp
index 1809c21a..75b65c02 100644
--- a/tests/reader.cpp
+++ b/tests/reader.cpp
@@ -9,35 +9,39 @@ using namespace H5;
 
 int readerFunction(const std::string& path, const std::string& dataPath)
 {
-  std::unique_ptr<H5File> file =
-      std::make_unique<H5File>(path, H5F_ACC_RDONLY | H5F_ACC_SWMR_READ);
-  std::unique_ptr<H5::DataSet> dSet =
-      std::make_unique<H5::DataSet>(file->openDataSet(dataPath));
-
-  std::vector<hsize_t> dsetSizes;
-  for (int i = 0; i < 3; ++i) {
-    H5Drefresh(dSet->getId());
-
-    // Get the current size of the dataset
-    DataSpace fSpace = dSet->getSpace();
-    hsize_t currentSize;
-    fSpace.getSimpleExtentDims(&currentSize, nullptr);
-
-    // Update the size
-    dsetSizes.push_back(currentSize);
-    sleep(1);  // Simulate real-time data streaming
-  }
-
-  // print out dataset sizes
-  std::cout << "Dataset sizes: ";
-  for (int val : dsetSizes) {
-    std::cout << val << " ";
-  }
-  std::cout << std::endl;
-
-  // check that data is being appended (last value should be greater than the
-  // first)
-  if (dsetSizes[0] >= dsetSizes[2]) {
+  try {
+    std::unique_ptr<H5File> file =
+        std::make_unique<H5File>(path, H5F_ACC_RDONLY | H5F_ACC_SWMR_READ);
+    std::unique_ptr<H5::DataSet> dSet =
+        std::make_unique<H5::DataSet>(file->openDataSet(dataPath));
+
+    std::vector<hsize_t> dsetSizes;
+    for (int i = 0; i < 3; ++i) {
+      H5Drefresh(dSet->getId());
+
+      // Get the current size of the dataset
+      DataSpace fSpace = dSet->getSpace();
+      hsize_t currentSize;
+      fSpace.getSimpleExtentDims(&currentSize, nullptr);
+
+      // Update the size
+      dsetSizes.push_back(currentSize);
+      sleep(1);  // Simulate real-time data streaming
+    }
+
+    // print out dataset sizes
+    std::cout << "Dataset sizes: ";
+    for (int val : dsetSizes) {
+      std::cout << val << " ";
+    }
+    std::cout << std::endl;
+
+    // check that data is being appended (last value should be greater than the
+    // first)
+    if (dsetSizes[0] >= dsetSizes[2]) {
+      return -1;
+    }
+  } catch (const FileIException& error) {
     return -1;
   }
 
diff --git a/tests/testRecordingWorkflow.cpp b/tests/testRecordingWorkflow.cpp
index 4248eda0..9651dc88 100644
--- a/tests/testRecordingWorkflow.cpp
+++ b/tests/testRecordingWorkflow.cpp
@@ -21,7 +21,7 @@ TEST_CASE("writeContinuousData", "[recording]")
   {
     // 0. setup mock data
     SizeType numChannels = 4;
-    SizeType numSamples = 300;
+    SizeType numSamples = 100;
     SizeType samplesRecorded = 0;
     SizeType bufferSize = numSamples / 10;
     std::vector<float> dataBuffer(bufferSize);
@@ -47,7 +47,7 @@ TEST_CASE("writeContinuousData", "[recording]")
 
     // 4. create datasets and add to recording containers
     nwbfile->createElectricalSeries(
-        mockRecordingArrays, BaseDataType::I16, recordingContainers.get());
+        mockRecordingArrays, BaseDataType::F32, recordingContainers.get());
 
     // 5. start the recording
     io->startRecording();
@@ -72,14 +72,12 @@ TEST_CASE("writeContinuousData", "[recording]")
           std::vector<SizeType> positionOffset = {samplesRecorded,
                                                   channel.localIndex};
           std::vector<SizeType> dataShape = {dataBuffer.size(), 1};
-          std::unique_ptr<int16_t[]> intBuffer = transformToInt16(
-              dataBuffer.size(), channel.getBitVolts(), dataBuffer.data());
 
           recordingContainers->writeTimeseriesData(i,
                                                    channel,
                                                    dataShape,
                                                    positionOffset,
-                                                   intBuffer.get(),
+                                                   dataBuffer.data(),
                                                    timestampsBuffer.data());
         }
       }
@@ -113,8 +111,7 @@ TEST_CASE("writeContinuousData", "[recording]")
                                             std::vector<float>(numSamples));
     for (SizeType i = 0; i < numChannelsToRead; ++i) {
       for (SizeType j = 0; j < numSamples; ++j) {
-        dataOut[i][j] =
-            buffer[j * numChannelsToRead + i] * (32767.0f * 0.000002f);
+        dataOut[i][j] = buffer[j * numChannelsToRead + i];
       }
     }
     delete[] buffer;
diff --git a/tests/testUtils.hpp b/tests/testUtils.hpp
index a29aabd9..06778827 100644
--- a/tests/testUtils.hpp
+++ b/tests/testUtils.hpp
@@ -81,7 +81,7 @@ inline std::vector<std::vector<float>> getMockData2D(SizeType numSamples = 1000,
   for (auto& channelData : mockData) {
     for (auto& data : channelData) {
       data = static_cast<float>(dis(rng))
-          * 1000.f;  // approximate microvolt unit range
+          * 100.f;  // approximate microvolt unit range
     }
   }