From c0ec0c1853901f1e31841675b6c6f46a6f3e643f Mon Sep 17 00:00:00 2001 From: DJ2LS <75909252+DJ2LS@users.noreply.github.com> Date: Fri, 6 Aug 2021 22:09:16 +0200 Subject: [PATCH] scatter plott support --- tnc/data_handler.py | 6 ++-- tnc/modem.py | 82 ++++++++++++++++++++++++++++++++++++++++----- tnc/sock.py | 26 ++++++++++++-- tnc/static.py | 2 ++ 4 files changed, 101 insertions(+), 15 deletions(-) diff --git a/tnc/data_handler.py b/tnc/data_handler.py index 84219186..883b3d9f 100644 --- a/tnc/data_handler.py +++ b/tnc/data_handler.py @@ -682,7 +682,7 @@ def received_ping_ack(data_in): static.DXGRID = bytes(data_in[3:9]).rstrip(b'\x00') - helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'PING-ACK') + helpers.add_to_heard_stations(static.DXCALLSIGN,static.DXGRID, 'PING-ACK', static.SNR) logging.info("PING [" + str(static.MYCALLSIGN, 'utf-8') + "] >|< [" + str(static.DXCALLSIGN, 'utf-8') + "]["+ str(static.DXGRID, 'utf-8') +"] [SNR:" + str(static.SNR) + "]") static.TNC_STATE = 'IDLE' @@ -723,7 +723,7 @@ def received_cq(data_in): dxgrid = bytes(data_in[8:14]).rstrip(b'\x00') logging.info("CQ RCVD [" + str(dxcallsign, 'utf-8') + "]["+ str(dxgrid, 'utf-8') +"] [SNR" + str(static.SNR) + "]") - helpers.add_to_heard_stations(dxcallsign,dxgrid, 'CQ CQ CQ') + helpers.add_to_heard_stations(dxcallsign,dxgrid, 'CQ CQ CQ', static.SNR) @@ -748,4 +748,4 @@ def received_beacon(): dxgrid = bytes(data_in[8:14]).rstrip(b'\x00') logging.info("BEACON RCVD [" + str(dxcallsign, 'utf-8') + "]["+ str(dxgrid, 'utf-8') +"] [SNR" + str(static.SNR) + "]") - helpers.add_to_heard_stations(dxcallsign,dxgrid, 'BEACON') + helpers.add_to_heard_stations(dxcallsign,dxgrid, 'BEACON', static.SNR) diff --git a/tnc/modem.py b/tnc/modem.py index 99439d9b..2ebbf559 100644 --- a/tnc/modem.py +++ b/tnc/modem.py @@ -31,6 +31,32 @@ import numpy as np from scipy.fft import fft, ifft from scipy import signal + + + +MODEM_STATS_NR_MAX = 320 +MODEM_STATS_NC_MAX = 51 + +class MODEMSTATS(ctypes.Structure): + _fields_ = [ + ("Nc", ctypes.c_int), + ("snr_est", ctypes.c_float), + ("rx_symbols", (ctypes.c_float * MODEM_STATS_NR_MAX)*MODEM_STATS_NC_MAX), + ("nr", ctypes.c_int), + ("sync", ctypes.c_int), + ("foff", ctypes.c_float), + ("rx_timing", ctypes.c_float), + ("clock_offset", ctypes.c_float), + ("sync_metric", ctypes.c_float), + ("pre", ctypes.c_int), + ("post", ctypes.c_int), + ("uw_fails", ctypes.c_int), + + ] + + + + class RF(): def __init__(self): @@ -437,13 +463,18 @@ class RF(): #print("listening-" + str(mode) + " - " + "nin: " + str(nin) + " - " + str(self.c_lib.freedv_get_rx_status(freedv))) self.calculate_snr(freedv) + self.get_scatter(freedv) # forward data only if broadcast or we are the receiver # bytes_out[1:2] == callsign check for signalling frames, bytes_out[6:7] == callsign check for data frames, bytes_out[1:2] == b'\x01' --> broadcasts like CQ # we could also create an own function, which returns True. In this case we could add callsign blacklists and so on + + + + if nbytes == bytes_per_frame and bytes(bytes_out[1:2]) == static.MYCALLSIGN_CRC8 or bytes(bytes_out[6:7]) == static.MYCALLSIGN_CRC8 or bytes(bytes_out[1:2]) == b'\x01': self.calculate_snr(freedv) - + static.SCATTER = [] # CHECK IF FRAMETYPE IS BETWEEN 10 and 50 ------------------------ frametype = int.from_bytes(bytes(bytes_out[:1]), "big") @@ -553,7 +584,40 @@ class RF(): # for debugging purposes to receive all data pass # print(bytes_out[:-2]) + def get_scatter(self, freedv): + modemStats = MODEMSTATS() + self.c_lib.freedv_get_modem_extended_stats.restype = None + #c_lib.freedv_get_modem_extended_stats.argtypes = c_void_p, [MODEMSTATS] + #c_lib.freedv_get_modem_extended_stats(freedv, modemStats) + self.c_lib.freedv_get_modem_extended_stats(freedv, ctypes.byref(modemStats)) + print("Nc: " + str(modemStats.Nc)) + #print("snr_est: " + str(modemStats.snr_est)) + print("nr: " + str(modemStats.nr)) + #data = [] +#MODEM_STATS_NR_MAX = 320 +#MODEM_STATS_NC_MAX = 51 + + scatterdata = [] + for i in range(MODEM_STATS_NC_MAX): + for j in range(MODEM_STATS_NR_MAX): + #xsymbols = modemStats.rx_symbols[i][j] + #xsymbols = modemStats.rx_symbols[i][::2] + #ysymbols = modemStats.rx_symbols[i][j+1] + + #check if odd or not to get every 2nd item for x + if (j % 2) == 0: + xsymbols = modemStats.rx_symbols[i][j] + ysymbols = modemStats.rx_symbols[i][j+1] + + if xsymbols != 0.0 and ysymbols != 0.0: + scatterdata.append({"x" : xsymbols, "y" : ysymbols }) + + # only append scatter data if new data arrived + if scatterdata != static.SCATTER: + static.SCATTER = scatterdata + + def calculate_ber(self, freedv): Tbits = self.c_lib.freedv_get_total_bits(freedv) Terrs = self.c_lib.freedv_get_total_bit_errors(freedv) @@ -593,11 +657,11 @@ class RF(): #static.FFT = fft_raw.tolist() #fft_raw = fft_raw.tobytes() - rate = 48000 - M = 1024 - freqs, times, Sx = signal.spectrogram(data_in_array, fs=rate, window='hanning', nperseg=1024, noverlap=M - 100, detrend=False, scaling='spectrum', return_onesided=True) + #rate = 48000 + #M = 1024 + #freqs, times, Sx = signal.spectrogram(data_in_array, fs=rate, window='hanning', nperseg=1024, noverlap=M - 100, detrend=False, scaling='spectrum', return_onesided=True) - freqs, times, Sx = signal.spectrogram(data_in_array, fs=rate, return_onesided=True, axis=-1) + #freqs, times, Sx = signal.spectrogram(data_in_array, fs=rate, return_onesided=True, axis=-1) @@ -608,8 +672,8 @@ class RF(): #print(fft_raw) #static.FFT = fft_raw.hex() #static.FFT = fft_raw - data_in = np.frombuffer(data_in, dtype=np.int16) - data = fft(data_in) + #data_in = np.frombuffer(data_in, dtype=np.int16) + #data = fft(data_in) #print(data) #data = getFFT(data_in, 48000, 2048) #print(data) @@ -620,13 +684,13 @@ class RF(): #data = np.frombuffer(data_in, dtype=np.int16) - data.resize((1,2048)) + #data.resize((1,2048)) #data = np.delete(data,0) #data = data.tobytes() #print(data) - static.FFT = data.tolist() + #static.FFT = data.tolist() #static.FFT = data.hex() def getFFT(data, rate, chunk_size, log_scale=False): diff --git a/tnc/sock.py b/tnc/sock.py index cff4239b..83e3234c 100644 --- a/tnc/sock.py +++ b/tnc/sock.py @@ -199,13 +199,15 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): "COMMAND": "STATION_INFO", "MY_CALLSIGN": str(static.MYCALLSIGN, encoding), "DX_CALLSIGN": str(static.DXCALLSIGN, encoding), - "DX_GRID": str(static.DXGRID, encoding) + "DX_GRID": str(static.DXGRID, encoding), + "EOF" : "EOF", } jsondata = json.dumps(output) self.request.sendall(bytes(jsondata, encoding)) if received_json["type"] == 'GET' and received_json["command"] == 'TNC_STATE': + print(static.SCATTER) output = { "COMMAND": "TNC_STATE", "PTT_STATE": str(static.PTT_STATE), @@ -219,6 +221,7 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): "MODE" : str(static.HAMLIB_MODE), "BANDWITH" : str(static.HAMLIB_BANDWITH), "FFT" : str(static.FFT), + "SCATTER" : static.SCATTER, #"RX_BUFFER_LENGTH": str(len(static.RX_BUFFER)), #"TX_N_MAX_RETRIES": str(static.TX_N_MAX_RETRIES), #"ARQ_TX_N_FRAMES_PER_BURST": str(static.ARQ_TX_N_FRAMES_PER_BURST), @@ -228,7 +231,9 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): #"ARQ_RX_FRAME_N_BURSTS": str(static.ARQ_RX_FRAME_N_BURSTS), #"ARQ_RX_N_CURRENT_ARQ_FRAME": str(static.ARQ_RX_N_CURRENT_ARQ_FRAME), #"ARQ_N_ARQ_FRAMES_PER_DATA_FRAME": str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) - } + "EOF" : "EOF", + } + jsondata = json.dumps(output) #print(len(jsondata)) @@ -242,6 +247,17 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): jsondata = json.dumps(output) self.request.sendall(bytes(jsondata, encoding)) + #if received_json["type"] == 'GET' and received_json["command"] == 'SCATTER': +# +# print(static.SCATTER) +# output = { +# "COMMAND" : "SCATTER", +# "DATA" : static.SCATTER +# } +# print(output) +# jsondata = json.dumps(output) +# self.request.sendall(bytes(jsondata, encoding)) + if received_json["type"] == 'GET' and received_json["command"] == 'DATA_STATE': output = { "COMMAND": "DATA_STATE", @@ -253,7 +269,8 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): "ARQ_TX_N_TOTAL_ARQ_FRAMES": str(int.from_bytes(bytes(static.ARQ_TX_N_TOTAL_ARQ_FRAMES), "big")), "ARQ_RX_FRAME_N_BURSTS": str(static.ARQ_RX_FRAME_N_BURSTS), "ARQ_RX_N_CURRENT_ARQ_FRAME": str(static.ARQ_RX_N_CURRENT_ARQ_FRAME), - "ARQ_N_ARQ_FRAMES_PER_DATA_FRAME": str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME) + "ARQ_N_ARQ_FRAMES_PER_DATA_FRAME": str(static.ARQ_N_ARQ_FRAMES_PER_DATA_FRAME), + "EOF" : "EOF", } jsondata = json.dumps(output) @@ -267,6 +284,9 @@ class CMDTCPRequestHandler(socketserver.BaseRequestHandler): for i in range(0, len(static.HEARD_STATIONS)): data["STATIONS"].append({"DXCALLSIGN": str(static.HEARD_STATIONS[i][0], 'utf-8'),"DXGRID": str(static.HEARD_STATIONS[i][1], 'utf-8'), "TIMESTAMP": static.HEARD_STATIONS[i][2], "DATATYPE": static.HEARD_STATIONS[i][3], "SNR": static.HEARD_STATIONS[i][4]}) # print(static.HEARD_STATIONS[i][1]) + + + #data.append({"EOF" : "EOF"}) jsondata = json.dumps(data) self.request.sendall(bytes(jsondata, encoding)) diff --git a/tnc/static.py b/tnc/static.py index 668ddad4..f7b13a14 100644 --- a/tnc/static.py +++ b/tnc/static.py @@ -80,6 +80,7 @@ FREEDV_SIGNALLING_PAYLOAD_PER_FRAME = 0 BER = 0 SNR = 0 +SCATTER = [] # --------------------------------- # Audio Defaults @@ -95,6 +96,7 @@ AUDIO_FRAMES_PER_BUFFER = 8192 # 256 # 512 # 1024 #2048 --> nicht 880 AUDIO_CHANNELS = 1 AUDIO_RMS = 0 FFT = [] + # --------------------------------- # ARQ DEFAULTS