diff --git a/CEP/BB/BBS/src/Prediffer.cc b/CEP/BB/BBS/src/Prediffer.cc
index 5008c0aa857ec4609c1113a80adb097b3523f2f6..2b9c4b08de5e62afcbd0f3d827c4b28902481ddc 100644
--- a/CEP/BB/BBS/src/Prediffer.cc
+++ b/CEP/BB/BBS/src/Prediffer.cc
@@ -58,11 +58,10 @@
 #include <casa/Arrays/Slice.h>
 #include <casa/Arrays/Slicer.h>
 #include <casa/Arrays/Vector.h>
-#include <measures/Measures/MDirection.h>
-#include <measures/Measures/MeasConvert.h>
+// Vector2.cc: necessary to instantiate .tovector()
+#include <casa/Arrays/Vector2.cc>
 #include <casa/Quanta/MVBaseline.h>
 #include <casa/Quanta/MVPosition.h>
-#include <casa/Utilities/Regex.h>
 #include <casa/OS/Timer.h>
 #include <casa/OS/RegularFile.h>
 #include <casa/OS/SymLink.h>
@@ -70,11 +69,35 @@
 #include <casa/IO/AipsIO.h>
 #include <casa/IO/MemoryIO.h>
 #include <casa/Exceptions/Error.h>
+#include <casa/Utilities/Regex.h>
+#include <casa/Utilities/GenSort.h>
+
+#include <measures/Measures/MeasConvert.h>
+#include <measures/Measures/MeasTable.h>
+#include <measures/Measures/MPosition.h>
+#include <measures/Measures/MDirection.h>
+#include <measures/Measures/Stokes.h>
+
 #include <tables/Tables/Table.h>
 #include <tables/Tables/TableDesc.h>
+#include <tables/Tables/ScalarColumn.h>
 #include <tables/Tables/ArrColDesc.h>
 #include <tables/Tables/TiledColumnStMan.h>
 
+#include <ms/MeasurementSets/MeasurementSet.h>
+#include <ms/MeasurementSets/MSAntenna.h>
+#include <ms/MeasurementSets/MSAntennaColumns.h>
+#include <ms/MeasurementSets/MSDataDescription.h>
+#include <ms/MeasurementSets/MSDataDescColumns.h>
+#include <ms/MeasurementSets/MSField.h>
+#include <ms/MeasurementSets/MSFieldColumns.h>
+#include <ms/MeasurementSets/MSObservation.h>
+#include <ms/MeasurementSets/MSObsColumns.h>
+#include <ms/MeasurementSets/MSPolarization.h>
+#include <ms/MeasurementSets/MSPolColumns.h>
+#include <ms/MeasurementSets/MSSpectralWindow.h>
+#include <ms/MeasurementSets/MSSpWindowColumns.h>
+
 #include <stdexcept>
 #include <iostream>
 #include <iomanip>
@@ -127,8 +150,10 @@ Prediffer::Prediffer(const string& msName,
 		<< "'" << skyPdm.getTableName() << "', "
 		<< itsCalcUVW << ")" );
   // Read the meta data and map the flags file.
-  readDescriptiveData (msName);
-  processMSDesc (ddid);
+  //readDescriptiveData(msName);
+  readMeasurementSetMetaData(msName);
+  processMSDesc(ddid);
+  
   itsFlagsMap = new FlagsMap(msName + "/vis.flg", MMap::Read);
   // Get all sources from the ParmDB.
   itsSources = new MeqSourceList(itsGSMMEP, itsParmGroup);
@@ -400,6 +425,8 @@ Prediffer::~Prediffer()
 
 void Prediffer::readDescriptiveData (const string& fileName)
 {
+  ASSERTSTR(false, "DEPRECATED -- will be removed in next release. Use Prediffer::readMeasurementSetMetaData instead.");
+  
   // Get meta data from description file.
   string name(fileName+"/vis.des");
   std::ifstream istr(name.c_str());
@@ -409,6 +436,204 @@ void Prediffer::readDescriptiveData (const string& fileName)
   bis >> itsMSDesc;
 }
 
