PyFT8 2.4.0__tar.gz → 2.4.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. {pyft8-2.4.0 → pyft8-2.4.2}/PKG-INFO +17 -4
  2. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/pyft8.py +16 -13
  3. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/receiver.py +57 -60
  4. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/transmitter.py +8 -6
  5. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/PKG-INFO +17 -4
  6. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/SOURCES.txt +3 -1
  7. {pyft8-2.4.0 → pyft8-2.4.2}/README.md +16 -3
  8. {pyft8-2.4.0 → pyft8-2.4.2}/pyproject.toml +1 -1
  9. pyft8-2.4.2/tests/dev/CQ AAAA.py +30 -0
  10. pyft8-2.4.2/tests/dev/view_worked_before.py +10 -0
  11. {pyft8-2.4.0 → pyft8-2.4.2}/LICENSE +0 -0
  12. {pyft8-2.4.0 → pyft8-2.4.2}/MANIFEST.in +0 -0
  13. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/__init__.py +0 -0
  14. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/callhashes.py +0 -0
  15. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/gui.py +0 -0
  16. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/pskr_upload.py +0 -0
  17. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/rigctrl.py +0 -0
  18. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8/time_utils.py +0 -0
  19. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/dependency_links.txt +0 -0
  20. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/entry_points.txt +0 -0
  21. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/requires.txt +0 -0
  22. {pyft8-2.4.0 → pyft8-2.4.2}/PyFT8.egg-info/top_level.txt +0 -0
  23. {pyft8-2.4.0 → pyft8-2.4.2}/setup.cfg +0 -0
  24. {pyft8-2.4.0 → pyft8-2.4.2}/tests/dev/osd.py +0 -0
  25. {pyft8-2.4.0 → pyft8-2.4.2}/tests/dev/test_generate_wav.py +0 -0
  26. {pyft8-2.4.0 → pyft8-2.4.2}/tests/dev/test_loopback_performance.py +0 -0
  27. {pyft8-2.4.0 → pyft8-2.4.2}/tests/plot_baseline.py +0 -0
  28. {pyft8-2.4.0 → pyft8-2.4.2}/tests/spare.py +0 -0
  29. {pyft8-2.4.0 → pyft8-2.4.2}/tests/test_batch_and_live.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyFT8
3
- Version: 2.4.0
3
+ Version: 2.4.2
4
4
  Summary: FT8 Decoding and Encoding in Python with test/loopback code
5
5
  Author-email: G1OJS <g1ojs@yahoo.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -17,7 +17,7 @@ Requires-Dist: matplotlib
17
17
  Requires-Dist: pyaudio
18
18
  Dynamic: license-file
19
19
 
20
- # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8)
20
+ # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=weekly&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads/wk)](https://pepy.tech/projects/pyft8)
21
21
  # All-Python FT8 Transceiver GUI / Command Line Modem
22
22
 
23
23
  This repository contains the source code for PyFT8, an all-Python open source FT8 transceiver that you can run as a basic GUI or from the command line to receive and transmit. Decoding performance (number of decodes) is about 70% of that achieved by WSJT-x in NORM mode, but (tbc) slightly above ft8_lib.
@@ -86,9 +86,22 @@ The image below shows the number of decodes from PyFT8, WSJT-x V2.7.0 running in
86
86
 
87
87
 
88
88
  ## Limitations
89
+ PyFT8 doesn't decode / encode *all* message types. The table below shows which are handled.
90
+
91
+ |i3.n3|Known as|Rx|Tx|notes|
92
+ |------|--------|----|----|-----|
93
+ |0.0|Free Text | | | |
94
+ |0.1|DXpedition | | | Call1 RR73; Call2 +07|
95
+ |0.3|Field Day | | | |
96
+ |0.4|Field Day | | | |
97
+ |0.5|Telemetry | | | |
98
+ |1|Std Msg |Y| Y |Standard <=6 char callsigns, can include /R |
99
+ |2|EU VHF |Y|Y| Standard <=6 char callsigns, can include /P |
100
+ |3|RTTY RU | | | |
101
+ |4|NonStd Call |Y|Y| <=11 char callsigns + hashed call|
102
+ |5|EU VHF | | | |
103
+
89
104
 
90
- In pursuit of tight code, I've concentrated on core standard messages, leaving out some of the less-used features. The receive part of the
91
- code doesn't (yet) have the full capability of the advanced decoders used in WSJT-x, and so gets fewer decodes than WSJT-x gets, depending on band conditions (on a quiet band with only good signals PyFT8 will get close to 100%).
92
105
 
