Converting wind direction in angles to text words
Asked Answered
O

17

51

I have wind direction data coming from a weather vane, and the data is represented in 0 to 359 degrees.

I want to convert this into text format (compass rose) with 16 different directions.

Basically I want to know if there is a fast slick way to scale the angle reading to a 16 string array to print out the correct wind direction without using a bunch of if statements and checking for ranges of angles

Wind direction can be found here.

thanks!

Omnifarious answered 20/9, 2011 at 19:26 Comment(3)
Are looking for text to the tune of N, NNW, NW, WNW, etc?Coiffure
The link in the question is now brokenEvildoer
If you're looking for the opposite conversion (compass directions to numeric degrees) as I was, here's an answer: #42597844Ous
S
97

EDIT :

Since there is an angle change at every 22.5 degrees, the direction should swap hands after 11.25 degrees.

Therefore:

349-360//0-11 = N
12-33 = NNE
34-56 = NE

Using values from 327-348 (The entire NNW spectrum) failed to produce a result for eudoxos' answer. After giving it some thought I could not find the flaw in his logic, so i rewrote my own..

def degToCompass(num):
    val=int((num/22.5)+.5)
    arr=["N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"]
    print arr[(val % 16)]

>>> degToCompass(0)
N
>>> degToCompass(180)
S
>>> degToCompass(720)
N
>>> degToCompass(11)
N
>>> 12
12
>>> degToCompass(12)
NNE
>>> degToCompass(33)
NNE
>>> degToCompass(34)
NE

STEPS :

  1. Divide the angle by 22.5 because 360deg/16 directions = 22.5deg/direction change.
  2. Add .5 so that when you truncate the value you can break the 'tie' between the change threshold.
  3. Truncate the value using integer division (so there is no rounding).
  4. Directly index into the array and print the value (mod 16).
Spermato answered 20/9, 2011 at 19:35 Comment(2)
Why are you subtracting 1 here? That would seem to give you -1 for the event of 0 degrees, giving you an index out of bounds error. Other than that, exactly what I was thinking.Coiffure
Remove the subtract 1 and put in the value 359. IndexOutOfBounds error. I did a subtract 1 and left out a tiny check.. If < 0, index should be set to 0.Spermato
A
46

Here's a javascript implementation of steve-gregory's answer, which works for me.

function degToCompass(num) {
    var val = Math.floor((num / 22.5) + 0.5);
    var arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"];
    return arr[(val % 16)];
}

See his answer for an explanation of the logic.

Azobenzene answered 16/9, 2014 at 11:2 Comment(3)
What does Math.floor(n + 0.5) do differently from Math.round(n)? Is it more performant?Piercing
It wasn't for performance reasons... maybe Math.round(n) would work fine. It would be worth trying with unit tests.Azobenzene
Ha ha, I wrote this then went to post it here and saw yours, personally I would move the %16 up into the first calculation ..Kerge
J
22

This JavaScript will work for anyone who only needs 8 cardinal directions and would like corresponding arrows.

function getCardinalDirection(angle) {
    const directions = ['↑ N', '↗ NE', '→ E', '↘ SE', '↓ S', '↙ SW', '← W', '↖ NW'];
    return directions[Math.round(angle / 45) % 8];
}

For wind, the arrows are reversed by convention, as the angle indicates the direction of the source rather than movement.

function getWindDirection(angle) {
    const directions = ['↓ N', '↙ NE', '← E', '↖ SE', '↑ S', '↗ SW', '→ W', '↘ NW'];
    return directions[Math.round(angle / 45) % 8];
}
Jem answered 13/2, 2019 at 18:29 Comment(2)
In terms of wind, shouldn't the arrows point in the opposite directions? Usually wind direction is defined by from where the wind originates.Hunchback
@Hunchback Good point. I added getWindDirection.Jem
I
12

Watch out for rounding, angles between 349...11 should be "N", therefore add half sector first (+(360/16)/2), then handle overflow over 360 by %360, then divide by 360/16:

