Index: trunk/psModules/src/concepts/pmConceptsAverage.c
===================================================================
--- trunk/psModules/src/concepts/pmConceptsAverage.c	(revision 12696)
+++ trunk/psModules/src/concepts/pmConceptsAverage.c	(revision 14465)
@@ -5,4 +5,5 @@
 #include <stdio.h>
 #include <pslib.h>
+#include <string.h>
 
 #include "pmHDU.h"
@@ -17,4 +18,64 @@
     psMetadataItem *item = psMetadataLookup(MD, NAME); \
     item->data.TYPE = VALUE; \
+}
+
+bool pmConceptsAverageFPAs(pmFPA *target, psList *sources)
+{
+    PS_ASSERT_PTR_NON_NULL(target, false);
+    PS_ASSERT_PTR_NON_NULL(sources, false);
+    PS_ASSERT_INT_POSITIVE(sources->n, false);
+    bool success = true;                // Result of setting everything
+
+    float exposure   = 0.0;             // Exposure time
+    double time      = 0.0;             // Time of observation
+    psTimeType timeSys = 0;             // Time system
+    char *filter     = NULL;            // Filter
+
+    int num = 0;                        // Number of FPAs
+    psListIterator *sourcesIter = psListIteratorAlloc(sources, PS_LIST_HEAD, false); // Iterator for sources
+    pmFPA *fpa = NULL;                  // Source FPA from iteration
+    while ((fpa = psListGetAndIncrement(sourcesIter))) {
+        if (!fpa) {
+            continue;
+        }
+
+        num++;
+        exposure   += psMetadataLookupF32(NULL, fpa->concepts, "FPA.EXPOSURE");
+
+        psTime *fpaTime = psMetadataLookupPtr(NULL, fpa->concepts, "FPA.TIME");
+        time       += psTimeToMJD(fpaTime);
+        if (num == 1) {
+            timeSys = psMetadataLookupS32(NULL, fpa->concepts, "FPA.TIMESYS");
+            filter = psMetadataLookupStr(NULL, fpa->concepts, "FPA.FILTER");
+        } else {
+            if (timeSys != psMetadataLookupS32(NULL, fpa->concepts, "FPA.TIMESYS")) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Differing FPA.TIMESYS in use: %d vs %d\n",
+                        timeSys, psMetadataLookupS32(NULL, fpa->concepts, "FPA.TIMESYS"));
+                success = false;
+            }
+            if (strcmp(filter, psMetadataLookupStr(NULL, fpa->concepts, "FPA.FILTER")) != 0) {
+                psError(PS_ERR_BAD_PARAMETER_VALUE, true, "Differing FPA.FILTER in use: %s vs %s\n",
+                        filter, psMetadataLookupStr(NULL, fpa->concepts, "FPA.FILTER"));
+                success = false;
+            }
+        }
+    }
+    psFree(sourcesIter);
+
+    exposure  /= (float)num;
+    time      /= (double)num;
+
+    MD_UPDATE(target->concepts, "FPA.EXPOSURE", F32, exposure);
+    MD_UPDATE(target->concepts, "FPA.TIMESYS", S32, timeSys);
+    MD_UPDATE(target->concepts, "FPA.FILTER", str, filter);
+
+    // FPA.TIME needs special care
+    {
+        psMetadataItem *timeItem = psMetadataLookup(target->concepts, "FPA.TIME");
+        psFree(timeItem->data.V);
+        timeItem->data.V = psTimeFromMJD(time);
+    }
+
+    return success;
 }
 
