diff --git a/gstlal-calibration/gst/cmath/Makefile.am b/gstlal-calibration/gst/cmath/Makefile.am
index a2b6c7acb6104621340319de8e2de28ca60205f5..04afb595237381729239478627f3bba26a7c53ec 100644
--- a/gstlal-calibration/gst/cmath/Makefile.am
+++ b/gstlal-calibration/gst/cmath/Makefile.am
@@ -5,6 +5,8 @@ libgstcmath_la_SOURCES = \
 	cmath.c \
 	cmath_base.h cmath_base.c \
 	cmath_cabs.c \
+	cmath_creal.c \
+	cmath_cimag.c \
 	cmath_cexp.c \
 	cmath_cln.c \
 	cmath_clog.c \
diff --git a/gstlal-calibration/gst/cmath/cmath.c b/gstlal-calibration/gst/cmath/cmath.c
index 6bbf425bdec5fb056393429b12546ccc1b42ed95..8975c0eb6d7ab3f9959ec47a041fcf4b78ee1e13 100644
--- a/gstlal-calibration/gst/cmath/cmath.c
+++ b/gstlal-calibration/gst/cmath/cmath.c
@@ -53,6 +53,8 @@
 
 
 GType cmath_cabs_get_type (void);
+GType cmath_creal_get_type (void);
+GType cmath_cimag_get_type (void);
 GType cmath_cexp_get_type (void);
 GType cmath_cln_get_type (void);
 GType cmath_clog_get_type (void);
