diff --git a/src/client/widgets/sky/sky.c b/src/client/widgets/sky/sky.c
index 2a858a1659e6b45b34ea1069aac743c33621a8a0..74e4bec2fb52c2803ee20995ef4d7115a2716f09 100644
--- a/src/client/widgets/sky/sky.c
+++ b/src/client/widgets/sky/sky.c
@@ -2210,7 +2210,7 @@ static gboolean sky_configure_event_cb(GtkWidget *w,
 							   width, height);
 
 	sky_update_coord_hor((gpointer) p);
-	sky_try_plot(w);
+	sky_plot(w);
 
 exit:
 	return TRUE;
diff --git a/src/server/backends/SIM/rt_sim.c b/src/server/backends/SIM/rt_sim.c
index d5f5e3709698f2cf0f6c809f448bcdc6d578d165..d6d95374cd4bd02993889882e092c5dcd0d2e4f1 100644
--- a/src/server/backends/SIM/rt_sim.c
+++ b/src/server/backends/SIM/rt_sim.c
@@ -45,6 +45,11 @@
 #define CONFDIR "config/"
 #endif
 
+#ifndef SYSCONFDIR
+#define SYSCONFDIR "config/"
+#endif
+
+
 /* cant use doppler_freq() (would be non-constant init)*/
 #define DOPPLER_FREQ(vel, ref)     ((ref) * (1.0 - (vel) / 299790.0))
 #define DOPPLER_FREQ_REL(vel, ref) ((vel) * (       ref ) / 299790.0)
@@ -586,7 +591,7 @@ static void sim_render_sky(const gdouble *amp, gsize len)
 		pix[1] = 255;
 		pix += nc;
 
-//		if (i > 1 && i 
+//		if (i > 1 && i
 
 	}
 #endif
@@ -836,7 +841,7 @@ static	double *conv2;
 	g_free(conv2);
 		conv2 = g_malloc(bins * bins * sizeof(double));
 		int j;
-		for (i = 0; i < (int) bins; i++) 
+		for (i = 0; i < (int) bins; i++)
 			for (j = 0; j < (int) bins; j++) {
 				conv2[i* (int) bins + j] = (conv[i] + conv[j]) / norm;
 			}
@@ -927,15 +932,21 @@ static	double *conv2;
 	return res;
 }
 
+/**
+ * @brief transpose a two-dimensional array of complex doubles
+ *
+ * @param out the output array
+ * @param in the input array
+ *
+ * @param w the width of the input array
+ * @param h the height of the input array
+ */
 
-
-static void sky_ctransp(complex double *out, complex double *in, int w, int h)
+static void transpose(complex double *out, complex double *in, int w, int h)
 {
 	int i, j, n;
 
-
 #pragma omp parallel for private(i), private(j)
-
 	for(n = 0; n < w * h; n++) {
 
 		i = n / h;
@@ -945,22 +956,173 @@ static void sky_ctransp(complex double *out, complex double *in, int w, int h)
 	}
 }
 
+/**
+ * @brief put one image into another image cyclically
+ *
+ * @param dst the destination matrix
+ * @param dw the width of the destination
+ * @param dh the height of the destination
+ *
+ * @param src the source matrix
+ * @param sw the width of the source
+ * @param sh the height of the source
+ *
+ * @param x the upper left corner destination x coordinate
+ * @param y the upper left corner destination y coordinate
+ *
+ * @returns 0 on success, otherwise error
+ *
+ * @note src must be smaller or equal dst; src will wrap within dst,
+ *	 x and y are taken as mod w and mod h respectively
+ */
+
+static int put_matrix(double complex *dst, int dw, int dh,
+		      const double  *src, int sw, int sh,
+		      int x, int y)
+{
+	int i, j;
+	int dx, dy;
+
+
+	if (!dst || !src)
+		return -1;
+
+	if ((dw < sw) || (dh < sh))
+		return -1;
+
+
+#pragma omp parallel for private(dy)
+	for (i = 0; i < sh; i++) {
+
+		dy = y + i;
+
+		/* fold into dest height */
+		if (dy < 0 || dy > dh)
+			dy = (dy + dh) % dh;
+
+#pragma omp parallel for private(dx)
+		for (j = 0; j < sw; j++) {
+
+			dx = x + j;
+
+			/* fold into dest width */
+			if (dx < 0 || dx > dw)
+				dx = (dx + dw) % dw;
+
+			dst[dy * dw + dx] =  src[i * sw + j];
+		}
+	}
+
+	return 0;
+}
+
 
 /**
- * @brief transpose a two-dimensional array of complex doubles
+ * @brief get one image from another image cyclically
+ *
+ * @param dst the destination matrix
+ * @param dw the width of the destination
+ * @param dh the height of the destination
+ *
+ * @param src the source matrix
+ * @param sw the width of the source area
+ * @param sh the height of the source area
+ *
+ * @param x the upper left corner source area x coordinate
+ * @param y the upper left corner source area y coordinate
+ * @param w the source area width
+ * @param h the source area height
+ *
+ * @returns 0 on success, otherwise error
+ *
+ * @note dst must be larger or equal src
+ *       the upper left corner of the sleected area area will be placed at 0,0
+ *       within dst
+ *       the src area will wrap within src, as x an y are taken as mod w and
+ *       mod h respectively for both source and destination
  */
 
