N Number & ICAO address

I just learned that, at least in the US, the ICAO hex and N number are mathematically linked. I don’t know the math, but if that formula is publicly available, a feature could be added to dump1090. With the ICAO hex, you could determine the N number without a database. I would think this would be helpful translating commercial flight identifiers into registration numbers.

Or maybe this is old news and is already in use?

It looks like there could be.
This site claims to have cracked it.

avionictools.com/icao.php

Yours would be
N456TS
Hex: A58A20
Octal: 51305040
Binary: 101001011000101000100000

It is very old. Refers to a “PalmPilot version”

Indeed, in the US it’s sequentially assigned from A00001 for N1 to ADF669 for N999ZZ.

That’s good to know! I couldn’t find a public list of all the mappings, so here I generated one. (12mb txt) :bulb:

Looks like Canada is also sequential, c00001=CFAAA to c0cdf8=CIZZZ (CG*** is skipped)

1 Like

I’ve been fiddling with some basic decoder functions for US & Canadian aircraft. When new aircraft objects are created in dump1090, I made it pre-fill the callsign field with the registration. That’s not really ideal though, because if the craft broadcasts a bogus callsign it will overwrite it. Also you might want to know the registration and callsign/flight separately.

Would it be better to add a new registration field to the aircraft struct & json?

Or leave dump1090 alone and just calculate the registration on the javascript side? (then you wouldn’t see it in interactive mode)

hmm… :confused:


I wonder what other countries have a known ICAO->Tail# pattern.

Right now, if I want to know more about an aircraft with out an N number listed, I have to click on the airframe link, then copy and paste the N number listed on that site into FA. It would be nice if that was automatically handled and skipping the airframe site. I think having everything listed as N number would be good. I only care about GA AC, so I’m not sure many would agree with me.

or… Maybe those AC with a flight #, get the n number added in the details at the top of the window when clicked on.

In any case, it would be nice for a link to be available to lookup the aircraft on FA.

@BartJr: this would fit well on the JavaScript side. It already loads registration data from a static db, computing the registration can be done around the same point.
edit: specifically, you could add it around here: github.com/mutability/dump1090/ … ect.js#L42
The DB lookup will then override the calculated value if it has data.

@N456TS: coincidentally there is something that should do this arriving shortly
edit: github.com/mutability/dump1090/ … 9c98013590

(airframes.org explicitly does not want automated lookups, so it is going to continue to be something you need to look at manually)

If I download and recompile now, it will work? Or does the FA site still need to be updated to accept the request?

edit: I should just look more closely. It looks like it’s ready to go…

Yeah, it should be live. It’s just a javascript change on the dump1090 side.

That’s a great enhancement, though it seems the “/live/modes/” url is not working for MLAT flights. For example:

“Could not find airborne flight”: flightaware.com/live/modes/a4934a/redirect
[flight]N394SW[/flight]

I can confirm as well.

I haven’t been able to crack the code for the math on it, however it is a mathematically linked function that I believe I have generated a list based on once. I got really bored one day and wrote a bash script to scrape the FAAs registration database and update my basestation.sqb file. It would probably be somewhat trivial to set up dump1090 to query the SQLite database for the information, however I don’t use the dump1090 interface and really don’t have much interest in doing so.

If anyone wants the script to download the DB, I can probably give it to you, however it’s coded to ‘bypass’ the function that seems to deter scripted downloads, so I don’t really want to put it out on the internet.

There is room for improvement on the whole thing (instead of starting with a blank sqb file, copy the running one, MERGE the info from the FAA and replace the running one) but it worked well enough for my purposes.

It DOES appear that VRS now can dynamically obtain the information automatically and update the sqb file, so that’s what I’m using now.

Here is some Python code that I wrote to go to / from N to ICAO. It is based on looking at the structure of BartJr’s table. Spot-checking a few flights on the air it seems to match. This has not been extensively tested and may have errors. Also there is no protection against invalid inputs in the tail to ICAO routine.

The general principle is that an N number has one to three digits after the N. The first digit is never a zero. These are most significant in setting the ICAO number. A number N2nnxx wiil always be exactly 101711 (decimal) away from its N1nnxx counterpart. After this one, two, or three digit number, a suffix of zero to two letters can be applied. If there are 3 digits after the N, the suffix may contain numbers, but if the first digit of the suffix is a letter, the second one (if present) must also be a letter (“N123A1” is illegal). This gives the effect of a 4 or 5 digit N number, but actually internally these are extensions of a 3 digit number with what I call a “base 35” suffix.


base9 = '123456789'  # The first digit (after the "N") is always one of these.
base10 = '0123456789' # The possible second and third digits are one of these.
# Note that "I" and "O" are never used as letters, to prevent confusion with "1" and "0"
base34 = 'ABCDEFGHJKLMNPQRSTUVWXYZ0123456789' 
icaooffset = 0xA00001 # The lowest possible number, N1, is this.
b1 = 101711 # basis between N1... and N2...
b2 = 10111 # basis between N10.... and N11....