@@ -71,6 +73,8 @@ plugin_init (GstPlugin *plugin)
 		{
 		"cmath_base", CMATH_BASE_TYPE}, {
 		"cabs", cmath_cabs_get_type ()}, {
+		"creal", cmath_creal_get_type ()}, {
+		"cimag", cmath_cimag_get_type ()}, {
 		"cexp", cmath_cexp_get_type ()}, {
 		"cln", cmath_cln_get_type ()}, {
 		"clog", cmath_clog_get_type ()}, {
diff --git a/gstlal-calibration/gst/cmath/cmath_base.c b/gstlal-calibration/gst/cmath/cmath_base.c
index e943569923aeb2165a52ab9b606cb5b3ed2516c9..4b4cc867198cf3419c2c7a93423cd810113e8aee 100644
--- a/gstlal-calibration/gst/cmath/cmath_base.c
+++ b/gstlal-calibration/gst/cmath/cmath_base.c
@@ -22,6 +22,8 @@
  * https://gstreamer.freedesktop.org/data/doc/gstreamer/head/gstreamer-libs/html/GstBaseTransform.html#GstBaseTransform-struct
  */
 
+
+#include <gst/audio/audio.h>
 #include <cmath_base.h>
 
 
@@ -36,7 +38,7 @@
 
 #define CAPS \
 		"audio/x-raw, " \
-		"format = (string) { F32LE, F32BE, F64LE, F64BE, Z64LE, Z64BE, Z128LE, Z128BE }, " \
+		"format = (string) {"GST_AUDIO_NE(F32)", "GST_AUDIO_NE(F64)", "GST_AUDIO_NE(Z64)", "GST_AUDIO_NE(Z128)"}, " \
 		"rate = (int) [1, MAX], " \
 		"channels = (int) [1, MAX], " \
 		"layout = (string) {interleaved, non-interleaved}, " \
@@ -111,7 +113,7 @@ gboolean set_caps(GstBaseTransform *trans, GstCaps *incaps,
 		GstCaps *outcaps)
 {
 	gboolean success = TRUE;
-	static char *formats[] = {"Z128LE", "Z64LE", "F64LE", "F32LE"};
+	static char *formats[] = {GST_AUDIO_NE(Z128), GST_AUDIO_NE(Z64), GST_AUDIO_NE(F64), GST_AUDIO_NE(F32)};
 	static int is_complex[] = {1, 1, 0, 0};
 	static int bits[] = {128, 64, 64, 32};
 	const gchar *format;
diff --git a/gstlal-calibration/gst/cmath/cmath_cabs.c b/gstlal-calibration/gst/cmath/cmath_cabs.c
index 689a4ea18029c37838bd037db0702baca030ae4d..6eaff1801b61ea9612d81e00ce5500716f9fc536 100644
--- a/gstlal-calibration/gst/cmath/cmath_cabs.c
+++ b/gstlal-calibration/gst/cmath/cmath_cabs.c
@@ -18,6 +18,7 @@
  */
 
 
+#include <gst/audio/audio.h>
 #include <cmath_base.h>
 
 #define TYPE_CMATH_CABS \
@@ -56,72 +57,175 @@ struct _CMathCAbsClass
  * ============================================================================
  */
 
-/* An in-place transform really does the same thing as the chain function */
+static GstCaps *transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter)
+{
+	guint n;
+
+	caps = gst_caps_normalize(gst_caps_copy(caps));
+	GstCaps *othercaps = gst_caps_new_empty();
+
+	switch(direction) {
+	case GST_PAD_SRC:
+		/* There are two possible sink pad formats for each src pad format, so the sink pad caps has twice as many structures */
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+
+			GstStructure *str = gst_caps_get_structure(othercaps, 2 * n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z64), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z128), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_SINK:
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			GstStructure *str = gst_caps_get_structure(othercaps, n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F32), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F64), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		goto error;
+	}
+
+	if(filter) {
+		GstCaps *intersection = gst_caps_intersect(othercaps, filter);
+		gst_caps_unref(othercaps);
+		othercaps = intersection;
+	}
+	gst_caps_unref(caps);
+	return gst_caps_simplify(othercaps);
+
+error:
+	gst_caps_unref(caps);
+	gst_caps_unref(othercaps);
+	return GST_CAPS_NONE;
+}
+
+static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, gsize size, GstCaps *othercaps, gsize *othersize)
+{
+	CMathCAbs* element = CMATH_CABS(trans);
+
+	int is_complex = element->cmath_base.is_complex;
 
-static GstFlowReturn
-transform_ip(GstBaseTransform *trans, GstBuffer *buf)
+	switch(direction) {
+	case GST_PAD_SRC:
+		/*
+		 * We have the size of the output buffer, and we set the size of the input buffer,
+		 * which depends on the sink pad caps.
+		 */
+
+		if(is_complex) {
+			/* input buffer is twice as large as output buffer since it is complex */
+			*othersize = 2 * size;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_SINK:
+		/*
+		 * We have the size of the input buffer, and we set the size of the output buffer,
+		 * which depends on the sink pad caps..
+		 */
+
+		if(is_complex) {
+			/* output buffer is half as large as input buffer since it is complex */
+			*othersize = size / 2;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		return FALSE;
+	}
+
+	return TRUE;
+	
+}
+
+/* A transform really does the same thing as the chain function */
+
+static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
 {
 	CMathCAbs* element = CMATH_CABS(trans);
 	int bits = element -> cmath_base.bits;
 	int is_complex = element -> cmath_base.is_complex;
 
-	/*
-	 * Debugging
-	 *
-	 * GstObject* element_gstobj = GST_OBJECT(trans);
-	 * int channels = element -> cmath_base.channels;
-	 * int rate = element -> cmath_base.rate;
-	 * g_print("[%s]: passing GstBuffer: ", element_gstobj->name);
-	 * g_print("%d channels, ", channels);
-	 * g_print("%d bits, ", bits);
-	 * g_print("rate: %d, ", rate);
-	 */
-
-	GstMapInfo info;
-	if(!gst_buffer_map(buf, &info, GST_MAP_READWRITE)) {
-		GST_ERROR_OBJECT(trans, "gst_buffer_map failed\n");
-	}
-	gpointer data = info.data;
-	gpointer data_end = data + info.size;
+	GstMapInfo inmap, outmap;
+	gst_buffer_map(inbuf, &inmap, GST_MAP_READ);
+	gst_buffer_map(outbuf, &outmap, GST_MAP_WRITE);
+
+	gpointer indata = inmap.data;
+	gpointer outdata = outmap.data;
+	gpointer indata_end = indata + inmap.size;
 
 	if(is_complex == 1) {
 
 		if(bits == 128) {
-			/* g_print("COMPLEX FLOAT128\n"); */
-			double complex *ptr, *end = data_end;
-			for(ptr = data; ptr < end; ptr++) {
-				*ptr = cabs(*ptr);
-			}
+			double complex *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = cabs(*ptr);
 		} else if(bits == 64) {
-			/* g_print("COMPLEX FLOAT64\n"); */
-			float complex *ptr, *end = data_end;
-			for(ptr = data; ptr < end; ptr++) {
-				*ptr = cabsf(*ptr);
-			}
+			float complex *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = cabsf(*ptr);
 		} else {
 			g_assert_not_reached();
 		}
 	} else if(is_complex == 0) {
 
 		if(bits == 64) {
-			/* g_print("REAL FLOAT64\n"); */
-			double *ptr, *end = data_end;
-			for(ptr = data; ptr < end; ptr++) {
-				*ptr = fabs(*ptr);
-			}
+			double *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = fabs(*ptr);
 		} else if(bits == 32) {
-			/* g_print("REAL FLOAT32\n"); */
-			float *ptr, *end = data_end;
-			for(ptr = data; ptr < end; ptr++) {
-				*ptr = fabsf(*ptr);
-			}
+			float *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = fabsf(*ptr);
 		} else {
 			g_assert_not_reached();
 		}
 	} else {
 		g_assert_not_reached();
 	}
-	gst_buffer_unmap(buf, &info);
+
+	gst_buffer_unmap(inbuf, &inmap);
+	gst_buffer_unmap(outbuf, &outmap);
+
 	return GST_FLOW_OK;
 }
 
@@ -146,8 +250,10 @@ cmath_cabs_class_init(gpointer klass, gpointer klass_data)
 		"Calculate absolute value, y = |x|", 
 		"Aaron Viets <aaron.viets@ligo.org>, Leo Singer <leo.singer@ligo.org>");
 
-	basetransform_class -> transform_ip = GST_DEBUG_FUNCPTR(transform_ip);
+	basetransform_class -> transform = GST_DEBUG_FUNCPTR(transform);
 	basetransform_class -> set_caps = GST_DEBUG_FUNCPTR(set_caps);
+	basetransform_class -> transform_caps = GST_DEBUG_FUNCPTR(transform_caps);
+	basetransform_class -> transform_size = GST_DEBUG_FUNCPTR(transform_size);
 }
 
 GType
