示例#1
0
    def closecurrenttab(self):
        try:
            reply = QMessageBox.question(self, 'Message',
                "Are you sure to close the current tab?", QMessageBox.Yes | 
                QMessageBox.No, QMessageBox.No)

            if reply == QMessageBox.Yes:

                #getting tab to close
                curtab = int(self.whatTab())
                curtabstr = "Tab " + str(curtab)
                indextoclose = self.tabWidget.currentIndex()
                
                #add any additional necessary commands (stop threads, prevent memory leaks, etc) here
                
                #closing tab
                self.tabWidget.removeTab(indextoclose)

                #removing current tab data from the alltabdata dict, correcting tabnumbers variable
                alltabdata.pop("Tab "+str(curtab))
                self.tabnumbers.pop(indextoclose)

        except Exception:
            trace_error()
            self.posterror("Failed to close the current tab")
示例#2
0
    def run(self):
        #initialize lastgooddata. This is overwritten if a good fix is achieved and is reinitialized every time the signal is emitted
        lastgooddata = (1, self.default_lat, self.default_lon, self.default_datetime, self.default_nsat, self.default_qual, self.default_alt)
        while True: #outer loop- always running
            try:
                if self.comport.lower() == "n":
                    self.keepGoing = True
                    while self.keepGoing: #loop indefinitely, do nothing, wait for signal to attempt connection with GPS receiver
                        sleep(0.5)
                
                else: #different port listed- attempt to connect
                    self.keepGoing = True
                    last_time = self.default_datetime
                    self.nbadsig = 0
                    
                    with Serial(self.comport, self.baudrate, timeout=1) as ser:
                        while self.keepGoing: #until interrupted
                        
                            try:
                                nmeaobj = parse(ser.readline(96).decode('ascii', errors='replace').strip())
                                success, data = self.parsegpsdata(nmeaobj)
                            except (nmea.ParseError, OSError):
                                success = False
                                data = (self.default_lat, self.default_lon, self.default_datetime, self.default_nsat, self.default_qual, self.default_alt)
                            
                            #if all of the data is acceptable overwrite the lastgooddata with the most recent fix info
                            if success and (data[0] != 0 and data[1] != 0 and data[3] > -1 and data[4] > -1 and data[5] > -1):
                                lastgooddata = (0, data[0], data[1], data[2], data[3], data[4], data[5])
                                

                                                                    
                            cdt = datetime.utcnow()
                            #only transmit an update if a certain amount of time has passed and it was a good signal
                            if (cdt - last_time).total_seconds() >= self.updatenseconds:
                                last_time = cdt
                                #if the lastgooddata has contains a good fix
                                if lastgooddata[0] == 0:
                                    #emit the data
                                    self.signals.update.emit(lastgooddata[0], lastgooddata[1], lastgooddata[2], lastgooddata[3], lastgooddata[4], lastgooddata[5], lastgooddata[6])
                                    #reset lastgooddata after the signal is emitted
                                    lastgooddata = (1, self.default_lat, self.default_lon, self.default_datetime, self.default_nsat, self.default_qual, self.default_alt)
                                    #reset the number of bad signals (counted based off the number of failed updates)
                                    self.nbadsig = 0 

                                else:
                                    #change the 
                                    self.nbadsig += 1 #add one to the number of bad signals if the update 
                                    
                            #if there have been too many consecutive failed signals, return to the default
                            if self.nbadsig > self.badsiglimit:
                                self.signals.update.emit(lastgooddata[0], lastgooddata[1], lastgooddata[2], lastgooddata[3], lastgooddata[4], lastgooddata[5], lastgooddata[6])
                                #reset lastgooddata after the info is emitted
                                lastgooddata = (1, self.default_lat, self.default_lon, self.default_datetime, self.default_nsat, self.default_qual, self.default_alt)
                                self.nbadsig = 0
                        
                        
            except Exception: #fails to connect to serial port
                trace_error()
                self.comport = "n"
                self.signals.update.emit(2, 0, 0, datetime(1,1,1), 0, 0, 0)
示例#3
0
                def updateaudiobuffer(streampointer_int, bufferpointer_int,
                                      size, samplerate):

                    try:
                        self.numcontacts += 1  #note that the buffer has been pulled again
                        bufferlength = int(size / 2)
                        bufferpointer = cast(bufferpointer_int,
                                             POINTER(c_int16 * bufferlength))
                        bufferdata = bufferpointer.contents
                        self.f_s = samplerate
                        self.nframes += bufferlength
                        self.audiostream.extend(
                            bufferdata[:])  #append data to end
                        del self.audiostream[:
                                             bufferlength]  #remove data from start

                        #recording to wav file: this terminates if the file exceeds a certain length
                        if self.isrecordingaudio and self.nframes > self.maxsavedframes:
                            self.isrecordingaudio = False
                            self.killaudiorecording()
                        elif self.isrecordingaudio:
                            wave.Wave_write.writeframes(
                                self.wavfile, bytearray(bufferdata))

                    except Exception:  #error handling for callback
                        trace_error()
                        self.kill(10)
示例#4
0
    def kill(self, reason):
        #NOTE: function contains 0.3 seconds of sleep to prevent race conditions between the processor loop, callback function and main GUI event loop
        try:
            self.waittoterminate = True  #keeps run method from terminating until kill process completes
            self.keepgoing = False  # kills while loop
            curtabnum = self.curtabnum

            timemodule.sleep(
                0.3)  #gives thread 0.1 seconds to finish current segment

            if reason != 0:  #notify event loop that processor failed if non-zero exit code provided
                self.signals.failed.emit(self.curtabnum, reason)

            self.isrecordingaudio = False
            if not self.isfromaudio and not self.isfromtest:
                self.wrdll.SetupStreams(self.hradio, None, None, None, None)
                timemodule.sleep(
                    0.3
                )  #additional 0.1 seconds after stream directed to null before closing wav file
                wave.Wave_write.close(self.wavfile)
                self.wrdll.CloseRadioDevice(self.hradio)

            self.signals.terminated.emit(
                curtabnum)  # emits signal that processor has been terminated
            self.txtfile.close()

        except Exception:
            trace_error()
            self.signals.failed.emit(self.curtabnum, 10)

        self.waittoterminate = False  #allow run method to terminate
