diff --git a/ChangeLog b/ChangeLog
index f9be1d69d1228bfb28b7615db495a24f83def34b..06ae02cfecdfe5f2451619755a7c5e5be79e7412 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -58,6 +58,19 @@ print(met)
 print(met.draw_sample())
 ```
 
+New approach for sampling complex numbers
+=========================================
+
+When calling draw_sample_with_dtype with a complex dtype,
+the variance is now used for the imaginary part and real part separately.
+This is done in order to be consistent with the Hamiltonian.
+Note that by this, 
+```
+np.std(ift.from_random(domain, 'normal', dtype=np.complex128).val)
+```` 
+does not give 1, but sqrt(2) as a result.
+
+
 MPI parallelisation over samples in MetricGaussianKL
 ====================================================
 
@@ -73,6 +86,7 @@ the generation of reproducible random numbers in the presence of MPI parallelism
 and leads to cleaner code overall. Please see the documentation of
 `nifty6.random` for details.
 
+
 Interface Change for from_random and OuterProduct
 =================================================
 
diff --git a/nifty6/field.py b/nifty6/field.py
index 4c94d58d2eba2e1e4ea288bc92fd66249b8c496b..1cd9253841ba80126bd49e2c0e956316e1e6d123 100644
--- a/nifty6/field.py
+++ b/nifty6/field.py
@@ -135,6 +135,8 @@ class Field(Operator):
             The domain of the output random Field.
         dtype : type
             The datatype of the output random Field.
+            If the datatype is complex, each real and imaginary part
+            have variance 1
 
         Returns
         -------
diff --git a/nifty6/multi_field.py b/nifty6/multi_field.py
index 1051aaec7cd49a96e46e4f00c58c4257c81dd7df..e880fa9f84945befe66743fb6124e106e711c008 100644
--- a/nifty6/multi_field.py
+++ b/nifty6/multi_field.py
@@ -112,6 +112,8 @@ class MultiField(Operator):
             The domain of the output random Field.
         dtype : type
             The datatype of the output random Field.
+            If the datatype is complex, each real an imaginary part have
+            variance 1.
 
         Returns
         -------
diff --git a/nifty6/operators/energy_operators.py b/nifty6/operators/energy_operators.py
index ff05301c0072d8729945d5bbc977d48461f6fd11..21ece3648ad781d20b154722d6906baf92e0068f 100644
--- a/nifty6/operators/energy_operators.py
+++ b/nifty6/operators/energy_operators.py
@@ -27,7 +27,7 @@ from .linear_operator import LinearOperator
 from .operator import Operator
 from .sampling_enabler import SamplingDtypeSetter, SamplingEnabler
 from .scaling_operator import ScalingOperator
-from .simple_linear_operators import VdotOperator
+from .simple_linear_operators import VdotOperator, FieldAdapter
 
 
 def _check_sampling_dtype(domain, dtypes):
@@ -187,6 +187,13 @@ class GaussianEnergy(EnergyOperator):
     domain : Domain, DomainTuple, tuple of Domain or MultiDomain
         Operator domain. By default it is inferred from `mean` or
         `covariance` if specified
+    sampling_dtype : type
+        Here one can specify whether the distribution is a complex Gaussian or
+        not. Note that for a complex Gaussian the inverse_covariance is
+        .. math ::
+        (<ff^dagger>)^{-1}_P(f)/2,
+        where the additional factor of 2 is necessary because the 
+        domain of s has double as many dimensions as in the real case.
 
     Note
     ----
diff --git a/nifty6/random.py b/nifty6/random.py
index 85278324a02e7eb1472da68a30ba20aecf9236d5..82b9d718f42c774be73c37da0d53eed3a19ab470 100644
--- a/nifty6/random.py
+++ b/nifty6/random.py
@@ -238,8 +238,8 @@ class Random(object):
             raise TypeError("mean must not be complex for a real result field")
         if np.issubdtype(dtype, np.complexfloating):
             x = np.empty(shape, dtype=dtype)
-            x.real = _rng[-1].normal(mean.real, std*np.sqrt(0.5), shape)
-            x.imag = _rng[-1].normal(mean.imag, std*np.sqrt(0.5), shape)
+            x.real = _rng[-1].normal(mean.real, std, shape)
+            x.imag = _rng[-1].normal(mean.imag, std, shape)
         else:
             x = _rng[-1].normal(mean, std, shape).astype(dtype, copy=False)
         return x
