######################################################################################################################## # Reads AVOS (*.AVMTD) data files in CSV format and saves a subset of 17 variables # (out of 40) in comma-delimited (*.csv) files. # # Converted to R from IDL program AVOS_parse2020.pro by T. Papakyriakou. GPS coordinates were converted # to decimal degrees incorrectly in the original IDL program. The IDL program also had problems handling # files containg missing data. These issues have been corrected in the R version. # # Missing data is denoted by "NA" in output files. # # R libraries used: svDialog # # W. Chan # February 21, 2020 # Modified by K. L. Firesen # March 15, 2022 # Version 1.3 # # Original AVOS data record format is 40 columns, comma-delimited. # Fields: # 1. AVMTD = message designator (D = version of message format) # 2. DATE = sample end date (YYMMDD) # 3. TIME = sample end time (hhmmss) # 4. unknown # 5. lat = GPS lat (DDmm.mmmmn (n='N' or 'S')) # 6. lon = GPS lon (DDDmm.mmmmn (n = 'E' or 'W')) # 7. ws = Apparent wind speed (knots) # 8. wd_rel = Apparent wind direction (Deg true) # 9. wd_true = True wind direction (Deg true) # 10. unknown # 11. unknown # 12. unknown # 13. P_uncor = Uncorrected Barometric Pressure (mbar) # 14. unknown # 15. Ta = Air Temperature (Deg C) # 16. RH = Relative Humidity (%) # 17. unknown # 18. unknown # 19. Tsrfc = Water Temperature (Deg C) # 20. BV = Battery Voltage (VDC) # 21. unknown # 22. unknown # 23. D...D = Ship's Call Sign (SHIP for default; CZ9742 = Namao) # 24. Ship's heading (AVOS Magnetic) (Degrees) # 25. sog_kts = Ship's Speed over ground (10 minute avg.) (Knots) # 26. unknown # 27. unknown # 28. unknown # 29. unknown # 30. unknown # 31. unknown # 32. unknown # 33. P_cor = Corrected Barometric Pressure (to mean sea level) (Mbar) # 34. unknown # 35. unknown # 36. unknown # 37. unknown # 38. unknown # 39. Ship's heading (Gyro compass) (Degrees) # 40. unknown ######################################################################################################################## #Whole script is enclosed in braces to allow 'stop' command to exit script properly. Otherwise, 'stop' will only #stop the current statement being executed and will continue executing the rest of the script. { #Install required packages if not installed already. needed_packages <- c("svDialogs") #List of required packages. not_installed <- needed_packages[!(needed_packages %in% installed.packages()[ , "Package"])] # Extract not installed packages. if(length(not_installed)) install.packages(not_installed) # Install not installed packages. #Load svDialogs library to use dialog boxes for user input of directory paths. library(svDialogs) #Ask user to select input directory. This was added because Mac dialog boxes can't show a title (title parameter in dlg_dir is ignored). dlgMessage("Select directory for raw AVOS files (.AVMTD).",type="ok") #Allow user to select input path for AVOS files using dialog box.Dlg_dir returns character(0) if no path is selected. input_path<-dlg_dir(default = getwd(),title = "Select directory for AVOS files:")$res #If null path is returned (character(0)), then stop script. if (!length(input_path)){ stop("No input file path selected. Stopping script...") } #Ask user to select output directory. dlgMessage("Select directory for converted AVOS files (.csv).",type="ok") #Allow user to select path for output files using dialog box. Default is the same as the input_path. Dlg_dir returns character(0) if no path is selected. output_path<-dlg_dir(default = input_path,title = "Select directory for output files:")$res #If null path is returned (character(0)), then stop script and print error message. if (!length(output_path)){ stop("No output file path selected. Stopping script...") } #Get list of AVOS files in input_path. file.names <- list.files(input_path, pattern =".AVMTD",ignore.case=TRUE) #If no files found (length of file.names is zero), then stop script and print error message. if (!length(file.names)) { stop(paste("No input files found in",input_path,"\nStopping script.")) } #Set current directory to input path. setwd(input_path) message("Processing all AVOS files in ",input_path,".") #Loop through all input files. for(i in 1:length(file.names)){ #Print current file name being processed. message(file.names[i]) #Read AVOS file (csv format). Set columns to be character to prevent type conversion and convert null ("") fields to NA. df<-read.csv(file.names[i],header=FALSE,colClasses = "character",na.strings = c("")) #Keep only rows that start with "AVMTD". df<-df[(df$V1=="AVMTD"),] #Parse date and time. year<-paste0("20",substr(df$V2,1,2)) #Year is two digits. Prepend "20" to make four-digit year. mon<-substr(df$V2,3,4) #Get month day<-substr(df$V2,5,6) #Get day hour<-substr(df$V3,1,2) #Get hour minute<-substr(df$V3,3,4) #Get minute #Parse latitude. Format is DDmm.mmmmn, where "n" = "N" or "S". latdeg<-as.numeric(substr(df$V5,1,2)) #First two characters are the integer part of the latitude. latmin<-as.numeric(substr(df$V5,3,9))/60.0 #Characters 3-9 are the minutes. Convert to decimal minutes by dividing by 60. NS_Hemisphere<-substr(df$V5,10,10) #"N" or "S" lat<-latdeg+latmin #Final latitude is the degrees added to the decimal minutes. #If latitude is in Southern Hemisphere, change the sign to negative. posn_where_S <- which(NS_Hemisphere == "S") lat[posn_where_S] <- -lat[posn_where_S] #Parse longitude. Format is DDDmm.mmmmn, where "n" = "W" or "E". londeg<-as.numeric(substr(df$V6,1,3)) #First three characters are the integer part of the longitude. lonmin<-as.numeric(substr(df$V6,4,10))/60.0 #Characters 4-10 are the minutes. Convert to decimal minutes by dividing by 60. lon<-londeg+lonmin #Final longitude is the degrees added to the decimal minutes. EW_Hemisphere<-substr(df$V6,11,11) #"E" or "W" #If longitude is in Western Hemisphere, change the sign to negative. posn_where_W <- which(EW_Hemisphere == "W") lon[posn_where_W] <- -lon[posn_where_W] #Get remaining variables. ws<-df$V7 #Wind speed wd_rel<-df$V8 #Relative wind direction wd_true<-df$V9 #True wind direction P_uncor<-df$V13 #Barometric pressure (uncorrected) Ta<-df$V15 #Air temperature RH<-df$V16 #Relative humidity Tsrfc<-df$V19 #Water surface temperature sog_kts<-df$V25 #SOG = Ship's speed over ground (knots) P_cor<-df$V33 #Barometric pressure (corrected) heading<-df$V39 #Ship's heading #Standardizing parameter names and creating output data frame. Date_and_time <- paste0(year,"-",mon,"-",day," ",hour,":",minute) latitude <- lat longitude <- lon wind_speed <- ws RelWindDirFrom <-wd_rel WindDirFrom <- wd_true air_pressure <- P_uncor air_temperature <- Ta relative_humidity <- RH Temp <- Tsrfc platform_speed_wrt_ground <- sog_kts air_pressure_corrected <- P_cor platform_orientation <- heading output_df <- data.frame(Date_and_time,latitude,longitude,wind_speed,RelWindDirFrom,WindDirFrom,air_pressure,air_temperature, relative_humidity,Temp,platform_speed_wrt_ground,air_pressure_corrected,platform_orientation) #Strip extension from base input filename and append .csv to create output filename. output_filename<-paste0(tools::file_path_sans_ext(file.names[i]),".csv") #Write data frame as a CSV file. write.csv(output_df,paste0(output_path,"/",output_filename),row.names = FALSE,quote=FALSE) } #Print message indicating end of processing. message("Files processed:",i,"\nOutput files saved to ",output_path,".") }