示例#5
0
    def savedataincurtab(self):
        try:
            #getting directory to save files from QFileDialog
            outdir = str(QFileDialog.getExistingDirectory(self, "Select Directory to Save File(s)"))
            if outdir == '':
                QApplication.restoreOverrideCursor()
                return False
        except:
            self.posterror("Error raised in directory selection")
            return

        try:
            QApplication.setOverrideCursor(Qt.WaitCursor)
            
            #pulling all relevant data
            curtabstr = "Tab " + str(self.whatTab())
            
            #write code to save open files here
                
        except Exception:
            trace_error() #if something else in the file save code broke
            self.posterror("Filed to save files")
            QApplication.restoreOverrideCursor()
            return False
        finally:
            QApplication.restoreOverrideCursor()
            return True
示例#6
0
 def killaudiorecording(self):
     try:
         self.isrecordingaudio = False
         wave.Wave_write.close(self.wavfile)  #close WAV file
         self.signals.failed.emit(self.curtabnum,
                                  13)  #pass warning message back to GUI
     except Exception:
         trace_error()
         self.kill(10)
示例#7
0
 def renametab(self):
     try:
         curtab = self.tabWidget.currentIndex()
         name, ok = QInputDialog.getText(self, 'Rename Current Tab', 'Enter new tab name:',QLineEdit.Normal,str(self.tabWidget.tabText(curtab)))
         if ok:
             self.tabWidget.setTabText(curtab,name)
     except Exception:
         trace_error()
         self.posterror("Failed to rename the current tab")
示例#8
0
def add_asterisk(self):
    try:
        curtab = self.tabWidget.currentIndex()
        curtabstr = "Tab " + str(self.whatTab())
        name = self.tabWidget.tabText(curtab)
        if not self.alltabdata[curtabstr]["profileSaved"] and name[-1] != '*':
            self.tabWidget.setTabText(curtab, name + '*')
    except Exception:
        trace_error()
        self.posterror("Failed to add unsave asterisk to tab name")
示例#9
0
 def changecurrentfrequency(self,
                            newfreq):  #update VHF frequency for WiNRADIO
     # change frequency- kill if failed
     try:
         self.vhffreq_2WR = c_ulong(int(newfreq * 1E6))
         if self.wrdll.SetFrequency(self.hradio, self.vhffreq_2WR) == 0:
             self.kill(4)
     except Exception:
         trace_error()
         self.kill(4)
示例#10
0
def remove_asterisk(self):
    try:
        curtab = self.tabWidget.currentIndex()
        curtabstr = "Tab " + str(self.whatTab())
        name = self.tabWidget.tabText(curtab)
        if self.alltabdata[curtabstr]["profileSaved"] and name[-1] == '*':
            self.tabWidget.setTabText(curtab, name[:-1])
    except Exception:
        trace_error()
        self.posterror("Failed to remove unsave asterisk from tab name")
示例#11
0
    def __init__(self):
        super().__init__()
        
        try:
            self.initUI() #creates GUI window
            self.buildmenu() #Creates interactive menu, options to create tabs and start autoQC
            self.makenewtab() #Opens first tab

        except Exception:
            trace_error()
            self.posterror("Failed to initialize the program.")
示例#12
0
 def __init__(self):
     super().__init__()
     
     try:
         self.initUI() #creates GUI window
         self.buildmenu() #Creates interactive menu, options to create tabs and run ARES systems
         self.loaddata() #loads climo and bathy data into program first if using the full datasets
         self.makenewprocessortab() # opens a data acquisition tab on startup
         
     except Exception:
         trace_error()
         self.posterror("Failed to initialize the program.")
