|
| 1 | +#! /usr/bin/python3 |
| 2 | + |
| 3 | +##-------------------------------------------------------------------------------\ |
| 4 | +# tinySA_python (tsapython) |
| 5 | +# './examples/save_scan_csv.py' |
| 6 | +# A short example using matplotlib to plot requested SCAN data |
| 7 | +# |
| 8 | +# Last update: August 17, 2025 |
| 9 | +##-------------------------------------------------------------------------------\ |
| 10 | + |
| 11 | + |
| 12 | +# import tinySA_python (tsapython) package |
| 13 | +fromtsapythonimporttinySA |
| 14 | + |
| 15 | +# imports FOR THE EXAMPLE |
| 16 | +importcsv |
| 17 | +importnumpyasnp |
| 18 | + |
| 19 | +defconvert_data_to_arrays(start,stop,pts,data): |
| 20 | +# using the start and stop frequencies, and the number of points, |
| 21 | + |
| 22 | +freq_arr=np.linspace(start,stop,pts)# note that the decimals might go out to many places. |
| 23 | +# you can truncate this because its only used |
| 24 | +# for plotting in this example |
| 25 | + |
| 26 | +# As of the Jan. 2024 build in some data returned with SWEEP or SCAN calls there is error data. |
| 27 | +# https://groups.io/g/tinysa/topic/tinasa_ultra_sweep_command/104194367 |
| 28 | +# this shows up as "-:.000000e+01". |
| 29 | +# TEMP fix - replace the colon character with a -10. This puts the 'filled in' points around the noise floor. |
| 30 | +# more advanced filtering should be applied for actual analysis. |
| 31 | + |
| 32 | +data1=bytearray(data.replace(b"-:.0",b"-10.0")) |
| 33 | + |
| 34 | +# get both values in each row returned (for reference) |
| 35 | +#data_arr = [list(map(float, line.split())) for line in data.decode('utf-8').split('\n') if line.strip()] |
| 36 | + |
| 37 | +# get first value in each returned row |
| 38 | +data_arr= [float(line.split()[0])forlineindata1.decode('utf-8').split('\n')ifline.strip()] |
| 39 | + |
| 40 | +returnfreq_arr,data_arr |
| 41 | + |
| 42 | + |
| 43 | +# create a new tinySA object |
| 44 | +tsa=tinySA() |
| 45 | + |
| 46 | +# set the return message preferences |
| 47 | +tsa.set_verbose(True)#detailed messages |
| 48 | +tsa.set_error_byte_return(True)#get explicit b'ERROR' if error thrown |
| 49 | + |
| 50 | +# attempt to autoconnect |
| 51 | +found_bool,connected_bool=tsa.autoconnect() |
| 52 | + |
| 53 | +# if port closed, then return error message |
| 54 | +ifconnected_bool==False: |
| 55 | +print("ERROR: could not connect to port") |
| 56 | +else:# if port found and connected, then complete task(s) and disconnect |
| 57 | +# set scan values |
| 58 | +start=int(1e9)# 1 GHz |
| 59 | +stop=int(3e9)# 3 GHz |
| 60 | +pts=450# sample points |
| 61 | +outmask=2# get measured data (y axis) |
| 62 | + |
| 63 | +# scan |
| 64 | +data_bytes=tsa.scan(start,stop,pts,outmask) |
| 65 | + |
| 66 | +print(data_bytes) |
| 67 | + |
| 68 | +tsa.resume()#resume so screen isn't still frozen |
| 69 | + |
| 70 | +tsa.disconnect() |
| 71 | + |
| 72 | +# processing after disconnect (just for this example) |
| 73 | + |
| 74 | +# convert data to 2 arrays |
| 75 | +freq_arr,data_arr=convert_data_to_arrays(start,stop,pts,data_bytes) |
| 76 | + |
| 77 | + |
| 78 | +# Save the data to CSV |
| 79 | +filename="scan_sample.csv" |
| 80 | + |
| 81 | +# Write out to csv where column 1 is frequency and col 2 is data |
| 82 | +withopen(filename,'w',newline='')ascsvfile: |
| 83 | +writer=csv.writer(csvfile) |
| 84 | + |
| 85 | +# Write header row |
| 86 | +writer.writerow(['Frequency_Hz','Signal_Strength_dBm']) |
| 87 | + |
| 88 | +# Write data rows (frequency, signal strength pairs) |
| 89 | +forfreq,signalinzip(freq_arr,data_arr): |
| 90 | +writer.writerow([f'{freq:.0f}',signal]) |
| 91 | + |
| 92 | +print(f"Data saved to{filename}") |
| 93 | +print(f"CSV contains{len(freq_arr)} frequency/signal pairs") |
| 94 | + |
| 95 | + |
| 96 | +print(f"Data saved to{filename}") |