Repository: sunpy/sunpy

Issue:
Confusion with Heliocentric Cartesian vs Heliocentric Radial angles
### Description
Maybe I'm missing something, but I'm looking to convert a HPC coordinate to the HCR frame. In the docs it says for HCR to use HCC with "Use a cylindrical representation, but with a 90-degree offset in psi", as this is due to the `psi` value in HCC measured from the west limb rather than solar north for HCR. 

However, when looking at the HCC coordinates it seems to map `psi` from +180, -180 rather than from 0-360, hence the offset of 90 for psi can get confusing as HCR goes from 0-360 according to the Thomson paper. 

I know this can be easily worked out what the HCR `psi` should be, but it still a little confusing and I spent a bit of time looking through the source code to figure out what was going on (and drawing many circles haha). 

Is there a way to force the HCC `psi` values to go from 0-360? If not I think that this should be clearer in the docs.

### Example
For example, I think the issue lies that even if you define a coordinate in HCC with a +180 degrees it converts e.g.
```python
>>> hcc = SkyCoord(CylindricalRepresentation(R_sun, 190*u.deg, 0*u.km),
                   frame=frames.Heliocentric(observer="earth", obstime=date))

>>> hcc.cylindrical.phi
<CylindricalRepresentation (rho, phi, z) in (m, deg, km)
    (6.957e+08, -170., 0.)>
```
So its changing the 190 degrees to -170. Naively one may assume that the HCR phi would just be a 90 degree offset from -170, whereas its actually (-170 + 360) with offset of 90. I know this is super simple as its just a circle but it took me an embarrassingly long time to figure out what was going on when I was converting HPC coords to HCC to get the HCR psi value 🤦‍♀️ .
 
### In Summary
What I'm looking for is to convert a list to HPC coords to HCR to get the `psi` values,  and my life would be easier if this `psi` value could be in 0-360 range rather than -180, 180 and this made me confused. Maybe in astropy you can easily do this with an angle? I played around the `_wrap_angle` keyword with no avail.





Discussion:
oh I just realised you can just use the `wrap_at(360*u.deg)` 

```python
>>> hcc.cylindrical.phi.wrap_at(360*u.deg)
```
and it will give you what I'm looking for. 

However just a general note - can we make this wrapping default for the HCC frame?

Resolving patch:
diff --git a/sunpy/coordinates/frames.py b/sunpy/coordinates/frames.py
--- a/sunpy/coordinates/frames.py
+++ b/sunpy/coordinates/frames.py
@@ -106,8 +106,8 @@ class SunPyBaseCoordinateFrame(BaseCoordinateFrame):
     This class is not intended to be used directly and has no transformations defined.
 
     * Defines the frame attribute ``obstime`` for observation time.
-    * Defines a default longitude wrap angle of 180 degrees, which can be overridden via the class
-      variable ``_wrap_angle``.
+    * Defines a default wrap angle of 180 degrees for longitude in spherical coordinates,
+      which can be overridden via the class variable ``_wrap_angle``.
     * Inject a nice way of representing the object which the coordinate represents.
     """
     obstime = TimeFrameAttributeSunPy()
@@ -121,7 +121,7 @@ class SunPyBaseCoordinateFrame(BaseCoordinateFrame):
                                 RepresentationMapping('d_distance', 'd_distance', u.km/u.s)],
     }
 
-    _wrap_angle = 180*u.deg
+    _wrap_angle = 180*u.deg  # for longitude in spherical coordinates
 
     def __init__(self, *args, **kwargs):
         self.object_name = None
@@ -139,20 +139,17 @@ def __init__(self, *args, **kwargs):
         return
 
     def represent_as(self, base, s='base', in_frame_units=False):
-        """
-        If a frame wrap angle is set, use that wrap angle for any spherical representations.
-        """
         data = super().represent_as(base, s, in_frame_units=in_frame_units)
+
+        # If a frame wrap angle is set, use that wrap angle for any spherical representations.
         if self._wrap_angle is not None and \
            isinstance(data, (UnitSphericalRepresentation, SphericalRepresentation)):
             data.lon.wrap_angle = self._wrap_angle
         return data
 
     def __str__(self):
-        """
-        We override this here so that when you print a SkyCoord it shows the
-        observer as the string and not the whole massive coordinate.
-        """
+        # We override this here so that when you print a SkyCoord it shows the
+        # observer as the string and not the whole massive coordinate.
         if getattr(self, "object_name", None):
             return f"<{self.__class__.__name__} Coordinate for '{self.object_name}'>"
         else:
@@ -393,6 +390,14 @@ class Heliocentric(SunPyBaseCoordinateFrame):
 
     observer = ObserverCoordinateAttribute(HeliographicStonyhurst)
 
+    def represent_as(self, base, s='base', in_frame_units=False):
+        data = super().represent_as(base, s, in_frame_units=in_frame_units)
+
+        # For cylindrical representations, wrap the `psi` component (natively `phi`) at 360 deg
+        if isinstance(data, CylindricalRepresentation):
+            data.phi.wrap_at(360*u.deg, inplace=True)
+        return data
+
 
 @add_common_docstring(**_frame_parameters())
 class Helioprojective(SunPyBaseCoordinateFrame):


Test patch:
diff --git a/sunpy/coordinates/tests/test_frames.py b/sunpy/coordinates/tests/test_frames.py
--- a/sunpy/coordinates/tests/test_frames.py
+++ b/sunpy/coordinates/tests/test_frames.py
@@ -373,6 +373,18 @@ def test_hcc_default_observer():
     assert not hcc.is_frame_attr_default('observer')
 
 
+@pytest.mark.parametrize('x, y, psi', [(0*u.km, -1*u.km, 270*u.deg),
+                                       (0*u.km, 1*u.km, 90*u.deg),
+                                       (-1*u.km, 0*u.km, 180*u.deg)])
+def test_heliocentric_radial_psi(x, y, psi):
+    # The cylindrical representation of HCC is Heliocentric Radial
+    # Test that the `psi` component is represented as desired
+    # The definition is shifted by 90 degrees relative to Thompson (2006)
+    hcc = Heliocentric(CartesianRepresentation(x, y, 0*u.km), representation_type='cylindrical')
+
+    assert_quantity_allclose(hcc.psi, psi)
+
+
 # ==============================================================================
 # SkyCoord Tests
 # ==============================================================================