diff --git a/gstlal-calibration/gst/cmath/cmath_cimag.c b/gstlal-calibration/gst/cmath/cmath_cimag.c
new file mode 100644
index 0000000000000000000000000000000000000000..adc2600e88b81102fbc362c088b076bd42493506
--- /dev/null
+++ b/gstlal-calibration/gst/cmath/cmath_cimag.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2010 Leo Singer
+ * Copyright (C) 2016 Aaron Viets
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <gst/audio/audio.h>
+#include <cmath_base.h>
+
+#define TYPE_CMATH_CIMAG \
+	(cmath_cimag_get_type())
+#define CMATH_CIMAG(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST((obj),TYPE_CMATH_CIMAG,CMathCImag))
+#define CMATH_CIMAG_CLASS(klass) \
+	(G_TYPE_CHECK_CLASS_CAST((klass),TYPE_CMATH_CIMAG,CMathCImagClass))
+#define IS_PLUGIN_TEMPLATE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE((obj),TYPE_CMATH_CIMAG))
+#define IS_PLUGIN_TEMPLATE_CLASS(klass) \
+	(G_TYPE_CHECK_CLASS_TYPE((klass),TYPE_CMATH_CIMAG))
+
+typedef struct _CMathCImag CMathCImag;
+typedef struct _CMathCImagClass CMathCImagClass;
+
+GType
+cmath_cimag_get_type(void);
+
+struct _CMathCImag
+{
+	CMathBase cmath_base;
+};
+
+struct _CMathCImagClass 
+{
+	CMathBaseClass parent_class;
+};
+
+
+/*
+ * ============================================================================
+ *
+ *		     GstBaseTransform vmethod Implementations
+ *
+ * ============================================================================
+ */
+
+static GstCaps *transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter)
+{
+	guint n;
+
+	caps = gst_caps_normalize(gst_caps_copy(caps));
+	GstCaps *othercaps = gst_caps_new_empty();
+
+	switch(direction) {
+	case GST_PAD_SRC:
+		/* There are two possible sink pad formats for each src pad format, so the sink pad caps has twice as many structures */
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+
+			GstStructure *str = gst_caps_get_structure(othercaps, 2 * n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z64), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z128), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_SINK:
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			GstStructure *str = gst_caps_get_structure(othercaps, n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F32), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F64), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		goto error;
+	}
+
+	if(filter) {
+		GstCaps *intersection = gst_caps_intersect(othercaps, filter);
+		gst_caps_unref(othercaps);
+		othercaps = intersection;
+	}
+	gst_caps_unref(caps);
+	return gst_caps_simplify(othercaps);
+
+error:
+	gst_caps_unref(caps);
+	gst_caps_unref(othercaps);
+	return GST_CAPS_NONE;
+}
+
+static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, gsize size, GstCaps *othercaps, gsize *othersize)
+{
+	CMathCImag* element = CMATH_CIMAG(trans);
+
+	int is_complex = element->cmath_base.is_complex;
+
+	switch(direction) {
+	case GST_PAD_SRC:
+		/*
+		 * We have the size of the output buffer, and we set the size of the input buffer,
+		 * which depends on the sink pad caps.
+		 */
+
+		if(is_complex) {
+			/* input buffer is twice as large as output buffer since it is complex */
+			*othersize = 2 * size;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_SINK:
+		/*
+		 * We have the size of the input buffer, and we set the size of the output buffer,
+		 * which depends on the sink pad caps..
+		 */
+
+		if(is_complex) {
+			/* output buffer is half as large as input buffer since it is complex */
+			*othersize = size / 2;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		return FALSE;
+	}
+
+	return TRUE;
+	
+}
+
+/* A transform really does the same thing as the chain function */
+
+static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
+{
+	CMathCImag* element = CMATH_CIMAG(trans);
+	int bits = element -> cmath_base.bits;
+	int is_complex = element -> cmath_base.is_complex;
+
+	GstMapInfo inmap, outmap;
+	gst_buffer_map(inbuf, &inmap, GST_MAP_READ);
+	gst_buffer_map(outbuf, &outmap, GST_MAP_WRITE);
+
+	gpointer indata = inmap.data;
+	gpointer outdata = outmap.data;
+	gpointer indata_end = indata + inmap.size;
+
+	if(is_complex == 1) {
+
+		if(bits == 128) {
+			double complex *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = cimag(*ptr);
+		} else if(bits == 64) {
+			float complex *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = cimagf(*ptr);
+		} else {
+			g_assert_not_reached();
+		}
+	} else if(is_complex == 0) {
+
+		if(bits == 64) {
+			double *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = 0;
+		} else if(bits == 32) {
+			float *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = 0;
+		} else {
+			g_assert_not_reached();
+		}
+	} else {
+		g_assert_not_reached();
+	}
+
+	gst_buffer_unmap(inbuf, &inmap);
+	gst_buffer_unmap(outbuf, &outmap);
+
+	return GST_FLOW_OK;
+}
+
+
+/*
+ * ============================================================================
+ *
+ *				Type Support
+ *
+ * ============================================================================
+ */
+
+/* Initialize the plugin's class */
+static void
+cmath_cimag_class_init(gpointer klass, gpointer klass_data)
+{
+	GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS(klass);
+
+	gst_element_class_set_details_simple(GST_ELEMENT_CLASS(klass),
+		"Imaginary",
+		"Filter/Audio",
+		"Calculate imanginary part of a complex number, y = Im(x)", 
+		"Aaron Viets <aaron.viets@ligo.org>");
+
+	basetransform_class -> transform = GST_DEBUG_FUNCPTR(transform);
+	basetransform_class -> set_caps = GST_DEBUG_FUNCPTR(set_caps);
+	basetransform_class -> transform_caps = GST_DEBUG_FUNCPTR(transform_caps);
+	basetransform_class -> transform_size = GST_DEBUG_FUNCPTR(transform_size);
+}
+
+GType
+cmath_cimag_get_type(void)
+{
+	static GType type = 0;
+
+	if(!type) {
+		static const GTypeInfo info = {
+			.class_size = sizeof(CMathBaseClass),
+			.class_init = cmath_cimag_class_init,
+			.instance_size = sizeof(CMathBase),
+		};
+		type = g_type_register_static(CMATH_BASE_TYPE, "CMathCImag", &info, 0);
+	}
+
+	return type;
+}
diff --git a/gstlal-calibration/gst/cmath/cmath_creal.c b/gstlal-calibration/gst/cmath/cmath_creal.c
new file mode 100644
index 0000000000000000000000000000000000000000..cd41db49c6950ab1ff7d8f33c4a87d84f360c033
--- /dev/null
+++ b/gstlal-calibration/gst/cmath/cmath_creal.c
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2010 Leo Singer
+ * Copyright (C) 2016 Aaron Viets
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+
+#include <gst/audio/audio.h>
+#include <cmath_base.h>
+
+#define TYPE_CMATH_CREAL \
+	(cmath_creal_get_type())
+#define CMATH_CREAL(obj) \
+	(G_TYPE_CHECK_INSTANCE_CAST((obj),TYPE_CMATH_CREAL,CMathCReal))
+#define CMATH_CREAL_CLASS(klass) \
+	(G_TYPE_CHECK_CLASS_CAST((klass),TYPE_CMATH_CREAL,CMathCRealClass))
+#define IS_PLUGIN_TEMPLATE(obj) \
+	(G_TYPE_CHECK_INSTANCE_TYPE((obj),TYPE_CMATH_CREAL))
+#define IS_PLUGIN_TEMPLATE_CLASS(klass) \
+	(G_TYPE_CHECK_CLASS_TYPE((klass),TYPE_CMATH_CREAL))
+
+typedef struct _CMathCReal CMathCReal;
+typedef struct _CMathCRealClass CMathCRealClass;
+
+GType
+cmath_creal_get_type(void);
+
+struct _CMathCReal
+{
+	CMathBase cmath_base;
+};
+
+struct _CMathCRealClass 
+{
+	CMathBaseClass parent_class;
+};
+
+
+/*
+ * ============================================================================
+ *
+ *		     GstBaseTransform vmethod Implementations
+ *
+ * ============================================================================
+ */
+
+static GstCaps *transform_caps(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, GstCaps *filter)
+{
+	guint n;
+
+	caps = gst_caps_normalize(gst_caps_copy(caps));
+	GstCaps *othercaps = gst_caps_new_empty();
+
+	switch(direction) {
+	case GST_PAD_SRC:
+		/* There are two possible sink pad formats for each src pad format, so the sink pad caps has twice as many structures */
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+
+			GstStructure *str = gst_caps_get_structure(othercaps, 2 * n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z64), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(Z128), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_SINK:
+		for(n = 0; n < gst_caps_get_size(caps); n++) {
+			gst_caps_append(othercaps, gst_caps_copy_nth(caps, n));
+			GstStructure *str = gst_caps_get_structure(othercaps, n);
+			const gchar *format = gst_structure_get_string(str, "format");
+
+			if(!format) {
+				GST_DEBUG_OBJECT(trans, "unrecognized caps %" GST_PTR_FORMAT, othercaps);
+				goto error;
+			} else if(!strcmp(format, GST_AUDIO_NE(F32)) || !strcmp(format, GST_AUDIO_NE(Z64)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F32), NULL);
+			else if(!strcmp(format, GST_AUDIO_NE(F64)) || !strcmp(format, GST_AUDIO_NE(Z128)))
+				gst_structure_set(str, "format", G_TYPE_STRING, GST_AUDIO_NE(F64), NULL);
+			else {
+				GST_DEBUG_OBJECT(trans, "unrecognized format %s in %" GST_PTR_FORMAT, format, othercaps);
+				goto error;
+			}
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		goto error;
+	}
+
+	if(filter) {
+		GstCaps *intersection = gst_caps_intersect(othercaps, filter);
+		gst_caps_unref(othercaps);
+		othercaps = intersection;
+	}
+	gst_caps_unref(caps);
+	return gst_caps_simplify(othercaps);
+
+error:
+	gst_caps_unref(caps);
+	gst_caps_unref(othercaps);
+	return GST_CAPS_NONE;
+}
+
+static gboolean transform_size(GstBaseTransform *trans, GstPadDirection direction, GstCaps *caps, gsize size, GstCaps *othercaps, gsize *othersize)
+{
+	CMathCReal* element = CMATH_CREAL(trans);
+
+	int is_complex = element->cmath_base.is_complex;
+
+	switch(direction) {
+	case GST_PAD_SRC:
+		/*
+		 * We have the size of the output buffer, and we set the size of the input buffer,
+		 * which depends on the sink pad caps.
+		 */
+
+		if(is_complex) {
+			/* input buffer is twice as large as output buffer since it is complex */
+			*othersize = 2 * size;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_SINK:
+		/*
+		 * We have the size of the input buffer, and we set the size of the output buffer,
+		 * which depends on the sink pad caps..
+		 */
+
+		if(is_complex) {
+			/* output buffer is half as large as input buffer since it is complex */
+			*othersize = size / 2;
+		} else {
+			/* input and output buffers are the same size */
+			*othersize = size;
+		}
+		break;
+
+	case GST_PAD_UNKNOWN:
+		GST_ELEMENT_ERROR(trans, CORE, NEGOTIATION, (NULL), ("invalid direction GST_PAD_UNKNOWN"));
+		return FALSE;
+	}
+
+	return TRUE;
+	
+}
+
+/* A transform really does the same thing as the chain function */
+
+static GstFlowReturn transform(GstBaseTransform *trans, GstBuffer *inbuf, GstBuffer *outbuf)
+{
+	CMathCReal* element = CMATH_CREAL(trans);
+	int bits = element -> cmath_base.bits;
+	int is_complex = element -> cmath_base.is_complex;
+
+	GstMapInfo inmap, outmap;
+	gst_buffer_map(inbuf, &inmap, GST_MAP_READ);
+	gst_buffer_map(outbuf, &outmap, GST_MAP_WRITE);
+
+	gpointer indata = inmap.data;
+	gpointer outdata = outmap.data;
+	gpointer indata_end = indata + inmap.size;
+
+	if(is_complex == 1) {
+
+		if(bits == 128) {
+			double complex *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = creal(*ptr);
+		} else if(bits == 64) {
+			float complex *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = crealf(*ptr);
+		} else {
+			g_assert_not_reached();
+		}
+	} else if(is_complex == 0) {
+
+		if(bits == 64) {
+			double *ptr, *end = indata_end;
+			double *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = *ptr;
+		} else if(bits == 32) {
+			float *ptr, *end = indata_end;
+			float *outptr = outdata;
+			for(ptr = indata; ptr < end; ptr++, outptr++)
+				*outptr = *ptr;
+		} else {
+			g_assert_not_reached();
+		}
+	} else {
+		g_assert_not_reached();
+	}
+
+	gst_buffer_unmap(inbuf, &inmap);
+	gst_buffer_unmap(outbuf, &outmap);
+
+	return GST_FLOW_OK;
+}
+
+
+/*
+ * ============================================================================
+ *
+ *				Type Support
+ *
+ * ============================================================================
+ */
+
+/* Initialize the plugin's class */
+static void
+cmath_creal_class_init(gpointer klass, gpointer klass_data)
+{
+	GstBaseTransformClass *basetransform_class = GST_BASE_TRANSFORM_CLASS(klass);
+
+	gst_element_class_set_details_simple(GST_ELEMENT_CLASS(klass),
+		"Real",
+		"Filter/Audio",
+		"Calculate real part of a complex number, y = Re(x)", 
+		"Aaron Viets <aaron.viets@ligo.org>");
+
+	basetransform_class -> transform = GST_DEBUG_FUNCPTR(transform);
+	basetransform_class -> set_caps = GST_DEBUG_FUNCPTR(set_caps);
+	basetransform_class -> transform_caps = GST_DEBUG_FUNCPTR(transform_caps);
+	basetransform_class -> transform_size = GST_DEBUG_FUNCPTR(transform_size);
+}
+
+GType
+cmath_creal_get_type(void)
+{
+	static GType type = 0;
+
+	if(!type) {
+		static const GTypeInfo info = {
+			.class_size = sizeof(CMathBaseClass),
+			.class_init = cmath_creal_class_init,
+			.instance_size = sizeof(CMathBase),
+		};
+		type = g_type_register_static(CMATH_BASE_TYPE, "CMathCReal", &info, 0);
+	}
+
+	return type;
+}
diff --git a/gstlal-calibration/gst/lal/gstlal_demodulate.c b/gstlal-calibration/gst/lal/gstlal_demodulate.c
index 6320d5eb621f1aaeca588a9c2b44e5ae28b98862..ee0b5474c3fbcc04e9b78395b34d4cbb9c14db45 100644
--- a/gstlal-calibration/gst/lal/gstlal_demodulate.c
+++ b/gstlal-calibration/gst/lal/gstlal_demodulate.c
@@ -47,7 +47,6 @@
 #include <gst/gst.h>
 #include <gst/audio/audio.h>
 #include <gst/base/gstbasetransform.h>
-#include <gst/audio/audio.h>
 
 
 /*