93
106
  ## Acknowledgements
94
107
  This project implements a decoder for the FT8 digital mode.
@@ -11,7 +11,7 @@ from PyFT8.transmitter import AudioOut
11
11
  from PyFT8.time_utils import global_time_utils
12
12
  from PyFT8.rigctrl import Rig
13
13
 
14
- VER = '2.4.0'
14
+ VER = '2.4.2'
15
15
 
16
16
  MAX_TX_START_SECONDS = 2.5
17
17
  rig, gui, qso, worked_before, pskr_upload = None, None, None, None, None
@@ -50,16 +50,16 @@ class Logging:
50
50
  f.write("header <eoh>")
51
51
  if(not os.path.exists(self.worked_before_file)):
52
52
  with open(f"{self.worked_before_file}","wb") as f:
53
- pickle.dump({'dummy':'dummy'}, f)
53
+ pickle.dump({'dummy':0}, f)
54
54
  self.load_wb()
55
+ console_print(f"Logging to {self.adif_log_file}")
55
56
 
56
57
  def load_wb(self):
57
58
  global worked_before
58
59
  with open(f"{self.worked_before_file}","rb") as f:
59
60
  worked_before = pickle.load(f)
60
- #self.load_wb_from_txt()
61
61
 
62
- def load_wb_from_txt(self, file = 'c:/users/drala/recent_log.adi'):
62
+ def merge_adif_to_wb_not_used(self, file = 'c:/users/drala/recent_log.adi'):
63
63
  import datetime
64
64
  with open(file, 'r') as f:
65
65
  for l in f.readlines():
@@ -69,14 +69,18 @@ class Logging:
69
69
  t = parse_from_adif_rec(l, 'time_on')
70
70
  d = parse_from_adif_rec(l, 'qso_date')
71
71
  tm = time.mktime(datetime.datetime.strptime(d+t, "%Y%m%d%H%M%S").timetuple())
72
+ if callsign in worked_before:
73
+ if tm < worked_before[callsign]:
74
+ continue
72
75
  self.update_worked_before(callsign, tm)
73
76
 
74
- def update_worked_before(self, callsign, tm):
77
+ def update_worked_before(self, callsign, band, mode, tm):
75
78
  global worked_before
76
- #self.load_wb()
77
- if not callsign in worked_before:
78
- worked_before[callsign] = {}
79
+ self.load_wb()
80
+ worked_before[callsign] = tm
81
+ cbm = callsign + "_"+band+"_"+mode
79
82
  worked_before[callsign] = tm
83
+ worked_before[cbm] = tm
80
84
  with open(f"{self.worked_before_file}","wb") as f:
81
85
  pickle.dump(worked_before, f)
82
86
 
@@ -93,7 +97,7 @@ class Logging:
93
97
  v = str(v)
94
98
  f.write(f"<{k}:{len(v)}>{v} ")
95
99
  f.write(f"<eor>\n")
96
- self.update_worked_before(oStation['c'], time.time())
100
+ self.update_worked_before(oStation['c'], band_info['b'], 'FT8', time.time())
97
101
  console_print(f"Logged QSO with {oStation['c']}")
98
102
 
99
103
 
@@ -178,6 +182,7 @@ class FT8_QSO:
178
182
 
179
183
  def log(self):
180
184
  if self.logging is not None:
185
+ self.times['time_off'] = time.gmtime()
181
186
  self.logging.log(self.times, self.band_info, self.mStation, self.oStation, self.rpts)
182
187
 
183
188
  def isReport(grid_rpt): return "+" in grid_rpt or "-" in grid_rpt
@@ -220,14 +225,12 @@ def progress_qso(clicked_message):
220
225
  qso.rpts['rcvd'] = grid_rpt[-3:]
221
226
  if isRReport(grid_rpt) or isRRR(grid_rpt):
222
227
  reply = f"{qso.oStation['c']} {my_station['c']} RR73"
228
+ qso.log()
223
229
  if isRR73(grid_rpt):
224
230
  reply = f"{qso.oStation['c']} {my_station['c']} 73"
231
+ qso.log()
225
232
  qso.set_tx_message(reply)
226
233
 
227
- if is73(grid_rpt) or " 73" in reply or isRR73(grid_rpt):
228
- qso.times['time_off'] = time.gmtime()
229
- qso.log()
230
-
231
234
  def make_wav(msg, wave_output_file): # move to transmitter.py?
