Repository: sunpy/sunpy

Issue:
The function `sunpy.map.header_helper.make_fitswcs_header` does not check its input
<!-- This comments are hidden when you submit the issue so you do not need to remove them!
Please be sure to check out our contributing guidelines: https://github.com/sunpy/sunpy/blob/master/CONTRIBUTING.rst
Please be sure to check out our code of conduct:
https://github.com/sunpy/sunpy/blob/master/CODE_OF_CONDUCT.rst -->

<!-- Please have a search on our GitHub repository to see if a similar issue has already been posted.
If a similar issue is closed, have a quick look to see if you are satisfied by the resolution.
If not please go ahead and open an issue! -->

### Description
<!-- Provide a general description of the bug. -->
The following code
```python 
data = np.arange(0, 100).reshape(10, 10) 
coord = SkyCoord(0*u.arcsec, 0*u.arcsec, obstime='2013-10-28 08:24', observer='earth', frame=frames.Helioprojective) 
header = sunpy.map.header_helper.make_fitswcs_header(data, coord,                  reference_pixel=u.Quantity([0, 0]*u.pixel), scale=u.Quantity([2, 2]*u.arcsec/u.pixel),  instrument='Test case', detector='UV detector', wavelength=1000*u.keV ) 
```
returns the following
```python 
MetaDict([('wcsaxes', 2),
          ('crpix1', 0.0),
          ('crpix2', 0.0),
          ('cdelt1', 2.0),
          ('cdelt2', 2.0),
          ('cunit1', 'arcsec'),
          ('cunit2', 'arcsec'),
          ('ctype1', 'HPLN-TAN'),
          ('ctype2', 'HPLT-TAN'),
          ('crval1', 0.0),
          ('crval2', 0.0),
          ('lonpole', 180.0),
          ('latpole', 0.0),
          ('date-obs', '2013-10-28T08:24:00.000'),
          ('hgln_obs', 0.0),
          ('hglt_obs', 4.737769391892908),
          ('dsun_obs', 148630941339.4927),
          ('rsun_ref', 695700.0),
          ('rsun_obs', 965.4610032771359),
          ('instrume', 'Test case'),
          ('wavelnth', <Quantity 1000. keV>),
          ('detector', 'UV detector')])
```
### Expected behavior
<!-- What did you expect to happen. -->
All items in the `MetaDict` should be strings and the function should accept a Quantity wavelength. Also, would recommend to remove the `waveunit` keyword completely and only accept quantities on input for wavelength.

### Actual behavior
<!-- What actually happened. -->
<!-- Was the output confusing or poorly described? -->
The Quantity object was returned as an item of the `MetaDict`.