def suffix(rem):
    """ Produces the alpha(numeric) suffix from a number 0 - 950 """
    if rem == 0:
        suf = ''
    else:
        if rem <= 600: #Class A suffix -- only letters.
            rem = rem - 1
            suf = base34[rem // 25]
            if rem % 25 > 0:
                suf = suf + base34(rem % 25) - 1] # second class A letter, if present.
        else:  #rem > 600 : First digit of suffix is a number.  Second digit may be blank, letter, or number.
            rem = rem - 601
            suf = base10[rem // 35]
            if rem % 35 > 0:
                suf = suf + base34(rem % 35) - 1]
    return suf
    
def enc_suffix(suf):
    """ Produces a remainder from a 0 - 2 digit suffix. 
    No error checking.  Using illegal strings will have strange results."""
    if len(suf) == 0:
        return 0
    r0 = base34.find(suf[0])
    if len(suf) == 1:
        r1 = 0
    else:
        r1 = base34.find(suf[1]) + 1
    if r0 < 24: # first char is a letter, use base 25
        return r0 * 25 + r1 + 1
    else:  # first is a number -- base 35.
        return r0 * 35 + r1 - 239   
    
def icao_to_tail(icao):
    if (icao < 0) or (icao > 0xadf7c7):
        return "Undefined"
    icao = icao - icaooffset
    d1 = icao // b1
    nnum = 'N' + base9[d1]
    r1 = icao % b1
    if r1 < 601:
        nnum = nnum + suffix(r1) # of the form N1ZZ
    else:
        d2 = (r1 - 601) // b2  # find second digit.
        nnum = nnum + base10[d2]
        r2 = (r1 - 601) % b2  # and residue after that
        if r2 < 601:  # No third digit. (form N12ZZ)
            nnum = nnum + suffix(r2)
        else:
            d3 = (r2 - 601) // 951 # Three-digits have extended suffix.
            r3 = (r2 - 601) % 951   
            nnum = nnum + base10[d3] + suffix(r3)
    return nnum 
    
def tail_to_icao(tail):
    if tail[0] != 'N':
        return -1
    icao = icaooffset
    icao = icao + base9.find(tail[1]) * b1
    if len(tail) == 2: # simple 'N3' etc.
        return icao
    d2 = base10.find(tail[2])
    if d2 == -1: # Form N1A
        icao = icao + enc_suffix(tail[2:4])
        return icao
    else: # Form N11... or N111..
        icao = icao + d2 * b2 + 601
        d3 = base10.find(tail[3])
        if d3 > -1: #Form N111 Suffix is base 35.
            icao = icao + d3 * 951 + 601
            icao = icao + enc_suffix(tail[4:6])
            return icao
        else:  #Form N11A
            icao = icao + enc_suffix(tail[3:5])
            return icao

That looks like the same basic algorithm as my python code which I used to generate the table (though yours is better commented :mrgreen: )



#1: 1-9 * 101711
#2: _=601, 0-9*(9510+601)
az = list('ABCDEFGHJKLMNPQRSTUVWXYZ')
baz = ''] + az
na = map(str,range(10))
bazn = ''] + az + map(str,range(10))

def az1(i): #601
    if i == 0:
        return ''
    else:
        i -= 1
        return az* + baz*

def hex_to_n(h):
    s = 'N'
    i = int(h)-0xa00001
    s += str(i/101711 + 1)
    i %= 101711
    if i < 601:
        s += az1(i)
    else:
        i -= 601
        s += str(i/10111)
        i %= 10111
        if i < 601:
            s += az1(i)
        else:
            i -= 601
            s += str(i/951)
            i %= 951
            if i < 601:
                s += az1(i)
            else:
                i -= 601
                s += na* + bazn*
    return s



No need to scrape. They have a direct download of the entire FAA database, though you have to do some minor database-foo to correlate the interesting data from multiple files.

faa.gov/licenses_certificate … _download/

It fails the “N11” case. This seems to fix it:



    else: # Form N11... or N111..
        icao = icao + d2 * b2 + 601
+       if len(tail) == 3: # simple 'N34' etc.
+           return icao
        d3 = base10.find(tail[3])


My method doesn’t require any manual intervention. 8)

So is there a script I can run that would convert ICAO numbers to N numbers which would display on my local network connection instated of have the N field blank? Would that also mean that more planes would be trackable with the airplane icon and tail instead of just airliners? I guess what I am missing and would like to track is VFR traffic that is sending out ADS-B while they do appear sometimes I am not able to determine most of the times what my receiver is picking up if they are sq 1200

Thanks

This is hit or miss for me too. Not sure why it works when it does/doesn’t. ?

From the publicly available FAA tie-up data one can easily figure out what the algorithms are that relate American N numbers to their ICAO hex address - there are 24 algorithms for the 12 categories of 915399 possible N numbers. I turned these into a little and superfast Windows commandline application which works two-ways, N number <–> ICAO address. If somebody is interested, just ask for it : mailto:blackbird@inboxalias.com. The derived algorithms are available too (in Dutch only). They were thoroughly tested : the FAA data were generated both ways and all matched.