232
235
  symbols = audio_out.create_ft8_symbols(msg)
233
236
  audio_data = audio_out.create_ft8_wave(symbols)
@@ -33,92 +33,89 @@ HOPS_PER_GRID = 2 * HOPS_PER_CYCLE
33
33
  global_time_utils.set_cycle_length(T_CYC)
34
34
 
35
35
  #=========== Unpacking functions ========================================
36
- def get_bits(bits, n):
37
- mask = (1 << n) - 1
38
- out = bits & mask
39
- bits >>= n
40
- return out, bits
36
+ def get_bitfields(bits, lengths):
37
+ fields = []
38
+ for n in lengths:
39
+ mask = (1 << n) - 1
40
+ fields.append(bits & mask)
41
+ bits >>= n
42
+ return *fields, bits
41
43
 
42
44
  def unpack(bits):
43
- # print(f"{bits:77b}")
44
- i3, bits = get_bits(bits,3)
45
- # print(i3)
45
+ i3, bits74 = get_bitfields(bits,[3])
46
46
  if i3 == 0:
47
- n3, bits = get_bits(bits,3)
47
+ n3, bits71 = get_bitfields(bits74,[3])
48
48
  if n3 == 0:
49
49
  return ('Free text','not','implemented')
50
50
  else:
51
51
  return (['DXpedition','Field Day', 'Field Day', 'Telemetry'][n3-1],'not','implemented')
52
52
  elif i3 == 1 or i3 == 2: # 1 = Std Msg incl /R 2 = 'EU VHF' = Std Msg incl /P
53
- gr, bits = get_bits(bits,16)
54
- cb, bits = get_bits(bits,29)
55
- ca, bits = get_bits(bits,29)
56
- return (call_28(ca, i3), call_28(cb, i3), decode_grid(gr))
53
+ return unpack_std(bits74, i3)
57
54
  elif i3 == 3:
58
55
  return ('RTTY RU','not','implemented')
59
56
  elif i3 == 4:
60
- cq_, bits = get_bits(bits,1)
61
- rrr, bits = get_bits(bits,2)
62
- swp, bits = get_bits(bits,1)
63
- c58, bits = get_bits(bits,58)
64
- hsh, bits = get_bits(bits,12)
65
- ca = "CQ" if cq_ else call_hashes.get((hsh,12), '<....>')
66
- cb = call_58(c58)
57
+ cq, rrr, swp, c58, hsh, _ = get_bitfields(bits74, [1,2,1,58,12])
58
+ ca = "CQ" if cq else call_hashes.get((hsh,12), '<....>')
59
+ cb = ""
60
+ for i in range(12):
61
+ cb = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/"[c58 % 38] + cb
62
+ c58 = c58 // 38
63
+ cb = cb.strip()
64
+ add_call_hashes(cb)
67
65
  (ca, cb) = (cb, ca) if swp else (ca, cb)
68
66
  return (ca, cb, ('', 'RRR', 'RR73', '73')[rrr])
69
67
  elif i3 == 5:
70
68
  return ('EU VHF','not','implemented')
71
69
 
72
- def call_58(call_int):
73
- call = ""
74
- chars = " 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ/"
75
- for i in range(12):
76
- call = chars[call_int % 38] + call
77
- call_int = call_int // 38
78
- call = call.strip()
79
- add_call_hashes(call)
80
- return call
70
+ def unpack_std(bits74, i3):
71
+ g16, cb29, ca29, _ = get_bitfields(bits74,[16,29,29])
72
+ g15 = g16 & 0x7FFF
73
+ if g15 < 32400:
74
+ a, nn = divmod(g15, 1800)
75
+ b, nn = divmod(nn, 100)
76
+ c, d = divmod(nn, 10)
77
+ grid_rpt = chr(65+a) + chr(65+b) + str(c) + str(d)
78
+ elif g15 - 32400 <= 4:
79
+ grid_rpt = ('', '', 'RRR', 'RR73', '73')[g15 - 32400]
80
+ else:
81
+ prefix = 'R' if (g16 >> 15) else ''
82
+ grid_rpt = prefix + f"{(g15 - 32435):+03d}"
83
+ return (call_29(ca29, i3), call_29(cb29, i3), grid_rpt)
81
84
 