### Steps to Reproduce
<!-- Ideally a code example could be provided so we can run it ourselves. -->
<!-- If you are pasting code, use tripe backticks (```) around your code snippet. -->

See above.

### System Details
<!-- We at least need to know the SunPy version you are using. -->
<!-- We provide a short function in SunPy that will provide some of the below information. -->
<!-- It is sunpy.util.system_info(), this is optional but strongly recommended. -->
  - SunPy Version: '1.0.0.dev1816+g04db428b6.d20190531'
  - Python Version: 3.6.8
  - OS information: OS X



Discussion:

Resolving patch:
diff --git a/examples/map/map_from_numpy_array.py b/examples/map/map_from_numpy_array.py
--- a/examples/map/map_from_numpy_array.py
+++ b/examples/map/map_from_numpy_array.py
@@ -34,8 +34,8 @@
 header = sunpy.map.header_helper.make_fitswcs_header(data, coord,
                                                      reference_pixel=u.Quantity([0, 0]*u.pixel),
                                                      scale=u.Quantity([2, 2]*u.arcsec/u.pixel),
-                                                     instrument='Test case', detector='UV detector',
-                                                     wavelength=1000, waveunit='angstrom')
+                                                     telescope='Fake Telescope', instrument='UV detector',
+                                                     wavelength=1000*u.angstrom)
 
 ##############################################################################
 # Let's now create our map.
diff --git a/sunpy/map/header_helper.py b/sunpy/map/header_helper.py
--- a/sunpy/map/header_helper.py
+++ b/sunpy/map/header_helper.py
@@ -30,12 +30,13 @@ def meta_keywords():
     return _map_meta_keywords
 
 
-@u.quantity_input
+@u.quantity_input(equivalencies=u.spectral())
 def make_fitswcs_header(data, coordinate, reference_pixel: u.pix = None,
                         scale: u.arcsec/u.pix = None,
                         rotation_angle: u.deg = None,
-                        rotation_matrix=None,
-                        **kwargs):
+                        rotation_matrix=None, instrument=None,
+                        telescope=None, observatory=None,
+                        wavelength: u.angstrom=None, exposure: u.s=None):
     """
     Function to create a FITS-WCS header from a coordinate object
     (`~astropy.coordinates.SkyCoord`) that is required to
@@ -63,17 +64,17 @@ def make_fitswcs_header(data, coordinate, reference_pixel: u.pix = None,
         Matrix describing the rotation required to align solar North with
         the top of the image in FITS ``PCi_j`` convention. Can not be specified
         with ``rotation_angle``.
-    **kwargs:
-        Additional arguments that will be put into the metadict header if they
-        are in the list returned by `~sunpy.map.meta_keywords`. Additional
-        keyword arguments for the instrument meta can also be given in the
-        following forms which will be translated to fits standard:
-
-        | ``instrument``
-        | ``telescope``
-        | ``observatory``
-        | ``wavelength``
-        | ``exposure``
+    instrument : `~str`, optional
+        Name of the instrument of the observation.
+    telescope : `~str`, optional
+        Name of the telescope of the observation.
+    observatory : `~str`, optional
+        Name of the observatory of the observation.
+    wavelength : `~u.Quantity`, optional
+        Wavelength of the observation as an astropy quanitity, e.g. 171*u.angstrom.
+        From this keyword, the meta keywords ``wavelnth`` and ``waveunit`` will be populated.
+    exposure : `~u.Quantity`, optional
+        Exposure time of the observation
 
     Returns
     -------
@@ -113,7 +114,7 @@ def make_fitswcs_header(data, coordinate, reference_pixel: u.pix = None,
         meta_observer = _get_observer_meta(coordinate)
         meta_wcs.update(meta_observer)
 
-    meta_instrument = _get_instrument_meta(**kwargs)
+    meta_instrument = _get_instrument_meta(instrument, telescope, observatory, wavelength, exposure)
     meta_wcs.update(meta_instrument)
 
     if reference_pixel is None:
@@ -147,10 +148,6 @@ def make_fitswcs_header(data, coordinate, reference_pixel: u.pix = None,
 
     meta_dict = MetaDict(meta_wcs)
 
-    for key in kwargs:
-        if key in _map_meta_keywords:
-            meta_dict[key] = kwargs[key]
-
     return meta_dict
 
 
@@ -210,19 +207,23 @@ def _get_observer_meta(coordinate):
     return coord_meta
 
 
-def _get_instrument_meta(**kwargs):
+def _get_instrument_meta(instrument, telescope, observatory, wavelength, exposure):
     """
-    Function to correctly name keywords from kwargs
+    Function to correctly name keywords from keyword arguments
     """
     coord = {}
 
-    conversion = {'instrument': 'instrume', 'telescope': 'telescop',
-                  'observatory': 'obsrvtry', 'wavelength': 'wavelnth', 'exposure': 'exptime'}
-
-    kwargs_temp = kwargs.copy()
-    for key in kwargs_temp:
-        if key in conversion:
-            coord[conversion[key]] = kwargs.pop(key)
+    if instrument is not None:
+        coord['instrume'] = str(instrument)
+    if telescope is not None:
+        coord['telescop'] = str(telescope)
+    if observatory is not None:
+        coord['obsrvtry'] = str(observatory)
+    if wavelength is not None:
+        coord['wavelnth'] = wavelength.to_value()
+        coord['waveunit'] = wavelength.unit.to_string("fits")
+    if exposure is not None:
+        coord['exptime'] = exposure.to_value(u.s)
 
     return coord
 


Test patch: