def setup_method(self, method):
     gaussian = components1d.Gaussian()
     gaussian.A.value = 10
     gaussian.centre.value = 10
     gaussian.sigma.value = 1
     self.signal = signals.Signal1D(
         gaussian.function(np.arange(0, 20, 0.01)))
     self.signal.axes_manager[0].scale = 0.01
 def setUp(self):
     gaussian = components1d.Gaussian()
     gaussian.A.value = 10
     gaussian.centre.value = 10
     gaussian.sigma.value = 1
     self.signal = signals.Signal1D(
         gaussian.function(np.arange(0, 20, 0.01)))
     self.signal.axes_manager[0].scale = 0.01
     self.signal.metadata.Signal.binned = False
def get_low_loss_eels_signal(add_noise=True, random_state=None):
    """Get an artificial low loss electron energy loss spectrum.

    The zero loss peak is offset by 4.1 eV.

    Parameters
    ----------
    %s

    %s

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_core_loss_eels_signal, get_core_loss_eels_model,
    get_low_loss_eels_line_scan_signal, get_core_loss_eels_line_scan_signal

    """

    random_state = check_random_state(random_state)

    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data = zero_loss.function(x)
    data += plasmon.function(x)
    if add_noise:
        data += random_state.uniform(size=len(x)) * 0.7

    s = signals.EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.axes_manager[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #4
0
def get_low_loss_eels_line_scan_signal():
    """Get an artificial low loss electron energy loss line scan spectrum.

    The zero loss peak is offset by 4.1 eV.

    Returns
    -------
    artificial_low_loss_line_scan_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_core_loss_eels_signal : get a core loss signal
    get_core_loss_eels_model : get a core loss model
    get_core_loss_eels_line_scan_signal : core loss signal with the same size

    """
    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data_signal = zero_loss.function(x)
    data_signal += plasmon.function(x)
    data = np.zeros((12, len(x)))
    for i in range(12):
        data[i] += data_signal
        data[i] += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.axes_manager.signal_axes[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #5
0
def get_low_loss_eels_signal():
    """Get an artificial low loss electron energy loss spectrum.

    The zero loss peak is offset by 4.1 eV.

    Returns
    -------
    artificial_low_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_low_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_core_loss_eels_signal : get a core loss signal
    get_core_loss_eels_model : get a core loss model
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    x = np.arange(-100, 400, 0.5)
    zero_loss = components1d.Gaussian(A=100, centre=4.1, sigma=1)
    plasmon = components1d.Gaussian(A=100, centre=60, sigma=20)

    data = zero_loss.function(x)
    data += plasmon.function(x)
    data += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.axes_manager[0].scale = x[1] - x[0]
    s.metadata.General.title = 'Artifical low loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(
        beam_energy=200, convergence_angle=26, collection_angle=20)
    return s
Beispiel #6
0
def get_core_loss_eels_signal():
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Returns
    -------
    artificial_core_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_core_loss_eels_signal()
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """
    x = np.arange(400, 800, 1)
    arctan = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    data += np.random.random(size=len(x)) * 0.7

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #7
0
 def set_background_estimator(self):
     if self.background_type == 'Power Law':
         self.background_estimator = components1d.PowerLaw()
         self.bg_line_range = 'from_left_range'
     elif self.background_type == 'Gaussian':
         self.background_estimator = components1d.Gaussian()
         self.bg_line_range = 'full'
     elif self.background_type == 'Offset':
         self.background_estimator = components1d.Offset()
         self.bg_line_range = 'full'
     elif self.background_type == 'Polynomial':
         self.background_estimator = components1d.Polynomial(
             self.polynomial_order)
         self.bg_line_range = 'full'
Beispiel #8
0
def xray_lines_model(elements,
                     beam_energy=200,
                     weight_percents=None,
                     energy_resolution_MnKa=130,
                     energy_axis=None):
    """
    Generate a model of X-ray lines using a Gaussian distribution for each
    peak.

    The area under a main peak (alpha) is equal to 1 and weighted by the
    composition.

    Parameters
    ----------
    elements : list of strings
        A list of chemical element symbols.
    beam_energy: float
        The energy of the beam in keV.
    weight_percents: list of float
        The composition in weight percent.
    energy_resolution_MnKa: float
        The energy resolution of the detector in eV
    energy_axis: dic
        The dictionary for the energy axis. It must contains 'size' and the
        units must be 'eV' of 'keV'.

    Example
    -------
    >>> s = xray_lines_model(['Cu', 'Fe'], beam_energy=30)
    >>> s.plot()
    """
    from hyperspy._signals.eds_tem import EDSTEMSpectrum
    from hyperspy import components1d
    if energy_axis is None:
        energy_axis = {
            'name': 'E',
            'scale': 0.01,
            'units': 'keV',
            'offset': -0.1,
            'size': 1024
        }
    s = EDSTEMSpectrum(np.zeros(energy_axis['size']), axes=[energy_axis])
    s.set_microscope_parameters(beam_energy=beam_energy,
                                energy_resolution_MnKa=energy_resolution_MnKa)
    s.add_elements(elements)
    counts_rate = 1.
    live_time = 1.
    if weight_percents is None:
        weight_percents = [100. / len(elements)] * len(elements)
    m = s.create_model()
    if len(elements) == len(weight_percents):
        for (element, weight_percent) in zip(elements, weight_percents):
            for line, properties in elements_db[element]['Atomic_properties'][
                    'Xray_lines'].items():
                line_energy = properties['energy (keV)']
                ratio_line = properties['weight']
                if s._get_xray_lines_in_spectral_range([element + '_' + line
                                                        ])[1] == []:
                    g = components1d.Gaussian()
                    g.centre.value = line_energy
                    g.sigma.value = get_FWHM_at_Energy(
                        energy_resolution_MnKa, line_energy) / sigma2fwhm
                    g.A.value = live_time * counts_rate * \
                        weight_percent / 100 * ratio_line
                    m.append(g)
    else:
        raise ValueError("The number of elements specified is not the same "
                         "as the number of weight_percents")

    s.data = m.as_signal().data
    return s
Beispiel #9
0
    def add_family_lines(self, xray_lines='from_elements'):
        """Create the Xray-lines instances and configure them appropiately

        If a X-ray line is given, all the the lines of the familiy is added.
        For instance if Zn Ka is given, Zn Kb is added too. The main lines
        (alpha) is added to self.xray_lines

        Parameters
        -----------
        xray_lines: {None, 'from_elements', list of string}
            If None, if `metadata` contains `xray_lines` list of lines use
            those. If 'from_elements', add all lines from the elements contains
            in `metadata`. Alternatively, provide an iterable containing
            a list of valid X-ray lines symbols. (eg. ('Al_Ka','Zn_Ka')).
        """

        only_one = False
        only_lines = ("Ka", "La", "Ma")

        if xray_lines is None or xray_lines == 'from_elements':
            if 'Sample.xray_lines' in self.signal.metadata \
                    and xray_lines != 'from_elements':
                xray_lines = self.signal.metadata.Sample.xray_lines
            elif 'Sample.elements' in self.signal.metadata:
                xray_lines = self.signal._get_lines_from_elements(
                    self.signal.metadata.Sample.elements,
                    only_one=only_one,
                    only_lines=only_lines)
            else:
                raise ValueError(
                    "No elements defined, set them with `add_elements`")

        components_names = [xr.name for xr in self.xray_lines]
        xray_lines = filter(lambda x: x not in components_names, xray_lines)
        xray_lines, xray_not_here = self.signal.\
            _get_xray_lines_in_spectral_range(xray_lines)
        for xray in xray_not_here:
            warnings.warn("%s is not in the data energy range." % (xray))

        for xray_line in xray_lines:
            element, line = utils_eds._get_element_and_line(xray_line)
            line_energy, line_FWHM = self.signal._get_line_energy(
                xray_line, FWHM_MnKa='auto')
            component = create_component.Gaussian()
            component.centre.value = line_energy
            component.fwhm = line_FWHM
            component.centre.free = False
            component.sigma.free = False
            component.name = xray_line
            self.append(component)
            self.xray_lines.append(component)
            self[xray_line].A.map[
                'values'] = self.signal.isig[line_energy].data * \
                line_FWHM / self.signal.axes_manager[-1].scale
            self[xray_line].A.map['is_set'] = (np.ones(
                self.signal.isig[line_energy].data.shape) == 1)
            component.A.ext_force_positive = True
            for li in elements_db[element]['Atomic_properties']['Xray_lines']:
                if line[0] in li and line != li:
                    xray_sub = element + '_' + li
                    if self.signal.\
                            _get_xray_lines_in_spectral_range(
                                [xray_sub])[0] != []:
                        line_energy, line_FWHM = self.signal.\
                            _get_line_energy(
                                xray_sub, FWHM_MnKa='auto')
                        component_sub = create_component.Gaussian()
                        component_sub.centre.value = line_energy
                        component_sub.fwhm = line_FWHM
                        component_sub.centre.free = False
                        component_sub.sigma.free = False
                        component_sub.name = xray_sub
                        component_sub.A.twin_function = _get_weight(
                            element, li)
                        component_sub.A.twin_inverse_function = _get_iweight(
                            element, li)
                        component_sub.A.twin = component.A
                        self.append(component_sub)
            self.fetch_stored_values()
Beispiel #10
0
    def remove_background(self,
                          signal_range='interactive',
                          background_type='PowerLaw',
                          polynomial_order=2,
                          fast=True,
                          show_progressbar=None):
        """Remove the background, either in place using a gui or returned as a new
        spectrum using the command line.
        Parameters
        ----------
        signal_range : tuple, optional
            If this argument is not specified, the signal range has to be
            selected using a GUI. And the original spectrum will be replaced.
            If tuple is given, the a spectrum will be returned.
        background_type : string
            The type of component which should be used to fit the background.
            Possible components: PowerLaw, Gaussian, Offset, Polynomial
            If Polynomial is used, the polynomial order can be specified
        polynomial_order : int, default 2
            Specify the polynomial order if a Polynomial background is used.
        fast : bool
            If True, perform an approximative estimation of the parameters.
            If False, the signal is fitted using non-linear least squares
            afterwards.This is slower compared to the estimation but
            possibly more accurate.
        show_progressbar : None or bool
            If True, display a progress bar. If None the default is set in
            `preferences`.
        Examples
        --------
        Using gui, replaces spectrum s
        >>>> s.remove_background()
        Using command line, returns a spectrum
        >>>> s = s.remove_background(signal_range=(400,450), background_type='PowerLaw')
        Using a full model to fit the background
        >>>> s = s.remove_background(signal_range=(400,450), fast=False)
        Raises
        ------
        SignalDimensionError if the signal dimension is not 1.
        """
        self._check_signal_dimension_equals_one()
        if signal_range == 'interactive':
            br = BackgroundRemoval(self)
            br.edit_traits()
        else:
            if background_type == 'PowerLaw':
                background_estimator = components1d.PowerLaw()
            elif background_type == 'Gaussian':
                background_estimator = components1d.Gaussian()
            elif background_type == 'Offset':
                background_estimator = components1d.Offset()
            elif background_type == 'Polynomial':
                background_estimator = components1d.Polynomial(
                    polynomial_order)
            else:
                raise ValueError("Background type: " + background_type +
                                 " not recognized")

            spectra = self._remove_background_cli(
                signal_range=signal_range,
                background_estimator=background_estimator,
                fast=fast,
                show_progressbar=show_progressbar)
            return spectra
Beispiel #11
0
def get_core_loss_eels_signal(add_powerlaw=False,
                              add_noise=True,
                              random_state=None):
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Some random noise is also added to the spectrum, to simulate
    experimental noise.

    Parameters
    ----------
    %s
    %s

    %s

    Example
    -------
    >>> import hs.datasets.artifical_data as ad
    >>> s = ad.get_core_loss_eels_signal()
    >>> s.plot()

    With the powerlaw background

    >>> s = ad.get_core_loss_eels_signal(add_powerlaw=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> s1 = ad.get_core_loss_eels_signal(random_state=10)
    >>> s2 = ad.get_core_loss_eels_signal(random_state=10)
    >>> (s1.data == s2.data).all()
    True

    See also
    --------
    get_core_loss_eels_line_scan_signal, get_low_loss_eels_line_scan_signal,
    get_core_loss_eels_model

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    random_state = check_random_state(random_state)

    x = np.arange(400, 800, 1)
    arctan = components1d.EELSArctan(A=1, k=0.2, x0=688)
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    if add_noise:
        data += random_state.uniform(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #12
0
def get_core_loss_eels_line_scan_signal(add_powerlaw=False,
                                        add_noise=True,
                                        random_state=None):
    """Get an artificial core loss electron energy loss line scan spectrum.

    Similar to a Mn-L32 and Fe-L32 edge from a perovskite oxide.

    Parameters
    ----------
    %s
    %s

    %s

    Example
    -------
    >>> s = hs.datasets.artificial_data.get_core_loss_eels_line_scan_signal()
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_line_scan_signal, get_core_loss_eels_model

    """

    from hyperspy.signals import EELSSpectrum
    from hyperspy import components1d

    random_state = check_random_state(random_state)

    x = np.arange(400, 800, 1)
    arctan_mn = components1d.EELSArctan(A=1, k=0.2, x0=688)
    arctan_fe = components1d.EELSArctan(A=1, k=0.2, x0=612)
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)
    fe_l3_g = components1d.Gaussian(A=100, centre=605, sigma=4)
    fe_l2_g = components1d.Gaussian(A=10, centre=630, sigma=3)

    mn_intensity = [1, 1, 1, 1, 1, 1, 0.8, 0.5, 0.2, 0, 0, 0]
    fe_intensity = [0, 0, 0, 0, 0, 0, 0.2, 0.5, 0.8, 1, 1, 1]
    data = np.zeros((len(mn_intensity), len(x)))
    for i in range(len(mn_intensity)):
        data[i] += arctan_mn.function(x) * mn_intensity[i]
        data[i] += mn_l3_g.function(x) * mn_intensity[i]
        data[i] += mn_l2_g.function(x) * mn_intensity[i]
        data[i] += arctan_fe.function(x) * fe_intensity[i]
        data[i] += fe_l3_g.function(x) * fe_intensity[i]
        data[i] += fe_l2_g.function(x) * fe_intensity[i]
        if add_noise:
            data[i] += random_state.uniform(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function_nd(np.stack([x] * len(mn_intensity)))

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager.signal_axes[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager.signal_axes[0].name = 'Electron energy loss'
    s.axes_manager.signal_axes[0].units = 'eV'
    s.axes_manager.navigation_axes[0].name = 'Probe position'
    s.axes_manager.navigation_axes[0].units = 'nm'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s
Beispiel #13
0
def get_luminescence_signal(navigation_dimension=0,
                            uniform=False,
                            add_baseline=False,
                            add_noise=True,
                            random_state=None):
    """Get an artificial luminescence signal in wavelength scale (nm, uniform) or
    energy scale (eV, non-uniform), simulating luminescence data recorded with a
    diffracting spectrometer. Some random noise is also added to the spectrum,
    to simulate experimental noise.

    Parameters
    ----------
    navigation_dimension: positive int.
        The navigation dimension(s) of the signal. 0 = single spectrum,
        1 = linescan, 2 = spectral map etc...
    uniform: bool.
        return uniform (wavelength) or non-uniform (energy) spectrum
    add_baseline : bool
        If true, adds a constant baseline to the spectrum. Conversion to
        energy representation will turn the constant baseline into inverse
        powerlaw.
    %s

    Example
    -------
    >>> import hyperspy.datasets.artificial_data as ad
    >>> s = ad.get_luminescence_signal()
    >>> s.plot()

    With constant baseline

    >>> s = ad.get_luminescence_signal(uniform=True, add_baseline=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> s1 = ad.get_luminescence_signal(random_state=10)
    >>> s2 = ad.get_luminescence_signal(random_state=10)
    >>> (s1.data == s2.data).all()
    True

    2D map

    >>> s = ad.get_luminescence_signal(navigation_dimension=2)
    >>> s.plot()

    See also
    --------
    get_low_loss_eels_signal,
    get_core_loss_eels_signal,
    get_low_loss_eels_line_scan_signal,
    get_core_loss_eels_line_scan_signal,
    get_core_loss_eels_model,
    get_atomic_resolution_tem_signal2d,

    """

    #Initialisation of random number generator
    random_state = check_random_state(random_state)

    #Creating a uniform data axis, roughly similar to Horiba iHR320 with a 150 mm-1 grating
    nm_axis = UniformDataAxis(
        index_in_array=None,
        name="Wavelength",
        units="nm",
        navigate=False,
        size=1024,
        scale=0.54,
        offset=222.495,
        is_binned=False,
    )

    #Artificial luminescence peak
    gaussian_peak = components1d.Gaussian(A=5000, centre=375, sigma=25)

    if navigation_dimension >= 0:
        #Generate empty data (ones)
        data = np.ones([10
                        for i in range(navigation_dimension)] + [nm_axis.size])
        #Generate spatial axes
        spaxes = [
            UniformDataAxis(
                index_in_array=None,
                name="X{:d}".format(i),
                units="um",
                navigate=False,
                size=10,
                scale=2.1,
                offset=0,
                is_binned=False,
            ) for i in range(navigation_dimension)
        ]
        #Generate empty signal
        sig = signals.Signal1D(data, axes=spaxes + [nm_axis])
        sig.metadata.General.title = '{:d}d-map Artificial Luminescence Signal'\
                                        .format(navigation_dimension)
    else:
        raise ValueError("Value {:d} invalid as navigation dimension.".format(\
                            navigation_dimension))

    #Populating data array, possibly with noise and baseline
    sig.data *= gaussian_peak.function(nm_axis.axis)
    if add_noise:
        sig.data += (random_state.uniform(size=sig.data.shape) - 0.5) * 1.4
    if add_baseline:
        data += 350.

    #if not uniform, transformation into non-uniform axis
    if not uniform:
        hc = 1239.84198  #nm/eV
        #converting to non-uniform axis
        sig.axes_manager.signal_axes[0].convert_to_functional_data_axis(\
                                                              expression="a/x",
                                                              name='Energy',
                                                              units='eV',
                                                              a=hc,
                                                          )
        #Reverting the orientation of signal axis to have increasing Energy
        sig = sig.isig[::-1]
        #Jacobian transformation
        Eax = sig.axes_manager.signal_axes[0].axis
        sig *= hc / Eax**2
    return sig
Beispiel #14
0
def get_core_loss_eels_signal(add_powerlaw=False):
    """Get an artificial core loss electron energy loss spectrum.

    Similar to a Mn-L32 edge from a perovskite oxide.

    Some random noise is also added to the spectrum, to simulate
    experimental noise.

    Parameters
    ----------
    add_powerlaw : bool
        If True, adds a powerlaw background to the spectrum.
        Default False.

    Returns
    -------
    artificial_core_loss_signal : HyperSpy EELSSpectrum

    Example
    -------
    >>> import hs.datasets.artifical_data as ad
    >>> s = ad.get_core_loss_eels_signal()
    >>> s.plot()

    With the powerlaw background

    >>> s = ad.get_core_loss_eels_signal(add_powerlaw=True)
    >>> s.plot()

    To make the noise the same for multiple spectra, which can
    be useful for testing fitting routines

    >>> np.random.seed(seed=10)
    >>> s1 = ad.get_core_loss_eels_signal()
    >>> np.random.seed(seed=10)
    >>> s2 = ad.get_core_loss_eels_signal()
    >>> (s1.data == s2.data).all()
    True

    See also
    --------
    get_low_loss_eels_model : get a low loss signal
    get_core_loss_eels_model : get a model instead of a signal
    get_low_loss_eels_line_scan_signal : get EELS low loss line scan
    get_core_loss_eels_line_scan_signal : get EELS core loss line scan

    """
    x = np.arange(400, 800, 1)
    arctan = components1d.Arctan(A=1, k=0.2, x0=688)
    arctan.minimum_at_zero = True
    mn_l3_g = components1d.Gaussian(A=100, centre=695, sigma=4)
    mn_l2_g = components1d.Gaussian(A=20, centre=720, sigma=4)

    data = arctan.function(x)
    data += mn_l3_g.function(x)
    data += mn_l2_g.function(x)
    data += np.random.random(size=len(x)) * 0.7

    if add_powerlaw:
        powerlaw = components1d.PowerLaw(A=10e8, r=3, origin=0)
        data += powerlaw.function(x)

    s = EELSSpectrum(data)
    s.axes_manager[0].offset = x[0]
    s.metadata.General.title = 'Artifical core loss EEL spectrum'
    s.axes_manager[0].name = 'Electron energy loss'
    s.axes_manager[0].units = 'eV'
    s.set_microscope_parameters(beam_energy=200,
                                convergence_angle=26,
                                collection_angle=20)
    return s