82
- def call_28(call_int, i3):
83
- def get_table_7(call_int):
84
- table_7 = {'DE':(0,0),'QRZ':(1,1),'CQ':(2,2), 'CQ nnn':(3,1002),'CQ x':(1004,1029),
85
- 'CQ xx':(1031,1731),'CQ xxxx':(21443,532443),'hash':(2063592,2063592+4194303)}
86
- for ct, (lo, hi) in table_7.items():
87
- if lo <= call_int <= hi:
88
- return ct
85
+ def call_29(call_int29, i3):
86
+ portable_rover = call_int29 & 1
87
+ call_int28 = call_int29>>1
88
+ if call_int28 < 3:
89
+ return ['DE', 'QRZ', 'CQ'][call_int28]
90
+ elif call_int28 < 1004:
91
+ return f"CQ {call_int28 - 3:03d}"
92
+ elif call_int28 < 21443:
93
+ x, txt = call_int28 - 1003, ''
94
+ for i in range(4):
95
+ txt = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"[int(x % 27)] + txt
96
+ x //= 27
97
+ return f"CQ {txt.strip()}"
98
+ elif call_int28 < 2063592+4194303:
99
+ return call_hashes.get((call_int28 - 2063592, 22), '<....>')
100
+ else:
101
+ call = standard_call28(call_int28, i3)
102
+ if portable_rover:
103
+ call = call + ('/P' if i3 == 2 else '/R')
104
+ add_call_hashes(call)
105
+ return call
106
+
107
+ def standard_call28(call_int28, i3):
108
+ nn = call_int28 - (2063592 + 4194304)
89
109
  from string import ascii_uppercase as ltrs, digits as digs
90
110
  call_fields = [ (' ' + digs + ltrs, 36*10*27**3), (digs + ltrs, 10*27**3), (digs + ' ' * 17, 27**3),
91
111
  (' ' + ltrs, 27**2), (' ' + ltrs, 27), (' ' + ltrs, 1) ]
92
- portable_rover = call_int & 1
93
- call_int >>= 1
94
- t7 = get_table_7(call_int)
95
- if t7 is not None:
96
- return t7 if t7 != 'hash' else call_hashes.get((call_int - 2063592, 22), '<....>')
97
- call_int -= (2063592 + 4194304)
98
112
  chars = []
99
113
  for alphabet, div in call_fields:
100
- idx, call_int = divmod(call_int, div)
114
+ idx, nn = divmod(nn, div)
101
115
  chars.append(alphabet[idx])
102
116
  call = ''.join(chars).strip()
103
- if portable_rover:
104
- call = call + ('/P' if i3 == 2 else '/R')
105
- add_call_hashes(call)
106
117
  return call
107
118
 
108
- def decode_grid(grid_int):
109
- g15 = grid_int & 0x7FFF
110
- if g15 < 32400:
111
- a, nn = divmod(g15, 1800)
112
- b, nn = divmod(nn, 100)
113
- c, d = divmod(nn, 10)
114
- return chr(65+a) + chr(65+b) + str(c) + str(d)
115
- r = g15 - 32400
116
- if r <= 4:
117
- return ('', '', 'RRR', 'RR73', '73')[r]
118
- snr = r - 35
119
- ir = grid_int >> 15
120
- prefix = 'R' if ir else ''
121
- return prefix + f"{snr:+03d}"
122
119
  #============== CRC ===========================================================
123
120
  def check_crc(bits91_int):
124
121
  bits77_int = bits91_int >> 14
@@ -68,13 +68,12 @@ def _pack_message(c1, c2, gr):
68
68
  c28a, p1a = pack_ft8_c28(c1)
69
69
  c28b, p1b = pack_ft8_c28(c2)
70
70
  g15, ir = pack_ft8_g15(gr)
71
- i3 = 2 if p1a or p1b else 1
71
+ i3 = 2 if c1.endswith('/P') or c2.endswith('/P') else 1
72
72
  n3 = 0
73
- symbols, bits77 = [], 0
74
73
  if(c28a>=0 and c28b>=0):
75
74
  bits77 = (c28a<<28+1+1+1+15+3) | (p1a<<28+1+1+15+3) | (c28b<<1+1+15+3) | (p1b <<1+15+3) | (ir<<15+3) | (g15<< 3) | (i3)
76
75
  symbols = encode_bits77(bits77)
77
- if not any(symbols):
76
+ else:
78
77
  i3 = 4
79
78
  full_call = c1 if c28b>0 else c2
80
79
  hash_call = c2 if c28b>0 else c1
@@ -103,8 +102,8 @@ def pack_ft8_c28(call):
103
102
  if (call in tkns):
104
103
  c28, p1 = tkns.index(call), 0