+void Prediffer::readMeasurementSetMetaData(const string &fileName)
+{
+    MeasurementSet ms(fileName);
+    
+    Path absolutePath = Path(fileName).absoluteName();
+    itsMSDesc.msPath = absolutePath.dirName();
+    itsMSDesc.msName = absolutePath.baseName();
+    
+    itsMSDesc.npart  = 1;
+    
+    /*
+        Get baselines.
+    */
+    Block<String> sortColumns(2);
+    sortColumns[0] = "ANTENNA1";
+    sortColumns[1] = "ANTENNA2";
+    Table uniqueBaselines = ms.sort(sortColumns, Sort::Ascending, Sort::QuickSort + Sort::NoDuplicates);
+    ROScalarColumn<Int> station1Column(uniqueBaselines, "ANTENNA1");
+    ROScalarColumn<Int> station2Column(uniqueBaselines, "ANTENNA2");
+    station1Column.getColumn().tovector(itsMSDesc.ant1);
+    station2Column.getColumn().tovector(itsMSDesc.ant2);
+    
+    /*
+        Get information about frequency grid.
+    */
+    MSDataDescription dataDescription(ms.dataDescription());
+    ROMSDataDescColumns dataDescriptionColumns(dataDescription);
+    MSSpectralWindow spectralWindow(ms.spectralWindow());
+    ROMSSpWindowColumns spectralWindowColumns(spectralWindow);
+    int spectralWindowCount = dataDescription.nrow();
+    
+    itsMSDesc.nchan.resize(spectralWindowCount);
+    itsMSDesc.startFreq.resize(spectralWindowCount);
+    itsMSDesc.endFreq.resize(spectralWindowCount);
+    
+    for(int i = 0; i < spectralWindowCount; i++)
+    {
+        Vector<double> channelFrequency = spectralWindowColumns.chanFreq()(i);
+        Vector<double> channelWidth = spectralWindowColumns.chanWidth()(i);
+        
+        // So far, only equal frequency spacings are possible.
+        ASSERTSTR(allEQ(channelWidth, channelWidth(0)), "Channels must have equal spacings");
+        
+        int channelCount = channelWidth.nelements();
+        itsMSDesc.nchan[i] = channelCount;
+        
+        double step = abs(channelWidth(0));
+        if(channelFrequency(0) > channelFrequency(channelCount - 1))
+        {
+            itsMSDesc.startFreq[i] = channelFrequency(0) + step / 2;
+            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] - channelCount * step;
+        }
+        else
+        {
+            itsMSDesc.startFreq[i] = channelFrequency(0) - step / 2;
+            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] + channelCount * step;
+        }
+    }
+    
+    /*
+        Get information about time grid.
+    */
+    ROScalarColumn<double> timeColumn(ms, "TIME");
+    Vector<double> time = timeColumn.getColumn();
+    Vector<uInt> timeIndex;
+    uInt timeCount = GenSortIndirect<double>::sort(timeIndex, time, Sort::Ascending, Sort::InsSort + Sort::NoDuplicates);
+        
+    itsMSDesc.times.resize(timeCount);
+    itsMSDesc.exposures.resize(timeCount);
+    ROScalarColumn<double> exposureColumn(ms, "EXPOSURE");
+    Vector<double> exposure = exposureColumn.getColumn();
+    
+    for(uInt i = 0; i < timeCount; i++)
+    {
+        itsMSDesc.times[i] = time[timeIndex[i]];
+        itsMSDesc.exposures[i] = exposure[timeIndex[i]];
+    }
+    
+    /*
+        Get phase center as RA and DEC (J2000).
+        
+        From AIPS++ note 229 (MeasurementSet definition version 2.0):
+        ---
+        FIELD: Field positions for each source
+        Notes:
+            The FIELD table defines a field position on the sky. For interferometers,
+            this is the correlated field position. For single dishes, this is the
+            nominal pointing direction.    
+        ---
+        
+        The way this column is used by SelfCal seems to have nothing to do with sources.
+        In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found:
+            MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0));
+        which should be equivalent to:
+            MDirection phaseRef = mssubc.phaseDirMeas(0);
+        as used in the code below.
+    */
+    MSField field(ms.field());
+    ROMSFieldColumns fieldColumns(field);
+    MDirection phaseCenter = MDirection::Convert(fieldColumns.phaseDirMeas(0), MDirection::J2000)();
+    Quantum<Vector<double> > phaseCenterAngles = phaseCenter.getAngle();
+    itsMSDesc.ra  = phaseCenterAngles.getBaseValue()(0);
+    itsMSDesc.dec = phaseCenterAngles.getBaseValue()(1);
+    
+    /*
+        Get correlation types.
+    */
+    MSPolarization polarization(ms.polarization());
+    ROMSPolarizationColumns polarizationColumn(polarization);
+    Vector<Int> correlationTypes = polarizationColumn.corrType()(0);
+    int correlationTypeCount = correlationTypes.nelements();
+    itsMSDesc.corrTypes.resize(correlationTypeCount);
+    for(int i = 0; i < correlationTypeCount; i++)
+    {
+        itsMSDesc.corrTypes[i] = Stokes::name(Stokes::type(correlationTypes(i)));
+    }
+    
+    /*
+        Get station names and positions in ITRF coordinates.
+    */
+    MSAntenna antenna(ms.antenna());
+    ROMSAntennaColumns antennaColumns(antenna);
+    int antennaCount = antenna.nrow();
+    
+    MVPosition sumVector;
+    itsMSDesc.antNames.resize(antennaCount);
+    itsMSDesc.antPos.resize(IPosition(2, 3, antennaCount));
+    for(int i = 0; i < antennaCount; i++)
+    {
+        itsMSDesc.antNames[i] = antennaColumns.name()(i);
+        MPosition position = antennaColumns.positionMeas()(i);
+        position = MPosition::Convert(position, MPosition::ITRF)();
+        const MVPosition& positionVector = position.getValue();
+        sumVector += positionVector;
+        for(int j = 0; j < 3; j++)
+        {
+            itsMSDesc.antPos(IPosition(2, j, i)) = positionVector(j);
+        }
+    }
+    
+    /*
+        Get the array position in ITRF coordinates, or use the centroid
+        of the station positions if the array position is unknown.
+    */
+    MSObservation observation(ms.observation());
+    ROMSObservationColumns observationColumns(observation);
+    
+    MPosition position;
+    MVPosition positionVector;
+    if(observation.nrow() > 0 && MeasTable::Observatory(position, observationColumns.telescopeName()(0)))
+    {
+        position = MPosition::Convert(position, MPosition::ITRF)();
+        positionVector = position.getValue();
+    }
+    else
+    {
+        positionVector = sumVector * (1.0 / (double) antennaCount);
+    }
+    
+    itsMSDesc.arrayPos.resize(3);
+    for(int i = 0; i < 3; i++)
+    {
+        itsMSDesc.arrayPos[i] = positionVector(i);
+    }
+    
+    /*
+        Determine the startTime and endTime of the observation.
+    */
+    if(observation.nrow() > 0)
+    {
+        Vector<double> times = observationColumns.timeRange()(0);
+        itsMSDesc.startTime = times(0);
+        itsMSDesc.endTime   = times(1);
+    }
+    else
+    {
+        itsMSDesc.startTime = 0.0;
+        itsMSDesc.endTime   = 0.0;
+    }
+    
+    if(itsMSDesc.startTime >= itsMSDesc.endTime)
+    {
+        /*
+          Invalid start / end times; derive from times and interval.
+          Difference between interval and exposure is startup time which
+          is taken into account.
+        */
+        if(timeCount > 0)
+        {
+            ROScalarColumn<double> interval(ms, "INTERVAL");
+            itsMSDesc.startTime = itsMSDesc.times[0] - itsMSDesc.exposures[0] / 2 + (interval(0) - itsMSDesc.exposures[0]);
+            itsMSDesc.endTime   = itsMSDesc.times[timeCount - 1] + interval(timeCount - 1) / 2;
+        }
+    }
+    
+    cout << itsMSDesc;
+}
+
 void Prediffer::processMSDesc (uint ddid)
 {
   ASSERT (ddid < itsMSDesc.nchan.size());
diff --git a/CEP/BB/BBS/src/Prediffer.h b/CEP/BB/BBS/src/Prediffer.h
index 3f4aeeb9d3393ca1cac2fc7d5b4406b38831df82..e2235d8ed4bbd3991fbed2da58737dcf78777cef 100644
--- a/CEP/BB/BBS/src/Prediffer.h
+++ b/CEP/BB/BBS/src/Prediffer.h
@@ -196,10 +196,15 @@ private:
   // </group>
 
   // Get measurement set description from file
+  // NB. DEPRECATED -- only use for debugging purposes, will
+  // be removed in the next release.
   void readDescriptiveData (const string& fileName);
+  
+  // Read measurement set meta data
+  void readMeasurementSetMetaData(const string& fileName);
 
-  // Process the MS description for the given dd (sectral window).
-  void Prediffer::processMSDesc (uint ddid);
+  // Process the MS description for the given dd (spectral window).
+  void processMSDesc (uint ddid);
 
   // Get the phase reference position of the first field.
   void getPhaseRef (double ra, double dec, double startTime);
diff --git a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
index 3f4aeeb9d3393ca1cac2fc7d5b4406b38831df82..e2235d8ed4bbd3991fbed2da58737dcf78777cef 100644
--- a/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
+++ b/CEP/BB/BBSKernel/include/BBSKernel/Prediffer.h
@@ -196,10 +196,15 @@ private:
   // </group>
 
   // Get measurement set description from file
+  // NB. DEPRECATED -- only use for debugging purposes, will
+  // be removed in the next release.
   void readDescriptiveData (const string& fileName);
+  
+  // Read measurement set meta data
+  void readMeasurementSetMetaData(const string& fileName);
 
-  // Process the MS description for the given dd (sectral window).
-  void Prediffer::processMSDesc (uint ddid);
+  // Process the MS description for the given dd (spectral window).
+  void processMSDesc (uint ddid);
 
   // Get the phase reference position of the first field.
   void getPhaseRef (double ra, double dec, double startTime);
diff --git a/CEP/BB/BBSKernel/src/Prediffer.cc b/CEP/BB/BBSKernel/src/Prediffer.cc
index 5008c0aa857ec4609c1113a80adb097b3523f2f6..2b9c4b08de5e62afcbd0f3d827c4b28902481ddc 100644
--- a/CEP/BB/BBSKernel/src/Prediffer.cc
+++ b/CEP/BB/BBSKernel/src/Prediffer.cc
@@ -58,11 +58,10 @@
 #include <casa/Arrays/Slice.h>
 #include <casa/Arrays/Slicer.h>
 #include <casa/Arrays/Vector.h>
-#include <measures/Measures/MDirection.h>
-#include <measures/Measures/MeasConvert.h>
+// Vector2.cc: necessary to instantiate .tovector()
+#include <casa/Arrays/Vector2.cc>
 #include <casa/Quanta/MVBaseline.h>
 #include <casa/Quanta/MVPosition.h>
-#include <casa/Utilities/Regex.h>
 #include <casa/OS/Timer.h>
 #include <casa/OS/RegularFile.h>
 #include <casa/OS/SymLink.h>
@@ -70,11 +69,35 @@
 #include <casa/IO/AipsIO.h>
 #include <casa/IO/MemoryIO.h>
 #include <casa/Exceptions/Error.h>
+#include <casa/Utilities/Regex.h>
+#include <casa/Utilities/GenSort.h>
+
+#include <measures/Measures/MeasConvert.h>
+#include <measures/Measures/MeasTable.h>
+#include <measures/Measures/MPosition.h>
+#include <measures/Measures/MDirection.h>
+#include <measures/Measures/Stokes.h>
+
 #include <tables/Tables/Table.h>
 #include <tables/Tables/TableDesc.h>
+#include <tables/Tables/ScalarColumn.h>
 #include <tables/Tables/ArrColDesc.h>
 #include <tables/Tables/TiledColumnStMan.h>
 
+#include <ms/MeasurementSets/MeasurementSet.h>
+#include <ms/MeasurementSets/MSAntenna.h>
+#include <ms/MeasurementSets/MSAntennaColumns.h>
+#include <ms/MeasurementSets/MSDataDescription.h>
+#include <ms/MeasurementSets/MSDataDescColumns.h>
+#include <ms/MeasurementSets/MSField.h>
+#include <ms/MeasurementSets/MSFieldColumns.h>
+#include <ms/MeasurementSets/MSObservation.h>
+#include <ms/MeasurementSets/MSObsColumns.h>
+#include <ms/MeasurementSets/MSPolarization.h>
+#include <ms/MeasurementSets/MSPolColumns.h>
+#include <ms/MeasurementSets/MSSpectralWindow.h>
+#include <ms/MeasurementSets/MSSpWindowColumns.h>
+
 #include <stdexcept>
 #include <iostream>
 #include <iomanip>
@@ -127,8 +150,10 @@ Prediffer::Prediffer(const string& msName,
 		<< "'" << skyPdm.getTableName() << "', "
 		<< itsCalcUVW << ")" );
   // Read the meta data and map the flags file.
-  readDescriptiveData (msName);
-  processMSDesc (ddid);
+  //readDescriptiveData(msName);
+  readMeasurementSetMetaData(msName);
+  processMSDesc(ddid);
+  
   itsFlagsMap = new FlagsMap(msName + "/vis.flg", MMap::Read);
   // Get all sources from the ParmDB.
   itsSources = new MeqSourceList(itsGSMMEP, itsParmGroup);
@@ -400,6 +425,8 @@ Prediffer::~Prediffer()
 
 void Prediffer::readDescriptiveData (const string& fileName)
 {
+  ASSERTSTR(false, "DEPRECATED -- will be removed in next release. Use Prediffer::readMeasurementSetMetaData instead.");
+  
   // Get meta data from description file.
   string name(fileName+"/vis.des");
   std::ifstream istr(name.c_str());
@@ -409,6 +436,204 @@ void Prediffer::readDescriptiveData (const string& fileName)
   bis >> itsMSDesc;
 }
 
+void Prediffer::readMeasurementSetMetaData(const string &fileName)
+{
+    MeasurementSet ms(fileName);
+    
+    Path absolutePath = Path(fileName).absoluteName();
+    itsMSDesc.msPath = absolutePath.dirName();
+    itsMSDesc.msName = absolutePath.baseName();
+    
+    itsMSDesc.npart  = 1;
+    
+    /*
+        Get baselines.
+    */
+    Block<String> sortColumns(2);
+    sortColumns[0] = "ANTENNA1";
+    sortColumns[1] = "ANTENNA2";
+    Table uniqueBaselines = ms.sort(sortColumns, Sort::Ascending, Sort::QuickSort + Sort::NoDuplicates);
+    ROScalarColumn<Int> station1Column(uniqueBaselines, "ANTENNA1");
+    ROScalarColumn<Int> station2Column(uniqueBaselines, "ANTENNA2");
+    station1Column.getColumn().tovector(itsMSDesc.ant1);
+    station2Column.getColumn().tovector(itsMSDesc.ant2);
+    
+    /*
+        Get information about frequency grid.
+    */
+    MSDataDescription dataDescription(ms.dataDescription());
+    ROMSDataDescColumns dataDescriptionColumns(dataDescription);
+    MSSpectralWindow spectralWindow(ms.spectralWindow());
+    ROMSSpWindowColumns spectralWindowColumns(spectralWindow);
+    int spectralWindowCount = dataDescription.nrow();
+    
+    itsMSDesc.nchan.resize(spectralWindowCount);
+    itsMSDesc.startFreq.resize(spectralWindowCount);
+    itsMSDesc.endFreq.resize(spectralWindowCount);
+    
+    for(int i = 0; i < spectralWindowCount; i++)
+    {
+        Vector<double> channelFrequency = spectralWindowColumns.chanFreq()(i);
+        Vector<double> channelWidth = spectralWindowColumns.chanWidth()(i);
+        
+        // So far, only equal frequency spacings are possible.
+        ASSERTSTR(allEQ(channelWidth, channelWidth(0)), "Channels must have equal spacings");
+        
+        int channelCount = channelWidth.nelements();
+        itsMSDesc.nchan[i] = channelCount;
+        
+        double step = abs(channelWidth(0));
+        if(channelFrequency(0) > channelFrequency(channelCount - 1))
+        {
+            itsMSDesc.startFreq[i] = channelFrequency(0) + step / 2;
+            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] - channelCount * step;
+        }
+        else
+        {
+            itsMSDesc.startFreq[i] = channelFrequency(0) - step / 2;
+            itsMSDesc.endFreq[i]   = itsMSDesc.startFreq[i] + channelCount * step;
+        }
+    }
+    
+    /*
+        Get information about time grid.
+    */
+    ROScalarColumn<double> timeColumn(ms, "TIME");
+    Vector<double> time = timeColumn.getColumn();
+    Vector<uInt> timeIndex;
+    uInt timeCount = GenSortIndirect<double>::sort(timeIndex, time, Sort::Ascending, Sort::InsSort + Sort::NoDuplicates);
+        
+    itsMSDesc.times.resize(timeCount);
+    itsMSDesc.exposures.resize(timeCount);
+    ROScalarColumn<double> exposureColumn(ms, "EXPOSURE");
+    Vector<double> exposure = exposureColumn.getColumn();
+    
+    for(uInt i = 0; i < timeCount; i++)
+    {
+        itsMSDesc.times[i] = time[timeIndex[i]];
+        itsMSDesc.exposures[i] = exposure[timeIndex[i]];
+    }
+    
+    /*
+        Get phase center as RA and DEC (J2000).
+        
+        From AIPS++ note 229 (MeasurementSet definition version 2.0):
+        ---
+        FIELD: Field positions for each source
+        Notes:
+            The FIELD table defines a field position on the sky. For interferometers,
+            this is the correlated field position. For single dishes, this is the
+            nominal pointing direction.    
+        ---
+        
+        The way this column is used by SelfCal seems to have nothing to do with sources.
+        In LOFAR/CEP/BB/MS/src/makemsdesc.cc the following line can be found:
+            MDirection phaseRef = mssubc.phaseDirMeasCol()(0)(IPosition(1,0));
+        which should be equivalent to:
+            MDirection phaseRef = mssubc.phaseDirMeas(0);
+        as used in the code below.
+    */
+    MSField field(ms.field());
+    ROMSFieldColumns fieldColumns(field);
+    MDirection phaseCenter = MDirection::Convert(fieldColumns.phaseDirMeas(0), MDirection::J2000)();
+    Quantum<Vector<double> > phaseCenterAngles = phaseCenter.getAngle();
+    itsMSDesc.ra  = phaseCenterAngles.getBaseValue()(0);
+    itsMSDesc.dec = phaseCenterAngles.getBaseValue()(1);
+    
+    /*
+        Get correlation types.
+    */
+    MSPolarization polarization(ms.polarization());
+    ROMSPolarizationColumns polarizationColumn(polarization);
+    Vector<Int> correlationTypes = polarizationColumn.corrType()(0);
+    int correlationTypeCount = correlationTypes.nelements();
+    itsMSDesc.corrTypes.resize(correlationTypeCount);
+    for(int i = 0; i < correlationTypeCount; i++)
+    {
+        itsMSDesc.corrTypes[i] = Stokes::name(Stokes::type(correlationTypes(i)));
+    }
+    
+    /*
+        Get station names and positions in ITRF coordinates.
+    */
+    MSAntenna antenna(ms.antenna());
+    ROMSAntennaColumns antennaColumns(antenna);
+    int antennaCount = antenna.nrow();
+    
+    MVPosition sumVector;
+    itsMSDesc.antNames.resize(antennaCount);
+    itsMSDesc.antPos.resize(IPosition(2, 3, antennaCount));
+    for(int i = 0; i < antennaCount; i++)
+    {
+        itsMSDesc.antNames[i] = antennaColumns.name()(i);
+        MPosition position = antennaColumns.positionMeas()(i);
+        position = MPosition::Convert(position, MPosition::ITRF)();
+        const MVPosition& positionVector = position.getValue();
+        sumVector += positionVector;
+        for(int j = 0; j < 3; j++)
+        {
+            itsMSDesc.antPos(IPosition(2, j, i)) = positionVector(j);
+        }
+    }
+    
+    /*
+        Get the array position in ITRF coordinates, or use the centroid
+        of the station positions if the array position is unknown.
+    */
+    MSObservation observation(ms.observation());
+    ROMSObservationColumns observationColumns(observation);
+    
+    MPosition position;
+    MVPosition positionVector;
+    if(observation.nrow() > 0 && MeasTable::Observatory(position, observationColumns.telescopeName()(0)))
+    {
+        position = MPosition::Convert(position, MPosition::ITRF)();
+        positionVector = position.getValue();
+    }
+    else
+    {
+        positionVector = sumVector * (1.0 / (double) antennaCount);
+    }
+    
+    itsMSDesc.arrayPos.resize(3);
+    for(int i = 0; i < 3; i++)
+    {
+        itsMSDesc.arrayPos[i] = positionVector(i);
+    }
+    
+    /*
+        Determine the startTime and endTime of the observation.
+    */
+    if(observation.nrow() > 0)
+    {
+        Vector<double> times = observationColumns.timeRange()(0);
+        itsMSDesc.startTime = times(0);
+        itsMSDesc.endTime   = times(1);
+    }
+    else
+    {
+        itsMSDesc.startTime = 0.0;
+        itsMSDesc.endTime   = 0.0;
+    }
+    
+    if(itsMSDesc.startTime >= itsMSDesc.endTime)
+    {
+        /*
+          Invalid start / end times; derive from times and interval.
+          Difference between interval and exposure is startup time which
+          is taken into account.
+        */
+        if(timeCount > 0)
+        {
+            ROScalarColumn<double> interval(ms, "INTERVAL");
+            itsMSDesc.startTime = itsMSDesc.times[0] - itsMSDesc.exposures[0] / 2 + (interval(0) - itsMSDesc.exposures[0]);
+            itsMSDesc.endTime   = itsMSDesc.times[timeCount - 1] + interval(timeCount - 1) / 2;
+        }
+    }
+    
+    cout << itsMSDesc;
+}
+
 void Prediffer::processMSDesc (uint ddid)
 {
   ASSERT (ddid < itsMSDesc.nchan.size());
diff --git a/CEP/BB/BBSKernel/src/Prediffer.h b/CEP/BB/BBSKernel/src/Prediffer.h
index 3f4aeeb9d3393ca1cac2fc7d5b4406b38831df82..e2235d8ed4bbd3991fbed2da58737dcf78777cef 100644
--- a/CEP/BB/BBSKernel/src/Prediffer.h
+++ b/CEP/BB/BBSKernel/src/Prediffer.h
@@ -196,10 +196,15 @@ private:
   // </group>
 
   // Get measurement set description from file
+  // NB. DEPRECATED -- only use for debugging purposes, will
+  // be removed in the next release.
   void readDescriptiveData (const string& fileName);
+  
+  // Read measurement set meta data
+  void readMeasurementSetMetaData(const string& fileName);
 
-  // Process the MS description for the given dd (sectral window).
-  void Prediffer::processMSDesc (uint ddid);
+  // Process the MS description for the given dd (spectral window).
+  void processMSDesc (uint ddid);
 
   // Get the phase reference position of the first field.
   void getPhaseRef (double ra, double dec, double startTime);