-static void sky_ctransp2(complex double *out, complex double *in, int w, int h)
+static int get_matrix(double *dst, int dw, int dh,
+		      const double complex *src, int sw, int sh,
+		      int x, int y, int w, int h)
 {
-        int i, j;
+	int i, j;
+	int sx, sy;
 
-#pragma omp parallel for
-        for (j = 0; j < h; j++) {
-#pragma omp parallel for
-                for (i = 0; i < w; i++) {
-                        out[i * h + j] = in[j * w + i];
+
+	if (!dst || !src)
+		return -1;
+
+	if ((dw < w) || (dh < h))
+		return -1;
+
+	if ((w > sw) || (h > sh))
+		return -1;
+
+
+#pragma omp parallel for private(sy)
+	for (i = 0; i < h; i++) {
+
+		sy = y +i;
+
+		/* fold into src height */
+		if (sy < 0 || sy > sh)
+			sy = (sy + sh) % sh;
+
+#pragma omp parallel for private(sx)
+		for (j = 0; j < w; j++) {
+
+			sx  = x + j;
+
+			/* fold into src width */
+			if (sx < 0 || sx > sw)
+				sx = (sx + sw) % sw;
+
+			dst[i * dw + j] = creal(src[sy * sw + sx]);
 		}
 	}
+
+	return 0;
+}
+
+
+/**
+ * @brief in-place perform a two-dimensional fft on data
+ *
+ * @param data the data matrix to transform
+ * @param coeff a precomputed coefficient array, may be NULL
+ * @param n the fft size
+ *
+ * @note the data and coefficient array dimensions must match the fft size
+ *
+ * @returns 0 on succes, otherwise error
+ */
+
+static int fft2d(double complex *data, double complex *coeff, int n)
+{
+	int i;
+	double complex *tmp;
+
+
+	tmp = malloc(n * n * sizeof(double complex));
+	if (!tmp)
+		return -1;
+	/* inverse transform rows */
+#pragma omp parallel for
+	for (i = 0; i < n; i++)
+		fft2(&data[i * n], coeff, n, FFT_INVERSE);
+
+	/* transpose forward */
+	transpose(tmp, data, n, n);
+
+	/* inverse transform columns */
+#pragma omp parallel for
+	for (i = 0; i < n; i++)
+		fft2(&tmp[i * n], coeff, n, FFT_INVERSE);
+
+	memcpy(data, tmp, n * n * sizeof(double complex));
+
+	return 0;
 }
 
 
@@ -1033,7 +1195,6 @@ static gdouble *sim_rt_get_HI_img(gint vmin, gint vmax)
  * @note bins is always uneven (need center bin)
  */
 
-
 static gdouble *gauss_conv_kernel(gdouble r, gdouble sigma, gdouble res,
 				  gint *n)
 {
@@ -1126,201 +1287,66 @@ static gdouble *gauss_conv_kernel(gdouble r, gdouble sigma, gdouble res,
  *	  sigma cutoff and resolution in degrees
  *
  * @note bins is always uneven (need center bin)
+ *
+ * @note this does not integrate the gaussian within a "pixel", i.e. with
+ *	 respect to the integer coordinates between sample locations, so this
+ *	 is technically not a correct convolution kernel; doing so would be
+ *	 quite expensive, since we'd have to oversample the grid quite a lot
+ *	 (for no added visual benefit)
  */
 
-
-static gdouble *gauss_2d(gdouble r, gdouble sigma, gdouble res,
-				  gint *n)
+static gdouble *gauss_2d(gdouble r, gdouble sigma, gdouble res, gint *n)
 {
 	gint i, j;
 	gint bins;
 
 	gdouble x;
-	gdouble x0;
-	gdouble x1;
 
 	gdouble binw;
 
-	gdouble tot;
+	gdouble sum;
 	gdouble norm;
 
-	double *conv2;
-
+	gdouble *ker;
 
 
 	/* our width-normalised kernel runs from -sigma to +sigma */
-	x1 = sigma / 2.0 * sqrt(2.0 * log(2.0)) * r;
-	x0 = - x1;
-	x  = x0;
+	x = sigma / 2.0 * sqrt(2.0 * log(2.0)) * r;
 
 	/* need an extra center bin, does not count towards stepsize */
-	bins = (gint) (round((x1 - x0) / res));
+	bins = (gint) (round((2.0 * x) / res));
 
 	if (!(bins & 0x1))
 	    bins++;
 
 
-	binw = (x1 - x0) / ((gdouble) (bins - 1));
-
+	ker = g_malloc(bins * bins * sizeof(double));
 
-
-	/* 2d kernel */
-	conv2 = g_malloc(bins * bins * sizeof(double));
-	norm = 2.0 * tot * bins;
-
-	tot = 0.0;
+	sum = 0.0;
 
 	for (i = 0; i < bins; i++) {
 		for (j = 0; j < bins; j++)  {
 
-		gdouble s;
-		gdouble intg;
-		gdouble prev;
-
-		s = (double)bins / sqrt(((bins/2 - j) * (bins/2 -j)  + (bins/2 - i) * (bins/2 -i)));
-//		s = (x - binw * 0.5) / s;
-//			 g_message("s2 %g", s);
-
-
-		conv2[i * bins + j] = 0.5 * ((gauss_norm(s, r)));
-
-		x += binw;
-	}}
-
-
-	(*n) = bins;
-
-	return conv2;
-}
-
-
-/**
- * @brief put one image into another image cyclically
- *
- * @param dst the destination matrix
- * @param dw the width of the destination
- * @param dh the height of the destination
- *
- * @param src the source matrix
- * @param sw the width of the source
- * @param sh the height of the source
- *
- * @param x the upper left corner destination x coordinate
- * @param y the upper left corner destination y coordinate
- *
- * @returns 0 on success, otherwise error
- *
- * @note src must be smaller or equal dst; src will wrap within dst,
- *	 x and y are taken as mod w and mod h respectively
- */
-
-static gint sky_put_matrix(double complex *dst, gint dw, gint dh,
-			   const double  *src, gint sw, gint sh,
-			   gint x, gint y)
-{
-	gint i, j;
-	gint dx, dy;
-
+			gdouble s;
 
-	if (!dst || !src)
-		return -1;
-
-	if ((dw < sw) || (dh < sh))
-		return -1;
-
-
-#pragma omp parallel for private(dy)
-	for (i = 0; i < sh; i++) {
-
-		dy = y + i;
-
-		/* fold into dest height */
-		if (dy < 0 || dy > dh)
-			dy = (dy + dh) % dh;
-
-#pragma omp parallel for private(dx)
-		for (j = 0; j < sw; j++) {
-
-			dx = x + j;
-
-			/* fold into dest width */
-			if (dx < 0 || dx > dw)
-				dx = (dx + dw) % dw;
+			/* calculate norm and scale to resolution, take 1/2
+			 * for symmetry (we go from x0 to x1)
+			 */
+			s = 0.5 * res * euclid_norm((i - bins/2), (j - bins/2));
 
-			dst[dy * dw + dx] =  src[i * sw + j];
+			ker[i * bins + j] = 0.5 * ((gauss_norm(s, r)));
+			sum += ker[i * bins + j];
 		}
 	}
 
-	return 0;
-}
-
-
-/**
- * @brief get one image from another image cyclically
- *
- * @param dst the destination matrix
- * @param dw the width of the destination
- * @param dh the height of the destination
- *
- * @param src the source matrix
- * @param sw the width of the source area
- * @param sh the height of the source area
- *
- * @param x the upper left corner source area x coordinate
- * @param y the upper left corner source area y coordinate
- * @param w the source area width
- * @param h the source area height
- *
- * @returns 0 on success, otherwise error
- *
- * @note dst must be larger or equal src
- *       the upper left corner of the sleected area area will be placed at 0,0
- *       within dst
- *       the src area will wrap within src, as x an y are taken as mod w and
- *       mod h respectively for both source and destination
- */
-
-static gint sky_get_matrix(double *dst, gint dw, gint dh,
-			   const double complex *src, gint sw, gint sh,
-			   gint x, gint y, gint w, gint h)
-{
-	gint i, j;
-	gint sx, sy;
-
-
-	if (!dst || !src)
-		return -1;
-
-	if ((dw < w) || (dh < h))
-		return -1;
-
-	if ((w > sw) || (h > sh))
-		return -1;
-
-
-#pragma omp parallel for private(sy)
-	for (i = 0; i < h; i++) {
-
-		sy = y +i;
-
-		/* fold into src height */
-		if (sy < 0 || sy > sh)
-			sy = (sy + sh) % sh;
-
-#pragma omp parallel for private(sx)
-		for (j = 0; j < w; j++) {
-
-			sx  = x + j;
+	/* normalise kernel */
+	for (i = 0; i < bins; i++)
+		ker[i] /= sum;
 
-			/* fold into src width */
-			if (sx < 0 || sx > sw)
-				sx = (sx + sw) % sw;
 
-			dst[i * dw + j] = creal(src[sy * sw + sx]);
-		}
-	}
+	(*n) = bins;
 
-	return 0;
+	return ker;
 }
 
 
@@ -1334,65 +1360,6 @@ static double complex *it;
 #define SKY1_WIDTH  1024
 #define SKY1_HEIGHT 1024
 
-static gdouble *sky_convolve_dft(const double complex *sky, const double complex *ker, gint n)
-{
-	double complex *csk;
-	double complex *tmp;
-
-	double *img;
-
-	gint i, j;
-
-	GTimer *t;
-
-
-
-
-	tmp = g_malloc(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
-	csk = g_malloc(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
-
-	img = g_malloc(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double));
-
-
-
-
-	/* 0.0033 */
-	/* convolve */
-#pragma omp parallel for
-   	for (j = 0; j < SKY1_HEIGHT * SKY1_WIDTH; j++)
-		csk[j] = sky[j] * ker[j];
-
-
-
-	/* 0.008347 */
-	/* inverse transform */
-#pragma omp parallel for
-	for (j = 0; j < SKY1_WIDTH; j++)
-		fft2(&csk[j * SKY1_HEIGHT], it, SKY1_HEIGHT, FFT_INVERSE);
-
-	/* 0.009 */
-	/* transpose forward */
-	sky_ctransp(tmp, csk, SKY1_WIDTH, SKY1_HEIGHT);
-
-
-	/* 0.008347 */
-#pragma omp parallel for
-	for (j = 0; j < SKY1_HEIGHT; j++)
-		fft2(&tmp[j * SKY1_WIDTH], it, SKY1_WIDTH, FFT_INVERSE);
-
-
-
-	/* 0.000505 */
-	sky_get_matrix(img, SKY_WIDTH, SKY_HEIGHT, tmp, SKY1_WIDTH, SKY1_HEIGHT, 0, 0, SKY_WIDTH, SKY_HEIGHT);
-
-
-	g_free(tmp);
-	g_free(csk);
-
-
-
-	return img;
-}
 
 
 static gdouble *sky_convolve(const gdouble *sky, gdouble *kernel, gint n)
@@ -1437,12 +1404,10 @@ static gdouble *sky_convolve(const gdouble *sky, gdouble *kernel, gint n)
 				}
 			}
 			csky[y * SKY_WIDTH + x] = sig;
-
 		}
 	}
 
 	return csky;
-
 }
 
 