105
104
  else:
106
- p1 = 1 if call[-2:] == '/P' else 0
107
- call = call.replace('/P','')
105
+ p1 = 1 if call[-2:] in ('/P', '/R') else 0
106
+ call = call.replace('/P','').replace('/R','')
108
107
  if len(call) > 6:
109
108
  return -1, 0
110
109
  prepend_space = '' if call[2].isdigit() else ' '
@@ -185,7 +184,8 @@ def append_crc(bits77_int):
185
184
  if __name__ == "__main__":
186
185
  OK = True
187
186
  msgs = [("G1OJS/P", "G1OJS/P", "IO90"),("WM3PEN","EA6VQ","+08"),("E67A/P","EA6VQ","R-08"),
188
- ("CQ","CT7ARQ/P","RRR"), ("EC5A","9A5E","RR73"), ("EC5A/P","9A5E","73"), ("EC5A/MM","9A5E","73")]
187
+ ("CQ","CT7ARQ/P","JO03"), ("EC5A","9A5E","RR73"), ("EC5A/P","9A5E","73"), ("EC5A/MM","9A5E","73"),
188
+ ("CQ","CT7ARQ/R","JO03")]
189
189
  for msg_tx in msgs:
190
190
  symbols, bits77 = _pack_message(*msg_tx)
191
191
  from PyFT8.receiver import unpack
@@ -194,4 +194,6 @@ if __name__ == "__main__":
194
194
  OK = OK and (msg_tx == msg_rx) or 'implemented' in msg_rx
195
195
  #print(''.join([str(s) for s in symbols]))
196
196
  print("\nPASSED" if OK else "\nFAILED")
197
+
198
+ print(unpack(int('00000000000000000100011011110000010010000000000111000001100011111000010010001',2)))
197
199
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyFT8
3
- Version: 2.4.0
3
+ Version: 2.4.2
4
4
  Summary: FT8 Decoding and Encoding in Python with test/loopback code
5
5
  Author-email: G1OJS <g1ojs@yahoo.com>
6
6
  License-Expression: GPL-3.0-or-later
@@ -17,7 +17,7 @@ Requires-Dist: matplotlib
17
17
  Requires-Dist: pyaudio
18
18
  Dynamic: license-file
19
19
 
20
- # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8)
20
+ # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=weekly&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads/wk)](https://pepy.tech/projects/pyft8)
21
21
  # All-Python FT8 Transceiver GUI / Command Line Modem
22
22
 
23
23
  This repository contains the source code for PyFT8, an all-Python open source FT8 transceiver that you can run as a basic GUI or from the command line to receive and transmit. Decoding performance (number of decodes) is about 70% of that achieved by WSJT-x in NORM mode, but (tbc) slightly above ft8_lib.
@@ -86,9 +86,22 @@ The image below shows the number of decodes from PyFT8, WSJT-x V2.7.0 running in
86
86
 
87
87
 
88
88
  ## Limitations
89
+ PyFT8 doesn't decode / encode *all* message types. The table below shows which are handled.
90
+
91
+ |i3.n3|Known as|Rx|Tx|notes|
92
+ |------|--------|----|----|-----|
93
+ |0.0|Free Text | | | |
94
+ |0.1|DXpedition | | | Call1 RR73; Call2 +07|
95
+ |0.3|Field Day | | | |
96
+ |0.4|Field Day | | | |
97
+ |0.5|Telemetry | | | |
98
+ |1|Std Msg |Y| Y |Standard <=6 char callsigns, can include /R |
99
+ |2|EU VHF |Y|Y| Standard <=6 char callsigns, can include /P |
100
+ |3|RTTY RU | | | |
101
+ |4|NonStd Call |Y|Y| <=11 char callsigns + hashed call|
102
+ |5|EU VHF | | | |
103
+
89
104
 
90
- In pursuit of tight code, I've concentrated on core standard messages, leaving out some of the less-used features. The receive part of the
91
- code doesn't (yet) have the full capability of the advanced decoders used in WSJT-x, and so gets fewer decodes than WSJT-x gets, depending on band conditions (on a quiet band with only good signals PyFT8 will get close to 100%).
92
105
 
93
106
  ## Acknowledgements
94
107
  This project implements a decoder for the FT8 digital mode.
@@ -20,6 +20,8 @@ PyFT8.egg-info/top_level.txt
20
20
  tests/plot_baseline.py
21
21
  tests/spare.py
22
22
  tests/test_batch_and_live.py