示例#13
0
def closecurrenttab(self):
    try:

        curtab = int(self.whatTab())
        curtabstr = "Tab " + str(curtab)
        if self.alltabdata[curtabstr]["tabtype"] == "MissionTracker":
            self.postwarning("You cannot close the mission tracker tab!")
            return

        reply = QMessageBox.question(self, 'Message',
                                     "Are you sure to close the current tab?",
                                     QMessageBox.Yes | QMessageBox.No,
                                     QMessageBox.No)

        if reply == QMessageBox.Yes:

            #getting tab to close
            indextoclose = self.tabWidget.currentIndex()

            #check to make sure there isn't a corresponding processor thread, close if there is
            if self.alltabdata[curtabstr]["isprocessing"]:
                reply = QMessageBox.question(
                    self, 'Message',
                    "Closing this tab will terminate the current profile and discard the data. Continue?",
                    QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
                if reply == QMessageBox.No:
                    return
                else:
                    self.alltabdata[curtabstr]["processor"].abort()

            #closing open figures in tab to prevent memory leak
            if self.alltabdata[curtabstr]["tabtype"] == "ProfileEditor":
                plt.close(self.alltabdata[curtabstr]["ProfFig"])
                plt.close(self.alltabdata[curtabstr]["LocFig"])

            elif self.alltabdata[curtabstr][
                    "tabtype"] == 'SignalProcessor_incomplete' or self.alltabdata[
                        curtabstr]["tabtype"] == 'SignalProcessor_completed':
                plt.close(self.alltabdata[curtabstr]["ProcessorFig"])

            #closing tab
            self.tabWidget.removeTab(indextoclose)

            #removing current tab data from the self.alltabdata dict, correcting tabnumbers variable
            self.alltabdata.pop("Tab " + str(curtab))
            self.tabnumbers.pop(indextoclose)

    except Exception:
        trace_error()
        self.posterror("Failed to close the current tab")
示例#14
0
def renametab(self):
    try:
        curtab = self.tabWidget.currentIndex()
        curtabstr = "Tab " + str(self.whatTab())
        badcharlist = "[@!#$%^&*()<>?/\|}{~:]"
        strcheck = re.compile(badcharlist)
        name, ok = QInputDialog.getText(self, 'Rename Current Tab',
                                        'Enter new tab name:',
                                        QLineEdit.Normal,
                                        str(self.tabWidget.tabText(curtab)))
        if ok:
            if strcheck.search("name") == None:
                self.tabWidget.setTabText(curtab, name)
                if not self.alltabdata[curtabstr][
                        "profileSaved"]:  #add an asterisk if profile is unsaved
                    self.add_asterisk()
            else:
                self.postwarning("Tab names cannot include the following: " +
                                 badcharlist)
    except Exception:
        trace_error()
        self.posterror("Failed to rename the current tab")
示例#15
0
def parsestringinputs(self, latstr, lonstr, profdatestr, timestr, identifier,
                      checkcoords, checktime, checkid):
    try:
        #parsing and checking data
        if checkcoords:
            try:
                #checking latitude validity
                latstr = latstr.split(',')
                latsign = np.sign(float(latstr[0]))
                if len(latstr) == 3:
                    lat = float(latstr[0]) + latsign * float(
                        latstr[1]) / 60 + latsign * float(latstr[2]) / 3600
                elif len(latstr) == 2:
                    lat = float(latstr[0]) + latsign * float(latstr[1]) / 60
                else:
                    lat = float(latstr[0])
            except:
                self.postwarning('Invalid Latitude Entered!')
                return

            try:
                #checking longitude validity
                lonstr = lonstr.split(',')
                lonsign = np.sign(float(lonstr[0]))
                if len(lonstr) == 3:
                    lon = float(lonstr[0]) + lonsign * float(
                        lonstr[1]) / 60 + lonsign * float(lonstr[2]) / 3600
                elif len(lonstr) == 2:
                    lon = float(lonstr[0]) + lonsign * float(lonstr[1]) / 60
                else:
                    lon = float(lonstr[0])
            except:
                self.postwarning('Invalid Longitude Entered!')
                return

            if lon < -180 or lon > 180:
                self.postwarning('Longitude must be between -180 and 180')
            elif lat < -90 or lat > 90:
                self.postwarning('Latitude must be between -90 and 90')

            lon = round(lon, 3)
            lat = round(lat, 3)

        else:
            lon = np.NaN
            lat = np.NaN

        if checktime:  #checking time
            if len(timestr) != 4:
                self.postwarning('Invalid Time Format (must be HHMM)!')
                return
            elif len(profdatestr) != 8:
                self.postwarning('Invalid Date Format (must be YYYYMMDD)!')
                return

            try:  #checking date
                year = int(profdatestr[:4])
                month = int(profdatestr[4:6])
                day = int(profdatestr[6:])
            except:
                self.postwarning('Invalid (non-numeric) Date Entered!')
                return
            try:
                time = int(timestr)
                hour = int(timestr[:2])
                minute = int(timestr[2:4])
            except:
                self.postwarning('Invalid (non-numeric) Time Entered!')
                return

            if year < 1938 or year > 3000:  #year the bathythermograph was invented and the year by which it was probably made obsolete
                self.postwarning(
                    'Invalid Year Entered (< 1938 AD or > 3000 AD)!')
                return
            elif month <= 0 or month > 12:
                self.postwarning(
                    "Invalid Month Entered (must be between 1 and 12)")
                return
            elif hour > 23 or hour < 0:
                self.postwarning(
                    'Invalid Time Entered (hour must be between 0 and 23')
                return
            elif minute >= 60 or minute < 0:
                self.postwarning(
                    'Invalid Time Entered (minute must be between 0 and 59')
                return

            #figuring out number of days in month
            monthnames = [
                'January', 'February', 'March', 'April', 'May', 'June', 'July',
                'August', 'September', 'October', 'November', 'December'
            ]
            if month in [1, 3, 5, 7, 8, 10, 12]:
                maxdays = 31
            elif month in [4, 6, 9, 11]:
                maxdays = 30
            elif month == 2 and year % 4 == 0:
                maxdays = 29
            elif month == 2:
                maxdays = 28
            else:
                self.postwarning('Invalid month entered!')

            #checking to make sure days are in valid range
            if day <= 0 or day > maxdays:
                self.postwarning(
                    f"Invalid Day Entered (must be between 1 and {maxdays} for {monthnames[month-1]})"
                )
                return

            #making sure the profile is within 12 hours and not in the future, warning if otherwise
            curtime = timemodule.gmtime()
            deltat = dt.datetime(
                curtime[0], curtime[1], curtime[2], curtime[3], curtime[4],
                curtime[5]) - dt.datetime(year, month, day, hour, minute, 0)
            option = ''
            if self.settingsdict["dtgwarn"]:
                if deltat.days < 0:
                    option = self.postwarning_option(
                        "Drop time appears to be after the current time. Continue anyways?"
                    )
                elif deltat.days > 1 or (deltat.days == 0
                                         and deltat.seconds > 12 * 3600):
                    option = self.postwarning_option(
                        "Drop time appears to be more than 12 hours ago. Continue anyways?"
                    )
                if option == 'cancel':
                    return
        else:
            year = np.NaN
            month = np.NaN
            day = np.NaN
            time = np.NaN
            hour = np.NaN
            minute = np.NaN

        #check length of identifier
        if checkid and len(identifier) != 5:
            option = self.postwarning_option(
                "Identifier is not 5 characters! Continue anyways?")
            if option == 'cancel':
                return

        return lat, lon, year, month, day, time, hour, minute, identifier
    except Exception:
        trace_error()
        self.posterror("Unspecified error in reading profile information!")
        return
示例#16
0
    def run(self):

        #barrier to prevent signal processor loop from starting before __init__ finishes
        counts = 0
        while self.startthread != 100:
            counts += 1
            if counts > 100 or not self.keepgoing:  #give up and terminate after 10 seconds waiting for __init__
                self.kill(12)
                return
            elif self.startthread != 0 and self.startthread != 100:  #if the audio file couldn't be read in properly
                self.kill(
                    self.startthread
                )  #waits to run kill commands due to errors raised in __init__ until run() since slots+signals may not be connected to parent thread during init
                return
            timemodule.sleep(0.1)
        #if the Run() method gets this far, __init__ has completed successfully (and set self.startthread = 100)

        try:

            if not self.isfromaudio and not self.isfromtest:  #if source is a receiver

                #Declaring the callbuck function to update the audio buffer
                @CFUNCTYPE(None, c_void_p, c_void_p, c_ulong, c_ulong)
                def updateaudiobuffer(streampointer_int, bufferpointer_int,
                                      size, samplerate):

                    try:
                        self.numcontacts += 1  #note that the buffer has been pulled again
                        bufferlength = int(size / 2)
                        bufferpointer = cast(bufferpointer_int,
                                             POINTER(c_int16 * bufferlength))
                        bufferdata = bufferpointer.contents
                        self.f_s = samplerate
                        self.nframes += bufferlength
                        self.audiostream.extend(
                            bufferdata[:])  #append data to end
                        del self.audiostream[:
                                             bufferlength]  #remove data from start

                        #recording to wav file: this terminates if the file exceeds a certain length
                        if self.isrecordingaudio and self.nframes > self.maxsavedframes:
                            self.isrecordingaudio = False
                            self.killaudiorecording()
                        elif self.isrecordingaudio:
                            wave.Wave_write.writeframes(
                                self.wavfile, bytearray(bufferdata))

                    except Exception:  #error handling for callback
                        trace_error()
                        self.kill(10)

                #end of callback function

                # initializes audio callback function
                if self.wrdll.SetupStreams(self.hradio, None, None,
                                           updateaudiobuffer,
                                           c_int(self.curtabnum)) == 0:
                    self.kill(7)
                else:
                    timemodule.sleep(0.3)  # gives the buffer time to populate

            else:  #if source is an audio file
                #configuring sample times for the audio file
                self.lensignal = len(self.audiostream)
                self.maxtime = self.lensignal / self.f_s
                self.sampletimes = np.arange(0.1, self.maxtime - 0.1, 0.1)

            # setting up thread while loop- terminates when user clicks "STOP" or audio file finishes processing
            i = -1

            #MAIN PROCESSOR LOOP
            while self.keepgoing:
                i += 1

                # finds time from profile start in seconds
                curtime = dt.datetime.utcnow()  # current time
                deltat = curtime - self.starttime
                ctime = deltat.total_seconds()

                if not self.isfromaudio and not self.isfromtest:

                    #protocal to kill thread if connection with WiNRADIO is lost
                    if self.numcontacts == self.lastcontacts:  #checks if the audio stream is receiving new data
                        self.disconnectcount += 1
                    else:
                        self.disconnectcount = 0
                        self.lastcontacts = self.numcontacts

                    #if the audio stream hasn't received new data for several iterations and checking device connection fails
                    if self.disconnectcount >= 30 and not self.wrdll.IsDeviceConnected(
                            self.hradio):
                        self.kill(8)

                    # listens to current frequency, gets sound level, set audio stream, and corresponding time
                    currentdata = self.audiostream[-int(self.f_s *
                                                        self.fftwindow):]
                else:

                    #kill test/audio threads once time exceeds the max time of the audio file
                    #NOTE: need to do this on the cycle before hitting the max time when processing from audio because
                    #       the WAV file processes faster than the thread can kill itself
                    if (self.isfromtest
                            and ctime >= self.maxtime - self.fftwindow) or (
                                self.isfromaudio
                                and i >= len(self.sampletimes) - 1):
                        self.keepgoing = False
                        self.kill(0)
                        return

                    #getting current time to sample from audio file
                    if self.isfromaudio:
                        ctime = self.sampletimes[i]
                        if i % 10 == 0:  #updates progress every 10 data points
                            self.signals.updateprogress.emit(
                                self.curtabnum,
                                int(ctime / self.maxtime * 100))

                    #getting current data to sample from audio file- using indices like this is much more efficient than calculating times and using logical arrays
                    ctrind = int(np.round(ctime * self.f_s))
                    pmind = int(
                        np.min([
                            np.round(self.f_s * self.fftwindow / 2), ctrind,
                            self.lensignal - ctrind - 1
                        ]))  #uses minimum value so no overflow
                    currentdata = self.audiostream[ctrind - pmind:ctrind +
                                                   pmind]

                #conducting FFT or skipping, depending on signal strength
                fp, Sp, Rp = dofft(currentdata, self.f_s, self.flims)

                #rounding before comparisons happen
                ctime = np.round(ctime, 1)
                fp = np.round(fp, 2)
                Sp = np.round(Sp, 2)
                Rp = np.round(Rp, 3)

                #writing raw data to sigdata file (ASCII) for current thread- before correcting for minratio/minsiglev
                if self.keepgoing:  #only writes if thread hasn't been stopped since start of current segment
                    self.txtfile.write(f"{ctime},{fp},{Sp},{Rp}\n")

                #logic to determine whether or not profile is triggered
                if not self.istriggered and Sp >= self.triggersiglev and Rp >= self.triggerfftratio:
                    self.istriggered = True
                    self.firstpointtime = ctime
                    if self.keepgoing:  #won't send if keepgoing stopped since current iteration began
                        self.signals.triggered.emit(self.curtabnum, ctime)

                #logic to determine whether or not point is valid
                if self.istriggered and Sp >= self.minsiglev and Rp >= self.minfftratio:
                    cdepth = btconvert(ctime - self.firstpointtime,
                                       self.zcoeff)
                    ctemp = btconvert(fp, self.tcoeff)

                else:
                    fp = 0
                    ctemp = cdepth = np.NaN

                # tells GUI to update data structure, plot, and table
                ctemp = np.round(ctemp, 2)
                cdepth = np.round(cdepth, 1)
                if self.keepgoing:  #won't send if keepgoing stopped since current iteration began
                    self.signals.iterated.emit(self.curtabnum, ctemp,
                                               cdepth, fp, Sp,
                                               np.round(100 * Rp, 1), ctime, i)

                if not self.isfromaudio:
                    timemodule.sleep(
                        0.1)  #pauses when processing in realtime (fs ~ 10 Hz)
                else:
                    timemodule.sleep(
                        0.001
                    )  #slight pause to free some resources when processing from audio

        except Exception:  #if the thread encounters an error, terminate
            trace_error()  # if there is an error, terminates processing
            if self.keepgoing:
                self.kill(10)

        while self.waittoterminate:  #waits for kill process to complete to avoid race conditions with audio buffer callback
            timemodule.sleep(0.1)
示例#17
0
    def __init__(self, wrdll, datasource, vhffreq, curtabnum, starttime,
                 istriggered, firstpointtime, fftwindow, minfftratio,
                 minsiglev, triggerfftratio, triggersiglev, tcoeff, zcoeff,
                 flims, slash, tempdir, *args, **kwargs):
        super(ThreadProcessor, self).__init__()

        #prevents Run() method from starting before init is finished (value must be changed to 100 at end of __init__)
        self.startthread = 0

        # UI inputs
        self.curtabnum = curtabnum
        self.starttime = starttime
        self.istriggered = istriggered
        self.firstpointtime = firstpointtime

        self.keepgoing = True  # signal connections
        self.waittoterminate = False  #whether to pause on termination of run loop for kill process to complete
        self.signals = ThreadProcessorSignals()

        #FFT thresholds
        self.fftwindow = fftwindow
        self.minfftratio = minfftratio
        self.minsiglev = minsiglev
        self.triggerfftratio = triggerfftratio
        self.triggersiglev = triggersiglev

        #conversion coefficients + parameters
        self.tcoeff = tcoeff
        self.zcoeff = zcoeff
        self.flims = flims

        #output file names
        self.txtfilename = tempdir + slash + "sigdata_" + str(
            self.curtabnum) + '.txt'
        self.txtfile = open(self.txtfilename, 'w')
        self.wavfilename = tempdir + slash + "tempwav_" + str(
            self.curtabnum) + '.WAV'

        #to prevent ARES from consuming all computer's resources- this limits the size of WAV files used by the signal processor to a number of PCM datapoints corresponding to 1 hour of audio @ fs=64 kHz, that would produce a wav file of ~0.5 GB for 16-bit PCM data
        self.maxsavedframes = 2.5E8
        self.isrecordingaudio = True  #initialized to True for all cases (RF, test, and audio) but only matters in the callback function assigned for RF receivers

        # identifying whether tab is audio, test, or other format
        self.isfromaudio = False
        self.isfromtest = False

        if datasource[:5] == 'Audio':
            self.chselect = int(datasource[5:10])
            self.audiofile = datasource[10:]
            self.isfromaudio = True

            #checking file length- wont process files with more frames than max size
            try:  #exception if unable to read audio file if it doesn't exist or isn't WAV formatted
                file_info = wave.open(self.audiofile)
            except:
                self.startthread = 11
                return

            if file_info.getnframes() > self.maxsavedframes:
                self.startthread = 9
                return

            self.f_s, snd = wavfile.read(self.audiofile)  #reading file

            #if multiple channels, sum them together
            sndshape = np.shape(snd)  #array size (tuple)
            ndims = len(sndshape)  #number of dimensions
            if ndims == 1:  #if one channel, use that
                self.audiostream = snd
            elif ndims == 2:  #if two channels, pick selected channel, otherwise sum
                if self.chselect >= 1:
                    self.audiostream = snd[:, self.chselect - 1]
                else:
                    self.audiostream = np.sum(snd, axis=1)

            else:  #if more than 2D- not a valid file
                self.audiostream = [0] * 10000
                self.startthread = 11

        elif datasource == 'Test':  #test run- use included audio file
            self.audiofile = 'testdata/MZ000006.WAV'
            self.isfromtest = True

            try:  #exception if unable to read audio file if it doesn't exist or isn't WAV formatted
                self.f_s, snd = wavfile.read(self.audiofile)
            except:
                self.startthread = 11
                return

            self.audiostream = snd[:, 0]

        #if thread is to be connected to a WiNRADIO
        if not self.isfromaudio and not self.isfromtest:

            #initializing variables to check if WiNRADIO remains connected
            self.disconnectcount = 0
            self.numcontacts = 0
            self.lastcontacts = 0
            self.nframes = 0

            # initialize audio stream data variables
            self.f_s = 64000  # default value
            self.audiostream = [
                0
            ] * 2 * self.f_s  #initializes the buffer with 2 seconds of zeros

            # saves WiNRADIO DLL/API library
            self.wrdll = wrdll

            # initialize winradio
            self.serial = datasource  # translate winradio identifier
            self.serialnum_2WR = c_char_p(self.serial.encode('utf-8'))

            #setup WAV file to write (if audio or test, source file is copied instead)
            self.wavfile = wave.open(self.wavfilename, 'wb')
            wave.Wave_write.setnchannels(self.wavfile, 1)
            wave.Wave_write.setsampwidth(self.wavfile, 2)
            wave.Wave_write.setframerate(self.wavfile, self.f_s)
            wave.Wave_write.writeframes(self.wavfile,
                                        bytearray(self.audiostream))

            #opening current WiNRADIO/establishing contact
            self.hradio = self.wrdll.Open(self.serialnum_2WR)
            if self.hradio == 0:
                self.startthread = 1
                return

            try:
                # power on- kill if failed
                if wrdll.SetPower(self.hradio, True) == 0:
                    self.startthread = 2
                    return

                # initialize demodulator- kill if failed
                if wrdll.InitializeDemodulator(self.hradio) == 0:
                    self.startthread = 3
                    return

                # change frequency- kill if failed
                self.vhffreq_2WR = c_ulong(int(vhffreq * 1E6))
                if self.wrdll.SetFrequency(self.hradio, self.vhffreq_2WR) == 0:
                    self.startthread = 4
                    return

                # set volume- warn if failed
                if self.wrdll.SetVolume(self.hradio, 31) == 0:
                    self.startthread = 5
                    return

            except Exception:  #if any WiNRADIO comms/initialization attempts failed, terminate thread
                trace_error()
                self.startthread = 6
                return
        else:
            shcopy(self.audiofile, self.wavfilename
                   )  #copying audio file if datasource = Test or Audio

        self.startthread = 100
示例#18
0
def savedataincurtab(self):

    successval = True  #changes to False if error is raised

    try:
        #getting directory to save files from QFileDialog
        try:
            outdir = str(
                QFileDialog.getExistingDirectory(
                    self, "Select Directory to Save File(s)",
                    self.defaultfilewritedir, QFileDialog.DontUseNativeDialog))
        except Exception:
            trace_error()
            return False

        #checking directory validity
        if outdir == '':
            QApplication.restoreOverrideCursor()
            return False
        else:
            self.defaultfilewritedir = outdir

    except:
        self.posterror("Error raised in directory selection")
        return

    try:
        QApplication.setOverrideCursor(Qt.WaitCursor)

        #pulling all relevant data
        curtabstr = "Tab " + str(self.whatTab())

        if self.alltabdata[curtabstr]["tabtype"] == "ProfileEditor":
            try:
                rawtemperature = self.alltabdata[curtabstr]["profdata"][
                    "temp_raw"]
                rawdepth = self.alltabdata[curtabstr]["profdata"]["depth_raw"]
                climotempfill = self.alltabdata[curtabstr]["profdata"][
                    "climotempfill"]
                climodepthfill = self.alltabdata[curtabstr]["profdata"][
                    "climodepthfill"]
                temperature = self.alltabdata[curtabstr]["profdata"][
                    "temp_plot"]
                depth = self.alltabdata[curtabstr]["profdata"]["depth_plot"]
                day = self.alltabdata[curtabstr]["profdata"]["day"]
                month = self.alltabdata[curtabstr]["profdata"]["month"]
                year = self.alltabdata[curtabstr]["profdata"]["year"]
                time = self.alltabdata[curtabstr]["profdata"]["time"]
                lat = self.alltabdata[curtabstr]["profdata"]["lat"]
                lon = self.alltabdata[curtabstr]["profdata"]["lon"]
                identifier = self.alltabdata[curtabstr]["profdata"]["ID"]
                num = 99  #placeholder- dont have drop number here currently!!

                dtg = str(year) + str(month).zfill(2) + str(day).zfill(
                    2) + str(time).zfill(4)
                curtab = self.tabWidget.currentIndex()
                filename = self.check_filename(dtg)

                if self.settingsdict["overlayclimo"]:
                    matchclimo = self.alltabdata[curtabstr]["profdata"][
                        "matchclimo"]
                else:
                    matchclimo = 1

            except:
                self.posterror("Failed to retrieve profile information")
                QApplication.restoreOverrideCursor()
                return False

            if self.settingsdict["savefin"]:
                try:
                    depth1m = np.arange(0, np.floor(depth[-1]))
                    temperature1m = np.interp(depth1m, depth, temperature)
                    tfio.writefinfile(outdir + slash + filename + '.fin',
                                      temperature1m, depth1m, day, month, year,
                                      time, lat, lon, num)
                except Exception:
                    trace_error()
                    self.posterror("Failed to save FIN file")
            if self.settingsdict["savejjvv"]:
                isbtmstrike = self.alltabdata[curtabstr]["tabwidgets"][
                    "isbottomstrike"].isChecked()
                try:
                    tfio.writejjvvfile(outdir + slash + filename + '.jjvv',
                                       temperature, depth, day, month, year,
                                       time, lat, lon, identifier, isbtmstrike)
                except Exception:
                    trace_error()
                    self.posterror("Failed to save JJVV file")
            if self.settingsdict["savebufr"]:
                try:
                    tfio.writebufrfile(outdir + slash + filename + '.bufr',
                                       temperature, depth, year, month, day,
                                       time, lon, lat, identifier,
                                       self.settingsdict["originatingcenter"],
                                       False, b'\0')
                except Exception:
                    trace_error()
                    self.posterror("Failed to save BUFR file")
            if self.settingsdict["saveprof"]:
                try:
                    fig1 = plt.figure()
                    fig1.clear()
                    ax1 = fig1.add_axes([0.1, 0.1, 0.85, 0.85])
                    climohandle = tplot.makeprofileplot(
                        ax1, rawtemperature, rawdepth, temperature, depth,
                        climotempfill, climodepthfill, dtg, matchclimo)
                    if self.settingsdict["overlayclimo"] == 0:
                        climohandle.set_visible(False)
                    fig1.savefig(outdir + slash + filename + '_prof.png',
                                 format='png')
                except Exception:
                    trace_error()
                    self.posterror("Failed to save profile image")
                finally:
                    plt.close('fig1')

            if self.settingsdict["saveloc"]:
                try:
                    fig2 = plt.figure()
                    fig2.clear()
                    ax2 = fig2.add_axes([0.1, 0.1, 0.85, 0.85])
                    _, exportlat, exportlon, exportrelief = oci.getoceandepth(
                        lat, lon, 6, self.bathymetrydata)
                    tplot.makelocationplot(fig2, ax2, lat, lon, dtg, exportlon,
                                           exportlat, exportrelief, 6)
                    fig2.savefig(outdir + slash + filename + '_loc.png',
                                 format='png')
                except Exception:
                    trace_error()
                    self.posterror("Failed to save location image")
                finally:
                    plt.close('fig2')

        elif self.alltabdata[curtabstr][
                "tabtype"] == "SignalProcessor_completed":

            if self.alltabdata[curtabstr]["isprocessing"]:
                self.postwarning(
                    'You must stop processing the current tab before saving data!'
                )

            else:

                try:
                    #pulling prof data
                    rawtemperature = self.alltabdata[curtabstr]["rawdata"][
                        "temperature"]
                    rawdepth = self.alltabdata[curtabstr]["rawdata"]["depth"]
                    frequency = self.alltabdata[curtabstr]["rawdata"][
                        "frequency"]
                    timefromstart = self.alltabdata[curtabstr]["rawdata"][
                        "time"]

                    #pulling profile metadata if necessary
                    try:
                        lat = self.alltabdata[curtabstr]["rawdata"]["lat"]
                        lon = self.alltabdata[curtabstr]["rawdata"]["lon"]
                        year = self.alltabdata[curtabstr]["rawdata"]["year"]
                        month = self.alltabdata[curtabstr]["rawdata"]["month"]
                        day = self.alltabdata[curtabstr]["rawdata"]["day"]
                        time = self.alltabdata[curtabstr]["rawdata"][
                            "droptime"]
                        hour = self.alltabdata[curtabstr]["rawdata"]["hour"]
                        minute = self.alltabdata[curtabstr]["rawdata"][
                            "minute"]
                    except:
                        # pulling data from inputs
                        latstr = self.alltabdata[curtabstr]["tabwidgets"][
                            "latedit"].text()
                        lonstr = self.alltabdata[curtabstr]["tabwidgets"][
                            "lonedit"].text()
                        profdatestr = self.alltabdata[curtabstr]["tabwidgets"][
                            "dateedit"].text()
                        timestr = self.alltabdata[curtabstr]["tabwidgets"][
                            "timeedit"].text()

                        #flags for capability of saving data
                        edfcapable = True
                        logcapable = True
                        wavcapable = True
                        sigcapable = True

                        #check validity of data
                        #try edf data
                        try:
                            lat, lon, year, month, day, time, hour, minute, _ = self.parsestringinputs(
                                latstr, lonstr, profdatestr, timestr, 'omit',
                                True, True, False)
                        except:
                            edfcapable = False
                            self.postwarning('Cannot save edf file!')
                        #try other data
                        try:
                            _, _, year, month, day, time, hour, minute, _ = self.parsestringinputs(
                                latstr, lonstr, profdatestr, timestr, 'omit',
                                False, True, False)
                        except:
                            logcapable = False,
                            wavcapable = False
                            sigcapable = False
                            self.postwarning("Failed to save raw data files!")
                            QApplication.restoreOverrideCursor()

                except Exception:
                    trace_error()
                    self.posterror("Failed to pull raw profile data")
                    QApplication.restoreOverrideCursor()
                    return False

                #date and time strings for LOG file
                initdatestr = str(year) + '/' + str(month).zfill(
                    2) + '/' + str(day).zfill(2)
                inittimestr = str(hour).zfill(2) + ':' + str(minute).zfill(
                    2) + ':00'

                filename = self.check_filename(
                    str(year) + str(month).zfill(2) + str(day).zfill(2) +
                    str(time).zfill(4))

                if self.settingsdict["savelog"] and logcapable:
                    try:
                        tfio.writelogfile(outdir + slash + filename + '.DTA',
                                          initdatestr, inittimestr,
                                          timefromstart, rawdepth, frequency,
                                          rawtemperature)
                    except Exception:
                        trace_error()
                        self.posterror("Failed to save LOG file")
                if self.settingsdict["saveedf"] and edfcapable:
                    try:
                        #creating comment for data source:
                        cdatasource = self.alltabdata[curtabstr]["tabwidgets"][
                            "datasource"].currentText()
                        comments = "//Data source: " + cdatasource
                        if cdatasource.lower() not in ["audio", "test"]:
                            comments += f", VHF Ch. {self.alltabdata[curtabstr]['tabwidgets']['vhfchannel'].value()} ({self.alltabdata[curtabstr]['tabwidgets']['vhffreq'].value()} MHz)"
                        tfio.writeedffile(
                            outdir + slash + filename + '.edf', rawtemperature,
                            rawdepth, year, month, day, hour, minute, 0, lat,
                            lon, self.settingsdict["tcoeff"],
                            self.settingsdict["zcoeff"], comments
                        )  #lat/lon only parsed if self.settingsdict["saveedf"] is True
                    except Exception:
                        trace_error()
                        self.posterror("Failed to save EDF file")

                if self.settingsdict["savewav"] and wavcapable:
                    try:
                        oldfile = self.tempdir + slash + 'tempwav_' + str(
                            self.alltabdata[curtabstr]["tabnum"]) + '.WAV'
                        newfile = outdir + slash + filename + '.WAV'

                        if path.exists(oldfile) and path.exists(
                                newfile
                        ) and oldfile != newfile:  #if file already exists
                            remove(newfile)

                        shcopy(oldfile, newfile)
                    except Exception:
                        trace_error()
                        self.posterror("Failed to save WAV file")

                if self.settingsdict["savesig"] and sigcapable:
                    try:
                        oldfile = self.tempdir + slash + 'sigdata_' + str(
                            self.alltabdata[curtabstr]["tabnum"]) + '.txt'
                        newfile = outdir + slash + filename + '.sigdata'

                        if path.exists(oldfile) and path.exists(
                                newfile) and oldfile != newfile:
                            remove(newfile)

                        shcopy(oldfile, newfile)
                    except Exception:
                        trace_error()

        elif self.alltabdata[curtabstr]["tabtype"] == "MissionPlotter":
            filename = str(
                self.tabWidget.tabText(
                    self.tabWidget.currentIndex()))  #filename is name of tab
            self.alltabdata[curtabstr]["MissionFig"].savefig(outdir + slash +
                                                             filename + '.png',
                                                             format='png')

        else:
            self.postwarning(
                'You must process a profile before attempting to save data!')

    except Exception:
        QApplication.restoreOverrideCursor(
        )  #restore cursor here as extra measure
        trace_error()  #if something else in the file save code broke
        self.posterror("Failed to save files")
        successval = False  #notes that process failed
    finally:
        QApplication.restoreOverrideCursor()  #restore cursor here
        self.alltabdata[curtabstr][
            "profileSaved"] = True  #note that profile has been saved

    if successval:
        self.alltabdata[curtabstr]["profileSaved"] = True
        self.remove_asterisk()

    return successval
示例#19
0
    def makenewtab(self):     
        try:

            newtabnum,curtabstr = self.addnewtab()
    
            #creates dictionary entry for current tab- you can add additional key/value combinations for the opened tab at any point after the dictionary has been initialized
            alltabdata[curtabstr] = {"tab":QWidget(),"tablayout":QGridLayout(),
                      "tabtype":"newtab","testvariable":False}

            self.setnewtabcolor(alltabdata[curtabstr]["tab"])
            
            alltabdata[curtabstr]["tablayout"].setSpacing(10)
    
            #creating new tab, assigning basic info
            self.tabWidget.addTab(alltabdata[curtabstr]["tab"],'New Tab') 
            self.tabWidget.setCurrentIndex(newtabnum)
            self.tabWidget.setTabText(newtabnum, "New Tab #" + str(self.totaltabs))
            alltabdata[curtabstr]["tabnum"] = self.totaltabs #assigning unique, unchanging number to current tab
            alltabdata[curtabstr]["tablayout"].setSpacing(10)
            
            
            #and add new buttons and other widgets
            alltabdata[curtabstr]["tabwidgets"] = {}

            #making widgets
            alltabdata[curtabstr]["tabwidgets"]["sourcetitle"] = QLabel(' Source:') #1
            alltabdata[curtabstr]["tabwidgets"]["refresh"] = QPushButton('Refresh')  # 2
            alltabdata[curtabstr]["tabwidgets"]["options"] = QComboBox() #3
            alltabdata[curtabstr]["tabwidgets"]["options"].addItem('Item A')
            alltabdata[curtabstr]["tabwidgets"]["options"].addItem('Item B')
            alltabdata[curtabstr]["currentoption"] = alltabdata[curtabstr]["tabwidgets"]["options"].currentText()
            
            alltabdata[curtabstr]["tabwidgets"]["sb1title"] = QLabel('Spinbox 1:') #4
            alltabdata[curtabstr]["tabwidgets"]["sb2title"] = QLabel('Spinbox 2:') #5
            
            alltabdata[curtabstr]["tabwidgets"]["sb1"] = QSpinBox() #6
            alltabdata[curtabstr]["tabwidgets"]["sb1"].setRange(1,99)
            alltabdata[curtabstr]["tabwidgets"]["sb1"].setSingleStep(1)
            alltabdata[curtabstr]["tabwidgets"]["sb1"].setValue(12)
            
            alltabdata[curtabstr]["tabwidgets"]["sb2"] = QDoubleSpinBox() #7
            alltabdata[curtabstr]["tabwidgets"]["sb2"].setRange(20, 30)
            alltabdata[curtabstr]["tabwidgets"]["sb2"].setSingleStep(0.25)
            alltabdata[curtabstr]["tabwidgets"]["sb2"].setDecimals(2)
            alltabdata[curtabstr]["tabwidgets"]["sb2"].setValue(23.5)
            
            #run function every time spinbox value is changed
            #alltabdata[curtabstr]["tabwidgets"]["sb2"].valueChanged.connect(self.callbackfunction) 
            
            alltabdata[curtabstr]["tabwidgets"]["b1"] = QPushButton('Button 1') #8
            alltabdata[curtabstr]["tabwidgets"]["b2"] = QPushButton('Button 2') #9
            alltabdata[curtabstr]["tabwidgets"]["b3"] = QPushButton('Button 3') #10
            
            alltabdata[curtabstr]["tabwidgets"]["t1t"] = QLabel('Entry 1:') #11
            alltabdata[curtabstr]["tabwidgets"]["t1"] = QLineEdit('E1 example') #12
            alltabdata[curtabstr]["tabwidgets"]["t2t"] = QLabel('Entry 2: ') #13
            alltabdata[curtabstr]["tabwidgets"]["t2"] = QLineEdit('E2 example') #14
            alltabdata[curtabstr]["tabwidgets"]["t3t"] = QLabel('Entry 3: ') #15
            alltabdata[curtabstr]["tabwidgets"]["t3"] = QLineEdit('E3 example') #16
            alltabdata[curtabstr]["tabwidgets"]["t4t"] = QLabel('Entry 4: ') #17
            alltabdata[curtabstr]["tabwidgets"]["t4"] = QLineEdit('E4 example') #18
            alltabdata[curtabstr]["tabwidgets"]["t5t"] = QLabel('Entry 5: ') #19
            alltabdata[curtabstr]["tabwidgets"]["t5"] = QLineEdit('E5 example') #20
            
            #formatting widgets
            alltabdata[curtabstr]["tabwidgets"]["sb1title"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["sb2title"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["t1t"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["t2t"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["t3t"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["t4t"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            alltabdata[curtabstr]["tabwidgets"]["t5t"].setAlignment(Qt.AlignRight | Qt.AlignVCenter)
            
            #should be 19 entries 
            widgetorder = ["sourcetitle","refresh","options","sb1title","sb2title","sb1","sb2",
            "b1","b2","b3","t1t","t1","t2t","t2","t3t","t3",
            "t4t","t4","t5t","t5"]
            wrows     = [1,1,2,3,4,3,4,5,5,6,1,1,2,2,3,3,4,4,5,5]
            wcols     = [2,3,2,2,2,3,3,2,3,3,4,5,4,5,4,5,4,5,4,5]
            wrext     = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
            wcolext   = [1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,1]
    
            #adding user inputs
            for i,r,c,re,ce in zip(widgetorder,wrows,wcols,wrext,wcolext):
                alltabdata[curtabstr]["tablayout"].addWidget(alltabdata[curtabstr]["tabwidgets"][i],r,c,re,ce)
                    
            #adjusting stretch factors for all rows/columns
            colstretch = [5,1,1,1,1,1,1]
            for col,cstr in zip(range(0,len(colstretch)),colstretch):
                alltabdata[curtabstr]["tablayout"].setColumnStretch(col,cstr)
            rowstretch = [1,1,1,1,1,1,1,1,10]
            for row,rstr in zip(range(0,len(rowstretch)),rowstretch):
                alltabdata[curtabstr]["tablayout"].setRowStretch(row,rstr)

            #making the current layout for the tab
            alltabdata[curtabstr]["tab"].setLayout(alltabdata[curtabstr]["tablayout"])

        except Exception: #if something breaks
            trace_error()
            self.posterror("Failed to build new tab")