["N","NNW",...,"NNE"][((d+(360/16)/2)%360)/(360/16)]
Incorporable answered 20/9, 2011 at 19:39 Comment(4)
Aapparently none of fellows posters did :-( [They should all get a F for their answers, sice 359 should be clearly N, but they will get NNE or such.]Incorporable
@eudoxos: The divisor at the end should be 360/16 . Corrected the answer above. Works now. You might need a Math.floor or something similar in most languages though.Barret
Thank you @DoubleMalt, if anyone is getting N at 359 and NNE at 1, use [Math.floor(((d+(360/16)/2)%360)/(360/16))]Gobert
Watch out if you are using this in Python 2. It had me stumped wondering why it wasn't working quite right. This is using integer division, and needs to have at least one side of every division be a float for this to work. Replacing both instances of (360/16) with (360.0/16) will make it work correctly.Rackrent
T
8

I checked this and it works very good and seems accurate. Source: http://www.themethodology.net/2013/12/how-to-convert-degrees-to-cardinal.html by Adrian Stevens

    public static string DegreesToCardinal(double degrees)
    {
        string[] caridnals = { "N", "NE", "E", "SE", "S", "SW", "W", "NW", "N" };
        return caridnals[(int)Math.Round(((double)degrees % 360) / 45)];
    }

    public static string DegreesToCardinalDetailed(double degrees)
    {
        degrees *= 10;

        string[] caridnals = { "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW", "N" };
        return caridnals[(int)Math.Round(((double)degrees % 3600) / 225)];
    }
Trabzon answered 25/8, 2016 at 13:35 Comment(0)
U
5

I believe it is easier to:

  1. Shift the direction by 11.25
  2. Add an "N" at the end of the direction list to handle the 'over 360',

DirTable = ["N","NNE","NE","ENE","E","ESE", "SE","SSE","S","SSW","SW","WSW", "W","WNW","NW","NNW",**"N"**]; 

wind_direction= DirTable[Math.floor((d+11.25)/22.5)];
Unpractical answered 6/2, 2012 at 15:9 Comment(0)
A
4

Here's a one-line python function:

def deg_to_text(deg):
    return ["N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"][round(deg/22.5)%16]

Obviously it can be split into multiple lines for readability/pep8

Adamec answered 3/9, 2019 at 9:44 Comment(0)
M
3

If you arrived here and are only interested in breaking your degrees into one of 8 directions.

function degToCompass(num){
    const val =  Math.floor((num / 45) + 0.5);
    const arr = ["N","NE","E", "SE","S","SW","W","NW"];
    return arr[(val % 8)]
Mikol answered 5/3, 2018 at 15:26 Comment(0)
C
2

I would probably just do simple division of degrees to get a position in an array or an enum value or something that would give you the text you need. Just round down on all your division. 360/16 = 22.5, so you would want to divide by 22.5 to get the position.

String[] a = [N,NNW,NW,WNW,...,NNE]

Coiffure answered 20/9, 2011 at 19:35 Comment(0)
A
2

To do the reverse conversion (compass letter abbreviations to degrees):

function getDir($b)
{

   $dirs = array('N'=>0, 'NNE'=>22.5,"NE"=>45,"ENE"=>67.5, 'E'=>90,'ESE'=>112.5, 'SE'=>135,'SSE'=>157.5, 'S'=>180,'SSW'=>202.5, 'SW'=>225,'WSW'=>247.5, 'W'=>270,'WNW'=>292.5,'NW'=>315,'NNW'=>337.5, 'N'=>0,'North'=>0,'East'=>90,'West'=>270,'South'=>180);
   return $dirs[$b];
}
Ariannearianrhod answered 20/10, 2014 at 13:47 Comment(1)
This does not answer the question.Egestion
W
2

this works fine

#!/usr/bin/env python

def wind_deg_to_str1(deg):
        if   deg >=  11.25 and deg <  33.75: return 'NNE'
        elif deg >=  33.75 and deg <  56.25: return 'NE'
        elif deg >=  56.25 and deg <  78.75: return 'ENE'
        elif deg >=  78.75 and deg < 101.25: return 'E'
        elif deg >= 101.25 and deg < 123.75: return 'ESE'
        elif deg >= 123.75 and deg < 146.25: return 'SE'
        elif deg >= 146.25 and deg < 168.75: return 'SSE'
        elif deg >= 168.75 and deg < 191.25: return 'S'
        elif deg >= 191.25 and deg < 213.75: return 'SSW'
        elif deg >= 213.75 and deg < 236.25: return 'SW'
        elif deg >= 236.25 and deg < 258.75: return 'WSW'
        elif deg >= 258.75 and deg < 281.25: return 'W'
        elif deg >= 281.25 and deg < 303.75: return 'WNW'
        elif deg >= 303.75 and deg < 326.25: return 'NW'
        elif deg >= 326.25 and deg < 348.75: return 'NNW'
        else: return 'N'

def wind_deg_to_str2(deg):
        arr = ['NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW', 'N']
        return arr[int(abs((deg - 11.25) % 360)/ 22.5)]

i = 0
while i < 360:
        s1 = wind_deg_to_str1(i)
        s2 = wind_deg_to_str2(i)
        print '%5.1f deg -> func1(%-3s), func2(%-3s), same:%s' % (i, s1, s2, ('ok' if s1 == s2 else 'different'))
        i += 0.5
Weary answered 23/1, 2017 at 15:42 Comment(0)
F
1

Javascript function 100% working

function degToCompass(num) { 
    while( num < 0 ) num += 360 ;
    while( num >= 360 ) num -= 360 ; 
    val= Math.round( (num -11.25 ) / 22.5 ) ;
    arr=["N","NNE","NE","ENE","E","ESE", "SE", 
          "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW"] ;
    return arr[ Math.abs(val) ] ;
}

steps

  1. Given a 360 degree angle
  2. Since north is between -11.25 to 11.25 we subtract 11.25 for accuracy
  3. Divide the angle by 22.5 because 360deg/16 directions = 22.5deg/direction change
  4. Math.abs for as negative is still north
  5. Select the segment from arr from answer

Hope it helps

Fascist answered 28/8, 2013 at 7:58 Comment(3)
It doesn't work. degToCompass(70) returns NNE, the correct answer is ENE. climate.umn.edu/snow_fence/components/…Azobenzene
more testing needed! -90 should be west not east, also 12 degrees should be the first transition away from north.Gorged
@SamMason the function was created to work for angles between 0 to 360. i have modified to work with any now Thanks for inputFascist
K
1

I use R heavily and needed a solution for this. This is what I came up with and works well for all possible combinations I have fed it:

degToCardinal <- function(degrees) {
  val <- as.integer((degrees / 22.5) + 0.5)
  arr <- c("N","NNE","NE","ENE","E","ESE", "SE", "SSE","S","SSW","SW","WSW","W","WNW","NW","NNW")
  return(arr[((val+1) %% 16)])
}
Keratose answered 26/9, 2018 at 19:44 Comment(0)
L
1

Wanted to use @eudoxos but needed to pull all the parts together:

def deg_to_compass(d):
  return ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
        "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"] [math.floor(((d+(360/16)/2)%360)/(360/16))]

Borrrowed @Hristo markow to check the results:

for i in range(0,360):
  print (i,deg_to_compass(i) == wind_deg_to_str2(i))
Lev answered 15/4, 2019 at 2:44 Comment(0)
W
1
compass_direction =["NNE","NE","ENE","E","ESE","SE","SSE","S","SSW","SW","WSW","W","WNW","NW","NNW","N"]

for i in range (0,365):
    index = (int) ((((i / 11.25) - 1) /2) % 16) 
    print(f"Angle: {i:3}, Index: {index}, Compass: {compass_direction[index]}")
Won answered 16/11, 2021 at 17:19 Comment(0)
K
1

Here is a flutter/dart version:

const windDirections = [
  "↑N",
  "NNE",
  "↗NE",
  "ENE",
  "→E",
  "ESE",
  "↘SE",
  "SSE",
  "↓S",
  "SSW",
  "↙SW",
  "WSW",
  "←W",
  "WNW",
  "↖NW",
  "NNW"
];
String degToCompass(final int degrees) =>
    windDirections[((degrees / 22.5) + 0.5).toInt() % 16];
Keven answered 7/6, 2023 at 12:20 Comment(0)
K
0

Used this in Excel: VLOOKUP(MROUND(N12,22.5),N14:O29,2,FALSE)

Cell N12 is direction toward in degrees for which an answer is needed. The range N14:O29 is looking up the sector(A to R):

WIND SECTOR 0 A 22.5 B 45 C 67.5 D 90 E 112.5 F 135 G 157.5 H 180 J 202.5 K 225 L 247.5 M 270 N 292.5 P 315 Q 337.5 R

Kopeck answered 4/9, 2017 at 19:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.