diff --git a/nifty6/sugar.py b/nifty6/sugar.py
index 683b970af363b757bbceadd8ec4c5eb140705b2a..d384af8598828dd7fc27132a9f9e8bb2d4c418bc 100644
--- a/nifty6/sugar.py
+++ b/nifty6/sugar.py
@@ -266,6 +266,8 @@ def from_random(domain, random_type='normal', dtype=np.float64, **kwargs):
             The random distribution to use.
     dtype : type
         data type of the output field (e.g. numpy.float64)
+        If the datatype is complex, each real an imaginary part have
+        variance 1.
     **kwargs : additional parameters for the random distribution
         ('mean' and 'std' for 'normal', 'low' and 'high' for 'uniform')
 
diff --git a/test/test_operators/test_complex_consistency.py b/test/test_operators/test_complex_consistency.py
new file mode 100644
index 0000000000000000000000000000000000000000..dbb34fb303a86ed10f493d93022a99011eb71078
--- /dev/null
+++ b/test/test_operators/test_complex_consistency.py
@@ -0,0 +1,77 @@
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+# Copyright(C) 2013-2020 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
+
+import numpy as np
+import pytest
+
+import nifty6 as ift
+
+from ..common import list2fixture, setup_function, teardown_function
+from scipy.stats import norm
+
+
+Nsamp = 20000
+np.random.seed(42)
+
+def _to_array(d):
+    if isinstance(d, np.ndarray):
+        return d
+    assert isinstance(d, dict)
+    return np.concatenate(list(d.values()))
+
+
+def test_GaussianEnergy():
+    sp = ift.UnstructuredDomain(Nsamp)
+    S = ift.ScalingOperator(sp, 1.)
+    samp = S.draw_sample_with_dtype(dtype=np.complex128)
+    real_std = np.std(samp.val.real)
+    imag_std = np.std(samp.val.imag)
+    np.testing.assert_allclose(real_std, imag_std, 
+            atol=5./np.sqrt(Nsamp))
+    sp1 = ift.UnstructuredDomain(1)
+    mean = ift.full(sp1, 0.)
+    real_icov = ift.ScalingOperator(sp1, real_std**(-2))
+    imag_icov = ift.ScalingOperator(sp1, imag_std**(-2))
+    real_energy = ift.GaussianEnergy(mean, inverse_covariance=real_icov)
+    imag_energy = ift.GaussianEnergy(mean, inverse_covariance=imag_icov)
+    icov = ift.ScalingOperator(sp1, 1.)
+    complex_energy = ift.GaussianEnergy(mean+0.j, inverse_covariance=icov)
+    for i in range(min(10, Nsamp)):
+        fld = ift.full(sp1, samp.val[i])
+        val1 = (real_energy(fld.real) + imag_energy(fld.imag)).val
+        val2 = complex_energy(fld).val
+        np.testing.assert_allclose(val1, val2, atol=10./np.sqrt(Nsamp))
+
+
+def test_WienerFilter():
+    sp = ift.UnstructuredDomain(30)
+    S = ift.ScalingOperator(sp, 1.)
+    R = ift.ContractionOperator(sp, None)
+    N = ift.ScalingOperator(R.target, 1/5**2)
+    IC = ift.GradientNormController(iteration_limit=10, tol_abs_gradnorm=1e-7)
+    D = ift.WienerFilterCurvature(R, N, S, IC, IC).inverse
+    s = S.draw_sample_with_dtype(dtype=np.complex128)
+    d = R(s)+N.draw_sample_with_dtype(dtype=np.complex128)
+    j = R.adjoint_times(N.inverse_times(d))
+    m = D(j)
+    sr = s.real
+    jr = j.real
+    mr = D(jr)
+    si = s.imag
+    ji = j.imag
+    mi = D(ji)
+    np.testing.assert_allclose((mr+mi*1.j).val, m.val, rtol=1e-7)
diff --git a/test/test_operators/test_fisher_metric.py b/test/test_operators/test_fisher_metric.py
new file mode 100644
index 0000000000000000000000000000000000000000..bacb89244f0418a9888929e04e52aaaf400fd435
--- /dev/null
+++ b/test/test_operators/test_fisher_metric.py
@@ -0,0 +1,107 @@
+# 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 3 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, see <http://www.gnu.org/licenses/>.
+#
+# Copyright(C) 2013-2020 Max-Planck-Society
+#
+# NIFTy is being developed at the Max-Planck-Institut fuer Astrophysik.
+
+import numpy as np
+import pytest
+
+import nifty6 as ift
+
+from ..common import list2fixture, setup_function, teardown_function
+
+spaces = [ift.GLSpace(5),
+          (ift.RGSpace(3, distances=.789), ift.UnstructuredDomain(2))]
+pmp = pytest.mark.parametrize
+field = list2fixture([ift.from_random(sp, 'normal') for sp in spaces] +
+        [ift.from_random(sp, 'normal', dtype=np.complex128) for sp in spaces])
+
+Nsamp = 2000
+np.random.seed(42)
+
+def _to_array(d):
+    if isinstance(d, np.ndarray):
+        return d
+    assert isinstance(d, dict)
+    return np.concatenate(list(d.values()))
+
+def _complex2real(sp):
+    tup = tuple([d for d in sp])
+    rsp = ift.DomainTuple.make((ift.UnstructuredDomain(2),) + tup)
+    rl = ift.DomainTupleFieldInserter(rsp, 0, (0,))
+    im = ift.DomainTupleFieldInserter(rsp, 0, (1,))
+    x = ift.ScalingOperator(sp, 1)
+    return rl(x.real)+im(x.imag)
+
+def test_complex2real():
+    sp = ift.UnstructuredDomain(3)
+    op = _complex2real(ift.makeDomain(sp))
+    f = ift.from_random(op.domain, 'normal', dtype=np.complex128)
+    assert np.all((f == op.adjoint_times(op(f))).val)
+    assert op(f).dtype == np.float64
+    f = ift.from_random(op.target, 'normal')
+    assert np.all((f == op(op.adjoint_times(f))).val)
+    
+def energy_tester_complex(pos, get_noisy_data, energy_initializer):
+    op = _complex2real(pos.domain)
+    npos = op(pos)
+    nget_noisy_data = lambda mean : get_noisy_data(op.adjoint_times(mean))
+    nenergy_initializer = lambda mean : energy_initializer(mean) @ op.adjoint
+    energy_tester(npos, nget_noisy_data, nenergy_initializer)
+
+def energy_tester(pos, get_noisy_data, energy_initializer):
+    if np.issubdtype(pos.dtype, np.complexfloating):
+        energy_tester_complex(pos, get_noisy_data, energy_initializer)
+        return
+    domain = pos.domain
+    test_vec = ift.from_random(domain, 'normal')
+    results = []
+    lin = ift.Linearization.make_var(pos)
+    for i in range(Nsamp):
+        data = get_noisy_data(pos)
+        energy = energy_initializer(data)
+        grad = energy(lin).jac.adjoint(ift.full(energy.target, 1.))
+        results.append(_to_array((grad*grad.s_vdot(test_vec)).val))
+    print(energy)
+    print(grad)
+    res = np.mean(np.array(results), axis=0)
+    std = np.std(np.array(results), axis=0)/np.sqrt(Nsamp)
+    energy = energy_initializer(data)
+    lin = ift.Linearization.make_var(pos, want_metric=True)
+    res2 = _to_array(energy(lin).metric(test_vec).val)
+    np.testing.assert_allclose(res/std, res2/std, atol=6)
+
+def test_GaussianEnergy(field):
+    dtype = field.dtype
+
+    icov = ift.from_random(field.domain, 'normal')**2
+    icov = ift.makeOp(icov)
+    get_noisy_data = lambda mean : mean + icov.draw_sample_with_dtype(
+            from_inverse=True, dtype=dtype)
+    E_init = lambda mean : ift.GaussianEnergy(mean=mean,
+            inverse_covariance=icov)
+    energy_tester(field, get_noisy_data, E_init)
+
+def test_PoissonEnergy(field):
+    if not isinstance(field, ift.Field):
+        return
+    if np.iscomplexobj(field.val):
+        return
+    def get_noisy_data(mean):
+        return ift.makeField(mean.domain, np.random.poisson(mean.val))
+    lam = 10*(field**2).clip(0.1,None) # make rate positive and high enough to avoid bad statistic
+    E_init = lambda mean : ift.PoissonianEnergy(mean)
+    energy_tester(lam, get_noisy_data, E_init)
+