@@ -1452,6 +1417,7 @@ static gdouble *sky_convolve(const gdouble *sky, gdouble *kernel, gint n)
 
 static double complex *ker;
 static double complex *csky;
+static double complex *conv;
 static gdouble *msky;
 static gdouble *raw_sky;
 static gdouble *kernel;
@@ -1503,9 +1469,6 @@ static void sim_gen_sky(void)
 		it = fft_prepare_coeff(1024, FFT_INVERSE);
 
 
-
-#if 1
-	/** XXX */
 	v1  = gtk_spin_button_get_value_as_int(sim.gui.sb_vmin);
 	v2  = gtk_spin_button_get_value_as_int(sim.gui.sb_vmax);
 
@@ -1520,6 +1483,9 @@ static void sim_gen_sky(void)
 		vmax = v2;
 	}
 
+	if (!conv)
+		conv = g_malloc(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
+
 	if (!raw_sky) {
 		raw_sky = sim_rt_get_HI_img(vmin, vmax);
 
@@ -1532,60 +1498,49 @@ static void sim_gen_sky(void)
 		double complex *tmp = g_malloc0(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
 
 
-		sky_put_matrix(csky, SKY1_WIDTH, SKY1_HEIGHT, raw_sky, SKY_WIDTH, SKY_HEIGHT, 0, 0);
-#pragma omp parallel for
-		for (int j = 0; j < SKY1_HEIGHT; j++)
-			fft2(&csky[j * SKY1_WIDTH], ft, SKY1_WIDTH, FFT_FORWARD);
+		put_matrix(csky, SKY1_WIDTH, SKY1_HEIGHT, raw_sky, SKY_WIDTH, SKY_HEIGHT, 0, 0);
 
-		/* transpose forward */
-		sky_ctransp(tmp, csky, SKY1_HEIGHT, SKY1_WIDTH);
-
-#pragma omp parallel for
-		for (int j = 0; j < SKY1_WIDTH; j++)
-			fft2(&tmp[j * SKY1_HEIGHT], ft, SKY1_HEIGHT, FFT_FORWARD);
-
-
-		for (int j = 0; j < SKY1_HEIGHT * SKY1_WIDTH; j++)
-			csky[j] = tmp[j];
+		fft2d(csky, ft, SKY1_WIDTH);
 	}
 
 
-#endif
+#if 1
+	kernel = gauss_2d(sim.r_beam, 3.0, SKY_BASE_RES, &n);
+#else
 	kernel = gauss_conv_kernel(sim.r_beam, 3.0, SKY_BASE_RES, &n);
-	ker = g_malloc0(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
-#if 0
 #endif
-	sky_put_matrix(ker, SKY1_WIDTH, SKY1_HEIGHT, kernel, n, n, -n/2, -n/2);
+	ker = g_malloc0(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
+
 #if 1
+	put_matrix(ker, SKY1_WIDTH, SKY1_HEIGHT, kernel, n, n, -n/2, -n/2);
+#else
+	put_matrix(ker, SKY1_WIDTH, SKY1_HEIGHT, kernel, n, n, 360 - n/2, 180 - n/2);
+#endif
+#if 0
+	msky = g_malloc(SKY_WIDTH * SKY_HEIGHT * sizeof(double));
+	get_matrix(msky, SKY_WIDTH, SKY_HEIGHT, ker, SKY1_WIDTH, SKY1_HEIGHT,
+		   0, 0, SKY_WIDTH, SKY_HEIGHT);
+	sim_render_sky(msky, SKY_WIDTH * SKY_HEIGHT);
 
-	double complex *tmp = g_malloc0(SKY1_WIDTH * SKY1_HEIGHT * sizeof(double complex));
-#pragma omp parallel for
-	for (int j = 0; j < SKY1_HEIGHT; j++)
-		fft2(&ker[j * SKY1_WIDTH], ft, SKY1_WIDTH, FFT_FORWARD);
+	return;
+#endif
+	fft2d(ker, ft, SKY1_WIDTH);
 
-	/* transpose forward */
-	sky_ctransp(tmp, ker, SKY1_HEIGHT, SKY1_WIDTH);
+	g_timer_start(timer);
 
+	/* multiplication step */
 #pragma omp parallel for
-	for (int j = 0; j < SKY1_WIDTH; j++)
-		fft2(&tmp[j * SKY1_HEIGHT], ft, SKY1_HEIGHT, FFT_FORWARD);
+	for (i = 0; i < SKY1_HEIGHT * SKY1_WIDTH; i++)
+		conv[i] = csky[i] * ker[i];
 
 
-#pragma omp parallel for
-   	for (int j = 0; j < SKY1_HEIGHT * SKY1_WIDTH; j++)
-		ker[j] = tmp[j];
-#endif
+	fft2d(conv, it, SKY1_WIDTH);
+	msky = g_malloc(SKY_WIDTH * SKY_HEIGHT * sizeof(double));
+	get_matrix(msky, SKY_WIDTH, SKY_HEIGHT, conv, SKY1_WIDTH, SKY1_HEIGHT,
+		   0, 0, SKY_WIDTH, SKY_HEIGHT);
 
 
-	g_timer_start(timer);
-#if 0
-	if (!msky)
-		msky = sky_convolve(raw_sky, kernel, n);
-#else
-
-//	if (!msky)
-		msky = sky_convolve_dft(csky, ker, n);
-#endif
+	g_message("msky %g", msky[SKY_WIDTH * SKY_HEIGHT/2 + SKY_WIDTH/2]);
 
 	sim_render_sky(msky, SKY_WIDTH * SKY_HEIGHT);
 
@@ -2143,7 +2098,7 @@ static uint32_t sim_spec_acquire(struct observation *obs)
 cleanup:
 	g_free(s);
 
-	g_usleep(G_USEC_PER_SEC);
+	g_usleep(G_USEC_PER_SEC / 32);
 
 	return obs->acq.acq_max;
 }