23
+ tests/dev/CQ AAAA.py
23
24
  tests/dev/osd.py
24
25
  tests/dev/test_generate_wav.py
25
- tests/dev/test_loopback_performance.py
26
+ tests/dev/test_loopback_performance.py
27
+ tests/dev/view_worked_before.py
@@ -1,4 +1,4 @@
1
- # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8)
1
+ # PyFT8 [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=total&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads)](https://pepy.tech/projects/pyft8) [![PyPI Downloads](https://static.pepy.tech/personalized-badge/pyft8?period=weekly&units=INTERNATIONAL_SYSTEM&left_color=BLACK&right_color=GREEN&left_text=downloads/wk)](https://pepy.tech/projects/pyft8)
2
2
  # All-Python FT8 Transceiver GUI / Command Line Modem
3
3
 
4
4
  This repository contains the source code for PyFT8, an all-Python open source FT8 transceiver that you can run as a basic GUI or from the command line to receive and transmit. Decoding performance (number of decodes) is about 70% of that achieved by WSJT-x in NORM mode, but (tbc) slightly above ft8_lib.
@@ -67,9 +67,22 @@ The image below shows the number of decodes from PyFT8, WSJT-x V2.7.0 running in
67
67
 
68
68
 
69
69
  ## Limitations
70
+ PyFT8 doesn't decode / encode *all* message types. The table below shows which are handled.
71
+
72
+ |i3.n3|Known as|Rx|Tx|notes|
73
+ |------|--------|----|----|-----|
74
+ |0.0|Free Text | | | |
75
+ |0.1|DXpedition | | | Call1 RR73; Call2 +07|
76
+ |0.3|Field Day | | | |
77
+ |0.4|Field Day | | | |
78
+ |0.5|Telemetry | | | |
79
+ |1|Std Msg |Y| Y |Standard <=6 char callsigns, can include /R |
80
+ |2|EU VHF |Y|Y| Standard <=6 char callsigns, can include /P |
81
+ |3|RTTY RU | | | |
82
+ |4|NonStd Call |Y|Y| <=11 char callsigns + hashed call|
83
+ |5|EU VHF | | | |
84
+
70
85
 
71
- In pursuit of tight code, I've concentrated on core standard messages, leaving out some of the less-used features. The receive part of the
72
- code doesn't (yet) have the full capability of the advanced decoders used in WSJT-x, and so gets fewer decodes than WSJT-x gets, depending on band conditions (on a quiet band with only good signals PyFT8 will get close to 100%).
73
86
 
74
87
  ## Acknowledgements
75
88
  This project implements a decoder for the FT8 digital mode.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "PyFT8"
3
- version = "2.4.0"
3
+ version = "2.4.2"
4
4
  license = "GPL-3.0-or-later"
5
5
 
6
6
  authors = [
@@ -0,0 +1,30 @@
1
+
2
+ def meth1(a):
3
+ c = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4
+ x = a-1003
5
+ ci1 = x // (27*27*27)
6
+ x %= 27*27*27
7
+ ci2 = x // (27*27)
8
+ x %= 27*27
9
+ ci3 = x // 27
10
+ x %= 27
11
+ ci4 = x
12
+ aaaa = c[ci1] + c[ci2] + c[ci3] + c[ci4]
13
+ return f"CQ {aaaa}"
14
+
15
+
16
+ import numpy
17
+
18
+
19
+ def meth2(a):
20
+ c = " ABCDEFGHIJKLMNOPQRSTUVWXYZ"
21
+ x = int(a - 1003)
22
+ print(x)
23
+ txt = ''
24
+ for i in range(4):
25
+ txt = c[int(x % 27)] + txt
26
+ x /= 27
27
+ return f"CQ {txt}"
28
+
29
+ for a in [1004, 1029, 1031, 1731, 1760, 20685, 21443, 532443, 1135]:
30
+ print(meth1(a), meth2(a))
@@ -0,0 +1,10 @@
1
+ import pickle
2
+ def flat_list(worked_before_file = 'C:/Users/drala/Documents/Projects/GitHub/G1OJS/PyFT8_cfg/PyFT8_wb.pkl'):
3
+ with open(f"{worked_before_file}","rb") as f:
4
+ worked_before = pickle.load(f)
5
+ worked_before['dummy']=0
6
+ wb = sorted(worked_before.items(), key=lambda x: x[1])
7
+ for c in wb:
8
+ print(c)
9
+
10
+ flat_list()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes