Gage Digitizer Data File Utilities
Dave Typinski, AJ4CO Observatory
September, 2013

SIG to SPS converter2 - converts all the .sig files in ALL directories for an observation into mutiple SPS files, one SPS file per subdirectory

Print["Processing started "<>DateString[]]

(********************************************************************************************)
(*                                                                                          *)
(*  User configuration section                                                              *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Set directory for input -- contains one or more .sig Gage signal files *)
(* ENSURE FREQS.CSV FILE IS LOADED  *)
filebase="V:\\Observation Records\\2016 03 27 Io-B";

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* Set measured cycle time in milliseconds between trigger events *)
cycletime=392;

(* Set number of FFT bins *)
fftbins=2048;

(* Set low freq and high freq limits of FFT display in MHz *)
(* This is the portion of the FFT that we want to see; i.e., the actual near-baseband output of the TWB *)
(* See below for the RF input frequency setting to be placed in the SPS file *)
displaylof=2.8;
displayhif=4.8;

(* SPS file detector sensitivity in ADC counts per dB *)
adcsens=50;

(* Set DC offset (in μW) to be added to FFT before calculatind dBm *)
dcoffset=100;

(* Set DC offset (in dBm) to be added to FFT before conversion to SPS data *)
postdcoffset=11;

(* Set DC offset (in ADC counts) to be added before export to SPS file *)
spsoffset=1000;

(* Set desired sweep rate in SPS data file in Hz *)
SPSsweeprate=4882.8125;

(********************************************************************************************)
(*                                                                                          *)
(*  End of user configuration section                                                       *)
(*                                                                                          *)
(********************************************************************************************)


(********************************************************************************************)
(*                                                                                          *)
(*  Function definitions section                                                            *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Define proper rounding function as MM only rounds 0.5 up when the result is an even number *)
SetAttributes[Round2,Listable];
Round2[a_]:=If[FractionalPart[a]≥1/2,Ceiling[a],Floor[a]];

(* Define read string function                                  *)
(* file = input file stream                                     *)
(* len = number of characters to retrieve                       *)
ReadStringFunc[file_,len_]:=
Module[{f=file,l=len},
s="";
Do[{
s=s<>BinaryRead[f, "Character8"];
},
{i,1,l}
];
s
];

(********************************************************************************************)
(*                                                                                          *)
(*  End of function definitions section                                                     *)
(*                                                                                          *)
(********************************************************************************************)


(********************************************************************************************)
(*                                                                                          *)
(*  Main program code                                                                       *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)


(* Workaround to fix DateString[] behavior that Wolfram changed in version 10.            *)
(* In version 9 and lower, DateDifference[] returned a pure numeric value.                 *)
(* In version 10 and up, DateDifference[] returns a 'Quantity' value that includes units.  *)
(* These units cause the code to fail when this workbook is run on a version 10 system.     *) 
(* See the MM help entry for DateDifference[] -> Possible Issues.                           *)
SetSystemOptions["DataOptions"->"ReturnQuantities"->False];

filebaseout=filebase;

fileext=".sig";
SetDirectory[filebase];
infiles=Select[FileNames[],DirectoryQ];
dirs=infiles//Length;
Print["Found ",ToString[dirs]," directories to process in ",filebase,"\\"];

(* Read table of R8500 frequencies and observation times *)
freqs=Import["freqs.csv"];
(* Put header row at bottom of table *)
freqs=RotateLeft[freqs,{1,0}];

Do[
{
filebase2=filebase<>"\\"<>infiles[[dirscounter]];
SetDirectory[filebase2];
infiles2=Select[FileNames[],DirectoryQ];
dirs2=infiles2//Length;

(* Set the R8500 tuned frequency used during digitization, MHz, and force to floating point variable *)
r8500=freqs[[dirscounter,1]]*1.0;

(* Set observation start time in year, month, day, hour, minute, and second UTC  *)
startyear=freqs[[dirscounter,2]];
startmonth=freqs[[dirscounter,3]];
startday=freqs[[dirscounter,4]];
starthour=freqs[[dirscounter,5]];
startmin=freqs[[dirscounter,6]];
startsec=freqs[[dirscounter,7]];

Print[dirscounter,"  Found ",ToString[dirs2]," directories to process in \\",infiles[[dirscounter]],"  --  Center Frequency ",97-r8500," MHz starting on ",startyear,"-",startmonth,"-",startday," at ",starthour,":",startmin,":",startsec," UTC."];

Do[
{
(* Find and count all Gage .sig files in the specified directory *)
filebase3=filebase2<>"\\"<>infiles2[[dirscounter2]];
SetDirectory[filebase3];
infiles3=FileNames["*"<>fileext];
filecount=infiles3//Length;
Print[dirscounter,"-",dirscounter2,"  Found ",ToString[filecount]," files to process in \\",infiles2[[dirscounter2]]];

(**************************************************)
(* Processing code goes here                      *)
(**************************************************)

(* Set the SPS file RF frequency range labels in MHz (derived from R8500 tuned frequency) *)
(* TWB 1st LO (in the upconverter) is 97 MHz, TWB output is 2 MHz wide *)
SPSlof=97-r8500-1.;
SPShif=97-r8500+1.;

(* calculate some FFT and SPS file parameters *)
(* find RBW *)
fftrbw=(samplerate*10^6)/fftbins;
(* fined low frequency element of FFT to export to SPS file *)
lofelement=Round2[fftbins*displaylof/samplerate]+1;
(* find high frequency element of FFT to export to SPS file *)
hifelement=Round2[fftbins*displayhif/samplerate]+1;
(* find total number of bins to export to SPS file (this is the SPS file channel count) *)
outputbincount=hifelement-lofelement+1;

(* Open Gage data file for read *)
(* Open SPS file for write *)
infile=OpenRead[infiles3[[1]],BinaryFormat->True];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Calculate observation duration in seconds *)
observationduration=cycletime*filecount/1000.;

(* Calculate time length of digitized data in milliseconds *)
dburstduration=chartsamples/samplerate/1000.;

(* Calculate number of sweeps in the Gage data *)
fftsweeps=Floor[chartsamples/fftbins];

(* Calculate padding in milliseconds needed before start of next digitized burst of data *)
SPSpaddingtime=cycletime-dburstduration;
SPSpaddingsweeps=Round2[fftsweeps*cycletime/dburstduration-fftsweeps];
SPSsweepsperburst=Round2[fftsweeps*cycletime/dburstduration];
SPSsweepsperobservation=SPSsweepsperburst*filecount;

(* Calculate start and stop time to be placed in SPS header *)
SPSchartstart=DateDifference[{1900,1,1},{startyear,startmonth,startday,starthour,startmin,startsec}]+2;

(* Time since Dec 30, 1899, 00:00:00.000 UTC *)
SPSchartstartf=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];

SPSchartstartfr=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," UTC"}];
SPSchartend=SPSchartstart+SPSsweepsperobservation/SPSsweeprate/86400.;
SPSchartendf=DateString[(SPSchartend-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
SPSfileduration=SPSsweepsperobservation/SPSsweeprate/86400.*24.;
SPStimeexpansionratio=SPSfileduration*3600./observationduration;
SPSminute=60./SPStimeexpansionratio;
*)

(* Generate SPS & PDF filenames and open SPS output file for write *)
starttime=(SPSchartstart-2)*86400;
SPSoutfilename=filebaseout<>"\\AJ4CO TWB ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Year"]<>" ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Month"]<>" ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Day"]<>" - ";
If[dirscounter<100,SPSoutfilename=SPSoutfilename<>"0"];
If[dirscounter<10,SPSoutfilename=SPSoutfilename<>"0"];
SPSoutfilename=SPSoutfilename<>ToString[dirscounter]<>" - ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Hour"]<>" ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Minute"]<>" ";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Second"]<>" ";
PDFoutfilename=SPSoutfilename<>" Analysis";
outfile=OpenWrite[SPSoutfilename<>".sps",BinaryFormat->True];

(* Write SPS file header *)
(* Set RSS data file version number 2.2.19 *)
SPSchartversion="0000202019";
WriteString[outfile,SPSchartversion];
BinaryWrite[outfile,SPSchartstart,"Real64"];
BinaryWrite[outfile,SPSchartend,"Real64"];
SPSchartlat=0;
BinaryWrite[outfile,SPSchartlat,"Real64"];
SPSchartlong=0;
BinaryWrite[outfile,SPSchartlong,"Real64"];
SPSchartmax=4095;
BinaryWrite[outfile,SPSchartmax,"Real64"];
SPSchartmin=0;
BinaryWrite[outfile,SPSchartmin,"Real64"];
SPSchartTZ=0;
BinaryWrite[outfile,SPSchartTZ,"Integer16"];
SPSchartsource="TWB       ";
WriteString[outfile,SPSchartsource];
SPSchartauthor="Dave Typinski       ";
WriteString[outfile,SPSchartauthor];
SPSchartlocalname="AJ4CO_TWB           ";
WriteString[outfile,SPSchartlocalname];
SPSchartlocation="High Springs, Florida                   ";
WriteString[outfile,SPSchartlocation];
SPSchartchannels=outputbincount;
BinaryWrite[outfile,SPSchartchannels,"Integer16"];
SPSchartnote="*[[*SWEEPS"<>ToString[SPSsweepsperobservation]<>"ÿLOWF"<>ToString[Round[SPSlof*10^6]]<>"ÿHIF"<>ToString[Round[SPShif*10^6]]<>"ÿSTEPS411ÿDUALSPECFILEFalseÿRCVR6ÿCOLORRES1ÿ*]]*";
SPSchartnotelength=StringLength[SPSchartnote];
BinaryWrite[outfile,SPSchartnotelength,"Integer32"];
WriteString[outfile,SPSchartnote];

(* Generate text report entries *)
txtoutput=Table["",{i,1,60}];
txtoutput[[1]]=Style["TWB Gage Signal File to RSS SPS File Converter",Larger,Darker[Darker[Blue]],Bold];
txtoutput[[2]]=" Analysis run date: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

txtoutput[[10]]=Style["Data Conversion Analysis Report",Bold];

txtoutput[[12]]="Observation start time: "<>SPSchartstartfr;
txtoutput[[13]]="Duration of observation: "<>ToString[observationduration]<>" real-time seconds";

txtoutput[[15]]="Data directory: "<>filebase3;
txtoutput[[16]]="Number of digitized input files: "<> ToString[filecount];
txtoutput[[17]]="First input filename: "<>infiles3[[1]];
txtoutput[[18]]="Last input filename: "<>infiles3[[filecount]];

txtoutput[[20]]="Digitized burst file size: "<>ToString[chartsamples]<>" samples per file";
txtoutput[[21]]="Digitized burst file sample rate: "<>ToString[samplerate]<>" MHz";
txtoutput[[22]]="Digitized burst file duration: "<>ToString[dburstduration]<>" ms";
txtoutput[[23]]="Digitized burst cycle time: "<>ToString[cycletime]<>" ms";
txtoutput[[24]]="Dead time between data bursts: "<>ToString[SPSpaddingtime]<>" ms";
txtoutput[[25]]="Digitization coverage: "<>ToString[dburstduration/cycletime*100.]<>" percent";

txtoutput[[27]]="FFT bins: "<>ToString[fftbins];
txtoutput[[28]]="FFT sweep time: "<>ToString[fftbins/samplerate*1.]<>" μs";
txtoutput[[29]]="FFT sweeps per digitized data burst: "<>ToString[fftsweeps];
txtoutput[[30]]="Dead FFT sweeps between each digitized data burst: "<>ToString[SPSpaddingsweeps];
txtoutput[[31]]="FFT sweeps per digitized data burst including dead time padding: "<>ToString[SPSsweepsperburst];
txtoutput[[32]]="Total FFT sweeps for "<>ToString[filecount]<>" input files, including padding: "<>ToString[SPSsweepsperobservation];

txtoutput[[34]]="FFT BW: "<>ToString[fftrbw*(fftbins/2)/10^6]<>" MHz";
txtoutput[[35]]="FFT RBW: "<>ToString[fftrbw/1000.]<>" kHz";
txtoutput[[36]]="FFT Windowing: "<>"None (uniform window)";
txtoutput[[37]]="FFT display low frequency: "<>ToString[displaylof]<>" MHz ( FFT bin # "<>ToString[lofelement]<>" )";
txtoutput[[38]]="FFT display high frequency: "<>ToString[displayhif]<>" MHz ( FFT bin # "<>ToString[hifelement]<>" )";
txtoutput[[39]]="Total FFT bins exported to SPS file: "<>ToString[outputbincount];

(* txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW"; *)
txtoutput[[42]]="DC offset applied to FFT before calculating dBm: "<>ToString[dcoffset]<>" μW";
txtoutput[[43]]="DC offset applied to FFT after calculating dBm: "<>ToString[postdcoffset]<>" dBm";
txtoutput[[44]]="SPS file detector sensitivity: "<>ToString[adcsens]<>" ADC counts per dB";
txtoutput[[45]]="DC offset applied to SPS data before export to SPS file: "<>ToString[spsoffset]<>" ADC counts";

txtoutput[[47]]="SPS output file name: "<>SPSoutfilename<>".sps";
txtoutput[[48]]="SPS data file sweep rate: "<>ToString[SPSsweeprate]<>" sweeps (FFT spectra) per second";
txtoutput[[49]]="SPS file start time: "<>SPSchartstartf;
txtoutput[[50]]="SPS file end time: "<>SPSchartendf;
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
txtoutput[[51]]="SPS file duration: "<>ToString[SPSfileduration]<>" hours";
txtoutput[[52]]="SPS file time expansion ratio: "<>ToString[SPStimeexpansionratio]<>" to 1";
txtoutput[[53]]="One minute of SPS file time represents: "<>ToString[SPSminute*1000.]<>" milliseconds of real time";
*)
(* close first .sig file to reset processing -- main loop must start with the header read operations *)
Close[infile];

(***********************************************************)
(*                                                         *)
(* MAIN LOOP to cycle through all the available .sig files *)
(*                                                         *)
(***********************************************************)

Do[
{
infile=OpenRead[infiles3[[k]],BinaryFormat->True];

Print[dirscounter,"-",dirscounter2,"-",k,"  Processing file "<>infiles3[[k]]];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Read all signal data from one file *)
signal=Table[0.,{i,1,chartsamples}];
Do[
signal[[i]]=BinaryRead[infile,"Integer16"]
,{i,1,chartsamples}
];

(* Perform FFT analysis of signal data for one file *)
Do[
{
fsignal=Abs[Fourier[signal[[fftbins*j-fftbins+1;;fftbins*j]]]]^2/50; (* power spectrum in uW into 50 ohms *)
fsignal = fsignal+dcoffset; (* add DC offset to spectrum prior to conversion to dBm *)
fsignal=fsignal/1000; (* convert uW to mW *)
fsignal=10*Log10[fsignal/1]; (* convert mW to dBm *)
fsignal = fsignal+postdcoffset;  (* bring floor above 0 dBm prior to conversion to SPS data *)
spssignal=Round2[fsignal[[lofelement;;hifelement]]*adcsens+spsoffset]; (* convert to SPS data and add DC offset *)

(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,spssignal[[i]],"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];

}
,{j,1,fftsweeps}
];

(* Add one set of inter-burst padding sweeps to SPS file *)
Do[
{
(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,0,"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];
}
,{j,1,SPSpaddingsweeps}
];

Close[infile];

}
,{k,1,filecount}
];

Close[outfile];

(* Output the analysis report *)
txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW (last FFT sweep of last data file)"; 
txtoutput[[3]]=" Analysis complete: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

panelout=Panel[Column[{
Column[txtoutput[[10;;11]]],
Column[txtoutput[[12;;15]],Alignment->":"],
Column[txtoutput[[16;;51]],Alignment->":"]
}],
Column[txtoutput[[1;;4]]]];

Export[PDFoutfilename<>".pdf",panelout];
Export[PDFoutfilename<>".png",Rasterize[panelout]];
Export[PDFoutfilename<>".wmf",Rasterize[panelout]];


},{dirscounter2,1,dirs2}
]

},{dirscounter,1,dirs}
]


Print["Processing ended "<>DateString[]]

SIG to SPS converter - converts all the .sig files in one directory to a single long SPS file

(********************************************************************************************)
(*                                                                                          *)
(*  User configuration section                                                              *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)



Print["Processing started "<>DateString[]]

(* Set directory for input -- contains one or more .sig Gage signal files *)
filebase="R:\\Observation Records\\AJ4CO Observatory\\TWB\\Gage CS1220\\20140311 Io-B\\2014-03-11_19_CH01\\Folder.00001";

(* Set observation start time in year, month, day, hour, minute, and second UTC  *)
startyear=2014;
startmonth=03;
startday=11;
starthour=04;
startmin=23;
startsec=09;

(* Set the R8500 tuned frequency used during digitization, MHz *)
r8500=75.;

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* Set measured cycle time in milliseconds between trigger events *)
cycletime=392;

(* Set number of FFT bins *)
fftbins=2048;

(* Set low freq and high freq limits of FFT display in MHz *)
(* This is the portion of the FFT that we want to see; i.e., the actual near-baseband output of the TWB *)
(* See below for the RF input frequency setting to be placed in the SPS file *)
displaylof=2.8;
displayhif=4.8;

(* SPS file detector sensitivity in ADC counts per dB *)
adcsens=50;

(* Set DC offset (in μW) to be added to FFT before calculatind dBm *)
dcoffset=100;

(* Set DC offset (in dBm) to be added to FFT before conversion to SPS data *)
postdcoffset=11;

(* Set DC offset (in ADC counts) to be added before export to SPS file *)
spsoffset=1000;

(* Set desired sweep rate in SPS data file in Hz *)
SPSsweeprate=4882.8125;

(********************************************************************************************)
(*                                                                                          *)
(*  End of user configuration section                                                       *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Function definitions section                                                            *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Define proper rounding function as MM only rounds 0.5 up when the result is an even number *)
SetAttributes[Round2,Listable];
Round2[a_]:=If[FractionalPart[a]≥1/2,Ceiling[a],Floor[a]];

(* Define read string function                                  *)
(* file = input file stream                                     *)
(* len = number of characters to retrieve                       *)
ReadStringFunc[file_,len_]:=
Module[{f=file,l=len},
s="";
Do[{
s=s<>BinaryRead[f, "Character8"];
},
{i,1,l}
];
s
];

(********************************************************************************************)
(*                                                                                          *)
(*  End of function definitions section                                                     *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Main program code                                                                       *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Set the SPS file RF frequency range labels in MHz (derived from R8500 tuned frequency) *)
(* TWB 1st LO (in the upconverter) is 97 MHz, TWB output is 2 MHz wide *)
SPSlof=97-r8500-1.;
SPShif=97-r8500+1.;

(* calculate some FFT and SPS file parameters *)
(* find RBW *)
fftrbw=(samplerate*10^6)/fftbins;
(* fined low frequency element of FFT to export to SPS file *)
lofelement=Round2[fftbins*displaylof/samplerate]+1;
(* find high frequency element of FFT to export to SPS file *)
hifelement=Round2[fftbins*displayhif/samplerate]+1;
(* find total number of bins to export to SPS file (this is the SPS file channel count) *)
outputbincount=hifelement-lofelement+1;

(* Find and count all Gage .sig files in the specified directory *)
fileext=".sig";
SetDirectory[filebase];
infiles=FileNames["*"<>fileext];
filecount=infiles//Length;
Print["Found ",ToString[filecount]," files to process."]

(* Open Gage data file for read *)
(* Open SPS file for write *)
infile=OpenRead[infiles[[1]],BinaryFormat->True];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Calculate observation duration in seconds *)
observationduration=cycletime*filecount/1000.;

(* Calculate time length of digitized data in milliseconds *)
dburstduration=chartsamples/samplerate/1000.;

(* Calculate number of sweeps in the Gage data *)
fftsweeps=Floor[chartsamples/fftbins];

(* Calculate padding in milliseconds needed before start of next digitized burst of data *)
SPSpaddingtime=cycletime-dburstduration;
SPSpaddingsweeps=Round2[fftsweeps*cycletime/dburstduration-fftsweeps];
SPSsweepsperburst=Round2[fftsweeps*cycletime/dburstduration];
SPSsweepsperobservation=SPSsweepsperburst*filecount;

(* Calculate start and stop time to be placed in SPS header *)
SPSchartstart=DateDifference[{1900,1,1},{startyear,startmonth,startday,starthour,startmin,startsec}]+2; (* Time since Dec 30, 1899, 00:00:00.000 UTC *)
SPSchartstartf=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
SPSchartstartfr=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," UTC"}];
SPSchartend=SPSchartstart+SPSsweepsperobservation/SPSsweeprate/86400.;
SPSchartendf=DateString[(SPSchartend-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
SPSfileduration=SPSsweepsperobservation/SPSsweeprate/86400.*24.;
SPStimeexpansionratio=SPSfileduration*3600./observationduration;
SPSminute=60./SPStimeexpansionratio;
*)

(* Generate SPS & PDF filenames and open SPS output file for write *)
starttime=(SPSchartstart-2)*86400;
SPSoutfilename="AJ4CO-TWB-";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Year"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Month"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Day"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Hour"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Minute"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Second"];
PDFoutfilename=SPSoutfilename<>" Analysis";
outfile=OpenWrite[SPSoutfilename<>".sps",BinaryFormat->True];

(* Write SPS file header *)
(* Set RSS data file version number 2.2.19 *)
SPSchartversion="0000202019";
WriteString[outfile,SPSchartversion];
BinaryWrite[outfile,SPSchartstart,"Real64"];
BinaryWrite[outfile,SPSchartend,"Real64"];
SPSchartlat=0;
BinaryWrite[outfile,SPSchartlat,"Real64"];
SPSchartlong=0;
BinaryWrite[outfile,SPSchartlong,"Real64"];
SPSchartmax=4095;
BinaryWrite[outfile,SPSchartmax,"Real64"];
SPSchartmin=0;
BinaryWrite[outfile,SPSchartmin,"Real64"];
SPSchartTZ=0;
BinaryWrite[outfile,SPSchartTZ,"Integer16"];
SPSchartsource="TWB       ";
WriteString[outfile,SPSchartsource];
SPSchartauthor="Dave Typinski       ";
WriteString[outfile,SPSchartauthor];
SPSchartlocalname="AJ4CO_TWB           ";
WriteString[outfile,SPSchartlocalname];
SPSchartlocation="High Springs, Florida                   ";
WriteString[outfile,SPSchartlocation];
SPSchartchannels=outputbincount;
BinaryWrite[outfile,SPSchartchannels,"Integer16"];
SPSchartnote="*[[*SWEEPS"<>ToString[SPSsweepsperobservation]<>"ÿLOWF"<>ToString[Round[SPSlof*10^6]]<>"ÿHIF"<>ToString[Round[SPShif*10^6]]<>"ÿSTEPS411ÿDUALSPECFILEFalseÿRCVRÿCOLORRES1ÿ*]]*";
SPSchartnotelength=StringLength[SPSchartnote];
BinaryWrite[outfile,SPSchartnotelength,"Integer32"];
WriteString[outfile,SPSchartnote];

(* Generate text report entries *)
txtoutput=Table["",{i,1,60}];
txtoutput[[1]]=Style["TWB Gage Signal File to RSS SPS File Converter",Larger,Darker[Darker[Blue]],Bold];
txtoutput[[2]]=" Analysis run date: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

txtoutput[[10]]=Style["Data Conversion Analysis Report",Bold];

txtoutput[[12]]="Observation start time: "<>SPSchartstartfr;
txtoutput[[13]]="Duration of observation: "<>ToString[observationduration]<>" real-time seconds";

txtoutput[[15]]="Data directory: "<>filebase;
txtoutput[[16]]="Number of digitized input files: "<> ToString[filecount];
txtoutput[[17]]="First input filename: "<>infiles[[1]];
txtoutput[[18]]="Last input filename: "<>infiles[[filecount]];

txtoutput[[20]]="Digitized burst file size: "<>ToString[chartsamples]<>" samples per file";
txtoutput[[21]]="Digitized burst file sample rate: "<>ToString[samplerate]<>" MHz";
txtoutput[[22]]="Digitized burst file duration: "<>ToString[dburstduration]<>" ms";
txtoutput[[23]]="Digitized burst cycle time: "<>ToString[cycletime]<>" ms";
txtoutput[[24]]="Dead time between data bursts: "<>ToString[SPSpaddingtime]<>" ms";
txtoutput[[25]]="Digitization coverage: "<>ToString[dburstduration/cycletime*100.]<>" percent";

txtoutput[[27]]="FFT bins: "<>ToString[fftbins];
txtoutput[[28]]="FFT sweep time: "<>ToString[fftbins/samplerate*1.]<>" μs";
txtoutput[[29]]="FFT sweeps per digitized data burst: "<>ToString[fftsweeps];
txtoutput[[30]]="Dead FFT sweeps between each digitized data burst: "<>ToString[SPSpaddingsweeps];
txtoutput[[31]]="FFT sweeps per digitized data burst including dead time padding: "<>ToString[SPSsweepsperburst];
txtoutput[[32]]="Total FFT sweeps for "<>ToString[filecount]<>" input files, including padding: "<>ToString[SPSsweepsperobservation];

txtoutput[[34]]="FFT BW: "<>ToString[fftrbw*(fftbins/2)/10^6]<>" MHz";
txtoutput[[35]]="FFT RBW: "<>ToString[fftrbw/1000.]<>" kHz";
txtoutput[[36]]="FFT Windowing: "<>"None (uniform window)";
txtoutput[[37]]="FFT display low frequency: "<>ToString[displaylof]<>" MHz ( FFT bin # "<>ToString[lofelement]<>" )";
txtoutput[[38]]="FFT display high frequency: "<>ToString[displayhif]<>" MHz ( FFT bin # "<>ToString[hifelement]<>" )";
txtoutput[[39]]="Total FFT bins exported to SPS file: "<>ToString[outputbincount];

(* txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW"; *)
txtoutput[[42]]="DC offset applied to FFT before calculating dBm: "<>ToString[dcoffset]<>" μW";
txtoutput[[43]]="DC offset applied to FFT after calculating dBm: "<>ToString[postdcoffset]<>" dBm";
txtoutput[[44]]="SPS file detector sensitivity: "<>ToString[adcsens]<>" ADC counts per dB";
txtoutput[[45]]="DC offset applied to SPS data before export to SPS file: "<>ToString[spsoffset]<>" ADC counts";

txtoutput[[47]]="SPS output file name: "<>SPSoutfilename<>".sps";
txtoutput[[48]]="SPS data file sweep rate: "<>ToString[SPSsweeprate]<>" sweeps (FFT spectra) per second";
txtoutput[[49]]="SPS file start time: "<>SPSchartstartf;
txtoutput[[50]]="SPS file end time: "<>SPSchartendf;
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
txtoutput[[51]]="SPS file duration: "<>ToString[SPSfileduration]<>" hours";
txtoutput[[52]]="SPS file time expansion ratio: "<>ToString[SPStimeexpansionratio]<>" to 1";
txtoutput[[53]]="One minute of SPS file time represents: "<>ToString[SPSminute*1000.]<>" milliseconds of real time";
*)
(* close first .sig file to reset processing -- main loop must start with the header read operations *)
Close[infile];

(***********************************************************)
(*                                                         *)
(* MAIN LOOP to cycle through all the available .sig files *)
(*                                                         *)
(***********************************************************)

Do[
{
infile=OpenRead[infiles[[k]],BinaryFormat->True];

Print["Processing file "<>infiles[[k]]];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Read all signal data from one file *)
signal=Table[0.,{i,1,chartsamples}];
Do[
signal[[i]]=BinaryRead[infile,"Integer16"]
,{i,1,chartsamples}
];

(* Perform FFT analysis of signal data for one file *)
Do[
{
fsignal=Abs[Fourier[signal[[fftbins*j-fftbins+1;;fftbins*j]]]]^2/50; (* power spectrum in uW into 50 ohms *)
fsignal = fsignal+dcoffset; (* add DC offset to spectrum prior to conversion to dBm *)
fsignal=fsignal/1000; (* convert uW to mW *)
fsignal=10*Log10[fsignal/1]; (* convert mW to dBm *)
fsignal = fsignal+postdcoffset;  (* bring floor above 0 dBm prior to conversion to SPS data *)
spssignal=Round2[fsignal[[lofelement;;hifelement]]*adcsens+spsoffset]; (* convert to SPS data and add DC offset *)

(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,spssignal[[i]],"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];

}
,{j,1,fftsweeps}
];

(* Add one set of inter-burst padding sweeps to SPS file *)
Do[
{
(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,0,"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];
}
,{j,1,SPSpaddingsweeps}
];

Close[infile];

}
,{k,1,filecount}
];

Close[outfile];

(* Output the analysis report *)
txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW (last FFT sweep of last data file)"; 
txtoutput[[3]]=" Analysis complete: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

panelout=Panel[Column[{
Column[txtoutput[[10;;11]]],
Column[txtoutput[[12;;15]],Alignment->":"],
Column[txtoutput[[16;;51]],Alignment->":"]
}],
Column[txtoutput[[1;;4]]]];

Export[PDFoutfilename<>".pdf",panelout];
Export[PDFoutfilename<>".png",Rasterize[panelout]];
Export[PDFoutfilename<>".wmf",Rasterize[panelout]];

Print["Processing ended "<>DateString[]]

SIG to WAV converter - converts all the .sig files in multiple directores to multiple WAV files

(********************************************************************************************)
(*                                                                                          *)
(*  User configuration section                                                              *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

Print["Processing started "<>DateString[]]

(* set the number of data file directories for the observation run *)
dirstart=06;
dirend=06;
Do[
{

(* Set directory for input -- contains one or more .sig Gage signal files *)
filebase="R:\\Observation Records\\AJ4CO Observatory\\TWB\\Gage CS1220\\20140311 Io-B\\2014-03-11_"<>IntegerString[z,10,2]<>"_CH01\\Folder.00001";

Print[];
Print["Processing data directory number ",IntegerString[z,10,2],"."];

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* set LO frequency in MHz *)
LOfreq = 4.82;

(* Set desired WAV file sample rate in Hz *)
WAVsamplerate=44100;

(********************************************************************************************)
(*                                                                                          *)
(*  End of user configuration section                                                       *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Function definitions section                                                            *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Define proper rounding function as MM only rounds 0.5 up when the result is an even number *)
SetAttributes[Round2,Listable];
Round2[a_]:=If[FractionalPart[a]≥1/2,Ceiling[a],Floor[a]];

(* Define read string function                                  *)
(* file = input file stream                                     *)
(* len = number of characters to retrieve                       *)
ReadStringFunc[file_,len_]:=
Module[{f=file,l=len},
s="";
Do[{
s=s<>BinaryRead[f, "Character8"];
},
{i,1,l}
];
s
];

(********************************************************************************************)
(*                                                                                          *)
(*  End of function definitions section                                                     *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Main program code                                                                       *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Find and count all Gage .sig files in the specified directory *)
fileext=".sig";
SetDirectory[filebase];
infiles=FileNames["*"<>fileext];
filecount=infiles//Length;
Print["Found ",ToString[filecount]," files to process."]

(***********************************************************)
(*                                                         *)
(* MAIN LOOP to cycle through all the available .sig files *)
(*                                                         *)
(***********************************************************)

Do[
{
infile=OpenRead[infiles[[k]],BinaryFormat->True];

Print["Processing file "<>infiles[[k]]];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Read all signal data from one file *)
signal=Table[0.,{i,1,chartsamples}];
Do[
signal[[i]]=BinaryRead[infile,"Integer16"]
,{i,1,chartsamples}
];

Close[infile];

(* Convert 12-bit Gage data to 16 bits *)
signal = signal *16;

(* make LO signal 10 dB stronger than max data peak *)
LOamplitude=32000.;

(* run time series data thru a hi-pass filter *)
signal=HighpassFilter[signal,(2.8/5.0) π,40];

(* downconvert data to baseband using high-side injection to de-mirror the TWB's IF passband *)
Do[
signal[[i]]=signal[[i]]*LOamplitude*Sin[2 π (i) (LOfreq/samplerate)]
,{i,1,chartsamples}
];

(* run time series data thru a lo-pass filter *)
signal=LowpassFilter[signal,(2.0/5.0) π,10];

(* normalize signal to 16 bits so that max peak is roughly full scale *)
m=Max[signal];
signal = signal*32000/m;

(* Convert time series data to WAV file *)
(*WAVout=Sound[SampledSoundList[signal,WAVsamplerate]];*)
WAVout=ListPlay[signal,SampleDepth->16,SampleRate->WAVsamplerate,PlayRange->All];
outWAVname=StringReplace[infiles[[k]],".sig"->" baseband via 4.82 MHz LO, 44.1 kHz audio sample rate.wav"];

(* export WAV file *)
Export[outWAVname,WAVout];


}
,{k,1,filecount (* 1, filecount *)}
];

Print["Processing ended "<>DateString[]]

}
,{z,dirstart,dirend}
]

SIG to WAV converter - test runs

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* set LO frequency in MHz *)
LOfreq = 4.9;

(* make LO signal 10 dB stronger than max data peak*)
LOamplitude=1.;
(* LOamplitude=Max[signal]*10.; *)

LOfunc[i_]:=LOamplitude*Sin[2 π (i) (LOfreq/samplerate)];

Plot[LOfunc[x],{x,1,10}]

(* Read all signal data from one file *)
signal=Table[0.,{i,1,100}];
Do[
signal[[i]]=LOfunc[i]
,{i,1,100}
];
ListPlot[signal]

signal1=Table[RandomInteger[{-32765,32765}],{i,1,2000000}];
ListLinePlot[Abs[Fourier[signal1[[1;;2048]]]]^2]

(* run time series data thru a hi-pass filter *)
signal2=HighpassFilter[signal1,(2.8/5.0) π,40];
ListLinePlot[Abs[Fourier[signal2[[1;;2048]]]]^2]

SIG to SPS converter with Windowing Function - converts all the .sig files in one directory to a single long SPS file

(********************************************************************************************)
(*                                                                                          *)
(*  User configuration section                                                              *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

Print["Processing started "<>DateString[]]

(* Set directory for input -- contains one or more .sig Gage signal files *)
filebase="R:\\Observation Records\\AJ4CO Observatory\\TWB\\Gage\\20131130 Io-B\\2013-11-30_009_CH01\\Folder.00001\\test";

(* Set observation start time in year, month, day, hour, minute, and second UTC  *)
startyear=2013;
startmonth=11;
startday=30;
starthour=06;
startmin=28;
startsec=00;

(* Set the R8500 tuned frequency used during digitization, MHz *)
r8500=78.;

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* Set measured cycle time in milliseconds between trigger events *)
cycletime=392;

(* Set number of FFT bins *)
fftbins=2048;

(* Set Windowing function multiplier *)

(* Uniform window *)
(* windowfunction=1; *)

(* Hann window *)
(* windowfunction=Table[0.5*(1-Cos[(2*π*i)/(fftbins-1)]),{i,0,fftbins-1}]; *)

(* Blackman-Harris window *)
a0=0.3635819;
a1=0.4891775;
a2=0.1365995;
a3=0.0106411;
windowfunction=Table[a0-a1*Cos[2 π i/(fftbins-1)]+a2*Cos[4 π i/(fftbins-1)]-a3*Cos[6 π i/(fftbins-1)],{i,0,fftbins-1}];

(* Set low freq and high freq limits of FFT display in MHz *)
(* This is the portion of the FFT that we want to see; i.e., the actual near-baseband output of the TWB *)
(* See below for the RF input frequency setting to be placed in the SPS file *)
displaylof=2.8;
displayhif=4.8;

(* SPS file detector sensitivity in ADC counts per dB *)
adcsens=50;

(* Set DC offset (in μW) to be added to FFT before calculatind dBm *)
dcoffset=100;

(* Set DC offset (in dBm) to be added to FFT before conversion to SPS data *)
postdcoffset=11;

(* Set DC offset (in ADC counts) to be added before export to SPS file *)
spsoffset=1000;

(* Set desired sweep rate in SPS data file in Hz *)
SPSsweeprate=4882.8125;

(********************************************************************************************)
(*                                                                                          *)
(*  End of user configuration section                                                       *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Function definitions section                                                            *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Define proper rounding function as MM only rounds 0.5 up when the result is an even number *)
SetAttributes[Round2,Listable];
Round2[a_]:=If[FractionalPart[a]≥1/2,Ceiling[a],Floor[a]];

(* Define read string function                                  *)
(* file = input file stream                                     *)
(* len = number of characters to retrieve                       *)
ReadStringFunc[file_,len_]:=
Module[{f=file,l=len},
s="";
Do[{
s=s<>BinaryRead[f, "Character8"];
},
{i,1,l}
];
s
];

(********************************************************************************************)
(*                                                                                          *)
(*  End of function definitions section                                                     *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Main program code                                                                       *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Set the SPS file RF frequency range labels in MHz (derived from R8500 tuned frequency) *)
(* TWB 1st LO (in the upconverter) is 97 MHz, TWB output is 2 MHz wide *)
SPSlof=97-r8500-1.;
SPShif=97-r8500+1.;

(* calculate some FFT and SPS file parameters *)
(* find RBW *)
fftrbw=(samplerate*10^6)/fftbins;
(* fined low frequency element of FFT to export to SPS file *)
lofelement=Round2[fftbins*displaylof/samplerate]+1;
(* find high frequency element of FFT to export to SPS file *)
hifelement=Round2[fftbins*displayhif/samplerate]+1;
(* find total number of bins to export to SPS file (this is the SPS file channel count) *)
outputbincount=hifelement-lofelement+1;

(* Find and count all Gage .sig files in the specified directory *)
fileext=".sig";
SetDirectory[filebase];
infiles=FileNames["*"<>fileext];
filecount=infiles//Length;
Print["Found ",ToString[filecount]," files to process."]

(* Open Gage data file for read *)
(* Open SPS file for write *)
infile=OpenRead[infiles[[1]],BinaryFormat->True];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Calculate observation duration in seconds *)
observationduration=cycletime*filecount/1000.;

(* Calculate time length of digitized data in milliseconds *)
dburstduration=chartsamples/samplerate/1000.;

(* Calculate number of sweeps in the Gage data *)
fftsweeps=Floor[chartsamples/fftbins];

(* Calculate padding in milliseconds needed before start of next digitized burst of data *)
SPSpaddingtime=cycletime-dburstduration;
SPSpaddingsweeps=Round2[fftsweeps*cycletime/dburstduration-fftsweeps];
SPSsweepsperburst=Round2[fftsweeps*cycletime/dburstduration];
SPSsweepsperobservation=SPSsweepsperburst*filecount;

(* Calculate start and stop time to be placed in SPS header *)
SPSchartstart=DateDifference[{1900,1,1},{startyear,startmonth,startday,starthour,startmin,startsec}]+2; (* Time since Dec 30, 1899, 00:00:00.000 UTC *)
SPSchartstartf=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
SPSchartstartfr=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," UTC"}];
SPSchartend=SPSchartstart+SPSsweepsperobservation/SPSsweeprate/86400.;
SPSchartendf=DateString[(SPSchartend-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
SPSfileduration=SPSsweepsperobservation/SPSsweeprate/86400.*24.;
SPStimeexpansionratio=SPSfileduration*3600./observationduration;
SPSminute=60./SPStimeexpansionratio;
*)

(* Generate SPS & PDF filenames and open SPS output file for write *)
starttime=(SPSchartstart-2)*86400;
SPSoutfilename="AJ4CO-TWB-";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Year"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Month"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Day"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Hour"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Minute"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Second"];
PDFoutfilename=SPSoutfilename<>" Analysis";
outfile=OpenWrite[SPSoutfilename<>".sps",BinaryFormat->True];

(* Write SPS file header *)
(* Set RSS data file version number 2.2.19 *)
SPSchartversion="0000202019";
WriteString[outfile,SPSchartversion];
BinaryWrite[outfile,SPSchartstart,"Real64"];
BinaryWrite[outfile,SPSchartend,"Real64"];
SPSchartlat=0;
BinaryWrite[outfile,SPSchartlat,"Real64"];
SPSchartlong=0;
BinaryWrite[outfile,SPSchartlong,"Real64"];
SPSchartmax=4095;
BinaryWrite[outfile,SPSchartmax,"Real64"];
SPSchartmin=0;
BinaryWrite[outfile,SPSchartmin,"Real64"];
SPSchartTZ=0;
BinaryWrite[outfile,SPSchartTZ,"Integer16"];
SPSchartsource="TWB       ";
WriteString[outfile,SPSchartsource];
SPSchartauthor="Dave Typinski       ";
WriteString[outfile,SPSchartauthor];
SPSchartlocalname="AJ4CO_TWB           ";
WriteString[outfile,SPSchartlocalname];
SPSchartlocation="High Springs, Florida                   ";
WriteString[outfile,SPSchartlocation];
SPSchartchannels=outputbincount;
BinaryWrite[outfile,SPSchartchannels,"Integer16"];
SPSchartnote="*[[*SWEEPS"<>ToString[SPSsweepsperobservation]<>"ÿLOWF"<>ToString[Round[SPSlof*10^6]]<>"ÿHIF"<>ToString[Round[SPShif*10^6]]<>"ÿSTEPS411ÿDUALSPECFILEFalseÿRCVRÿCOLORRES1ÿ*]]*";
SPSchartnotelength=StringLength[SPSchartnote];
BinaryWrite[outfile,SPSchartnotelength,"Integer32"];
WriteString[outfile,SPSchartnote];

(* Generate text report entries *)
txtoutput=Table["",{i,1,60}];
txtoutput[[1]]=Style["TWB Gage Signal File to RSS SPS File Converter",Larger,Darker[Darker[Blue]],Bold];
txtoutput[[2]]=" Analysis run date: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

txtoutput[[10]]=Style["Data Conversion Analysis Report",Bold];

txtoutput[[12]]="Observation start time: "<>SPSchartstartfr;
txtoutput[[13]]="Duration of observation: "<>ToString[observationduration]<>" real-time seconds";

txtoutput[[15]]="Data directory: "<>filebase;
txtoutput[[16]]="Number of digitized input files: "<> ToString[filecount];
txtoutput[[17]]="First input filename: "<>infiles[[1]];
txtoutput[[18]]="Last input filename: "<>infiles[[filecount]];

txtoutput[[20]]="Digitized burst file size: "<>ToString[chartsamples]<>" samples per file";
txtoutput[[21]]="Digitized burst file sample rate: "<>ToString[samplerate]<>" MHz";
txtoutput[[22]]="Digitized burst file duration: "<>ToString[dburstduration]<>" ms";
txtoutput[[23]]="Digitized burst cycle time: "<>ToString[cycletime]<>" ms";
txtoutput[[24]]="Dead time between data bursts: "<>ToString[SPSpaddingtime]<>" ms";
txtoutput[[25]]="Digitization coverage: "<>ToString[dburstduration/cycletime*100.]<>" percent";

txtoutput[[27]]="FFT bins: "<>ToString[fftbins];
txtoutput[[28]]="FFT sweep time: "<>ToString[fftbins/samplerate*1.]<>" μs";
txtoutput[[29]]="FFT sweeps per digitized data burst: "<>ToString[fftsweeps];
txtoutput[[30]]="Dead FFT sweeps between each digitized data burst: "<>ToString[SPSpaddingsweeps];
txtoutput[[31]]="FFT sweeps per digitized data burst including dead time padding: "<>ToString[SPSsweepsperburst];
txtoutput[[32]]="Total FFT sweeps for "<>ToString[filecount]<>" input files, including padding: "<>ToString[SPSsweepsperobservation];

txtoutput[[34]]="FFT BW: "<>ToString[fftrbw*(fftbins/2)/10^6]<>" MHz";
txtoutput[[35]]="FFT RBW: "<>ToString[fftrbw/1000.]<>" kHz";
txtoutput[[36]]="FFT Windowing: "<>"None (uniform window)";
txtoutput[[37]]="FFT display low frequency: "<>ToString[displaylof]<>" MHz ( FFT bin # "<>ToString[lofelement]<>" )";
txtoutput[[38]]="FFT display high frequency: "<>ToString[displayhif]<>" MHz ( FFT bin # "<>ToString[hifelement]<>" )";
txtoutput[[39]]="Total FFT bins exported to SPS file: "<>ToString[outputbincount];

(* txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW"; *)
txtoutput[[42]]="DC offset applied to FFT before calculating dBm: "<>ToString[dcoffset]<>" μW";
txtoutput[[43]]="DC offset applied to FFT after calculating dBm: "<>ToString[postdcoffset]<>" dBm";
txtoutput[[44]]="SPS file detector sensitivity: "<>ToString[adcsens]<>" ADC counts per dB";
txtoutput[[45]]="DC offset applied to SPS data before export to SPS file: "<>ToString[spsoffset]<>" ADC counts";

txtoutput[[47]]="SPS output file name: "<>SPSoutfilename<>".sps";
txtoutput[[48]]="SPS data file sweep rate: "<>ToString[SPSsweeprate]<>" sweeps (FFT spectra) per second";
txtoutput[[49]]="SPS file start time: "<>SPSchartstartf;
txtoutput[[50]]="SPS file end time: "<>SPSchartendf;
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
txtoutput[[51]]="SPS file duration: "<>ToString[SPSfileduration]<>" hours";
txtoutput[[52]]="SPS file time expansion ratio: "<>ToString[SPStimeexpansionratio]<>" to 1";
txtoutput[[53]]="One minute of SPS file time represents: "<>ToString[SPSminute*1000.]<>" milliseconds of real time";
*)
(* close first .sig file to reset processing -- main loop must start with the header read operations *)
Close[infile];

(***********************************************************)
(*                                                         *)
(* MAIN LOOP to cycle through all the available .sig files *)
(*                                                         *)
(***********************************************************)

Do[
{
infile=OpenRead[infiles[[k]],BinaryFormat->True];

Print["Processing file "<>infiles[[k]]];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Read all signal data from one file *)
signal=Table[0.,{i,1,chartsamples}];
Do[
signal[[i]]=BinaryRead[infile,"Integer16"]
,{i,1,chartsamples}
];

(* Perform FFT analysis of signal data for one file *)
Do[
{
(* Window the time series data *)
signalwindowed=signal[[fftbins*j-fftbins+1;;fftbins*j]]*windowfunction;
fsignal=Abs[Fourier[signalwindowed]]^2/50; (* power spectrum in uW into 50 ohms *)
fsignal = fsignal+dcoffset; (* add DC offset to spectrum prior to conversion to dBm *)
fsignal=fsignal/1000; (* convert uW to mW *)
fsignal=10*Log10[fsignal/1]; (* convert mW to dBm *)
fsignal = fsignal+postdcoffset;  (* bring floor above 0 dBm prior to conversion to SPS data *)
spssignal=Round2[fsignal[[lofelement;;hifelement]]*adcsens+spsoffset]; (* convert to SPS data and add DC offset *)

(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,spssignal[[i]],"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];

}
,{j,1,fftsweeps}
];

(* Add one set of inter-burst padding sweeps to SPS file *)
Do[
{
(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,0,"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];
}
,{j,1,SPSpaddingsweeps}
];

Close[infile];

}
,{k,1,filecount}
];

Close[outfile];

(* Output the analysis report *)
txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW (last FFT sweep of last data file)"; 
txtoutput[[3]]=" Analysis complete: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

panelout=Panel[Column[{
Column[txtoutput[[10;;11]]],
Column[txtoutput[[12;;15]],Alignment->":"],
Column[txtoutput[[16;;51]],Alignment->":"]
}],
Column[txtoutput[[1;;4]]]];

Export[PDFoutfilename<>".pdf",panelout];
Export[PDFoutfilename<>".png",Rasterize[panelout]];
Export[PDFoutfilename<>".wmf",Rasterize[panelout]];

Print["Processing ended "<>DateString[]]

A=Table[0,{i,1,128}];
Do[
A[[i]]=Cos[4*i*10*π/180]-I Sin[4*i*10*π/180]
,{i,1,128}
];
ListPlot[{Re[A],Im[A]}]
ListPlot[Abs[Fourier[A]]]

SIG  Stats Analysis - Std dev, etc, of a single sig file

(********************************************************************************************)
(*                                                                                          *)
(*  User configuration section                                                              *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

Print["Processing started "<>DateString[]]

(* Set directory for input -- contains one or more .sig Gage signal files *)
filebase="R:\\Observation Records\\AJ4CO Observatory\\TWB\\Gage CS1220\\Archive\\20131220 Step Cal\\2013-12-20_30_dB_CH01\\Folder.00001";

(* Set observation start time in year, month, day, hour, minute, and second UTC  *)
startyear=2014;
startmonth=03;
startday=11;
starthour=03;
startmin=08;
startsec=00;

(* Set the R8500 tuned frequency used during digitization, MHz *)
r8500=78.;

(* Set Gage data sample rate in MHz *)
samplerate=10;

(* Set measured cycle time in milliseconds between trigger events *)
cycletime=392;

(* Set number of FFT bins *)
fftbins=2048;

(* Set low freq and high freq limits of FFT display in MHz *)
(* This is the portion of the FFT that we want to see; i.e., the actual near-baseband output of the TWB *)
(* See below for the RF input frequency setting to be placed in the SPS file *)
displaylof=2.8;
displayhif=4.8;

(* SPS file detector sensitivity in ADC counts per dB *)
adcsens=50;

(* Set DC offset (in μW) to be added to FFT before calculatind dBm *)
dcoffset=100;

(* Set DC offset (in dBm) to be added to FFT before conversion to SPS data *)
postdcoffset=11;

(* Set DC offset (in ADC counts) to be added before export to SPS file *)
spsoffset=1000;

(* Set desired sweep rate in SPS data file in Hz *)
SPSsweeprate=4882.8125;

(********************************************************************************************)
(*                                                                                          *)
(*  End of user configuration section                                                       *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Function definitions section                                                            *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Define proper rounding function as MM only rounds 0.5 up when the result is an even number *)
SetAttributes[Round2,Listable];
Round2[a_]:=If[FractionalPart[a]≥1/2,Ceiling[a],Floor[a]];

(* Define read string function                                  *)
(* file = input file stream                                     *)
(* len = number of characters to retrieve                       *)
ReadStringFunc[file_,len_]:=
Module[{f=file,l=len},
s="";
Do[{
s=s<>BinaryRead[f, "Character8"];
},
{i,1,l}
];
s
];

(********************************************************************************************)
(*                                                                                          *)
(*  End of function definitions section                                                     *)
(*                                                                                          *)
(********************************************************************************************)



(********************************************************************************************)
(*                                                                                          *)
(*  Main program code                                                                       *)
(*                                                                                          *)
(*                                                                                          *)
(********************************************************************************************)

(* Set the SPS file RF frequency range labels in MHz (derived from R8500 tuned frequency) *)
(* TWB 1st LO (in the upconverter) is 97 MHz, TWB output is 2 MHz wide *)
SPSlof=97-r8500-1.;
SPShif=97-r8500+1.;

(* calculate some FFT and SPS file parameters *)
(* find RBW *)
fftrbw=(samplerate*10^6)/fftbins;
(* fined low frequency element of FFT to export to SPS file *)
lofelement=Round2[fftbins*displaylof/samplerate]+1;
(* find high frequency element of FFT to export to SPS file *)
hifelement=Round2[fftbins*displayhif/samplerate]+1;
(* find total number of bins to export to SPS file (this is the SPS file channel count) *)
outputbincount=hifelement-lofelement+1;

(* Find and count all Gage .sig files in the specified directory *)
fileext=".sig";
SetDirectory[filebase];
infiles=FileNames["*"<>fileext];
filecount=infiles//Length;
Print["Found ",ToString[filecount]," files to process."]

(* Open Gage data file for read *)
(* Open SPS file for write *)
infile=OpenRead[infiles[[1]],BinaryFormat->True];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Calculate observation duration in seconds *)
observationduration=cycletime*filecount/1000.;

(* Calculate time length of digitized data in milliseconds *)
dburstduration=chartsamples/samplerate/1000.;

(* Calculate number of sweeps in the Gage data *)
fftsweeps=Floor[chartsamples/fftbins];

(* Calculate padding in milliseconds needed before start of next digitized burst of data *)
SPSpaddingtime=cycletime-dburstduration;
SPSpaddingsweeps=Round2[fftsweeps*cycletime/dburstduration-fftsweeps];
SPSsweepsperburst=Round2[fftsweeps*cycletime/dburstduration];
SPSsweepsperobservation=SPSsweepsperburst*filecount;

(* Calculate start and stop time to be placed in SPS header *)
SPSchartstart=DateDifference[{1900,1,1},{startyear,startmonth,startday,starthour,startmin,startsec}]+2; (* Time since Dec 30, 1899, 00:00:00.000 UTC *)
SPSchartstartf=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
SPSchartstartfr=DateString[(SPSchartstart-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," UTC"}];
SPSchartend=SPSchartstart+SPSsweepsperobservation/SPSsweeprate/86400.;
SPSchartendf=DateString[(SPSchartend-2)*86400,{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second",".","Millisecond"," UTC"}];
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
SPSfileduration=SPSsweepsperobservation/SPSsweeprate/86400.*24.;
SPStimeexpansionratio=SPSfileduration*3600./observationduration;
SPSminute=60./SPStimeexpansionratio;
*)

(* Generate SPS & PDF filenames and open SPS output file for write *)
starttime=(SPSchartstart-2)*86400;
SPSoutfilename="AJ4CO-TWB-";
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Year"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Month"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Day"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Hour"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Minute"];
SPSoutfilename=SPSoutfilename<>DateString[starttime, "Second"];
PDFoutfilename=SPSoutfilename<>" Analysis";



(* outfile=OpenWrite[SPSoutfilename<>".sps",BinaryFormat->True];

(* Write SPS file header *)
(* Set RSS data file version number 2.2.19 *)
SPSchartversion="0000202019";
WriteString[outfile,SPSchartversion];
BinaryWrite[outfile,SPSchartstart,"Real64"];
BinaryWrite[outfile,SPSchartend,"Real64"];
SPSchartlat=0;
BinaryWrite[outfile,SPSchartlat,"Real64"];
SPSchartlong=0;
BinaryWrite[outfile,SPSchartlong,"Real64"];
SPSchartmax=4095;
BinaryWrite[outfile,SPSchartmax,"Real64"];
SPSchartmin=0;
BinaryWrite[outfile,SPSchartmin,"Real64"];
SPSchartTZ=0;
BinaryWrite[outfile,SPSchartTZ,"Integer16"];
SPSchartsource="TWB       ";
WriteString[outfile,SPSchartsource];
SPSchartauthor="Dave Typinski       ";
WriteString[outfile,SPSchartauthor];
SPSchartlocalname="AJ4CO_TWB           ";
WriteString[outfile,SPSchartlocalname];
SPSchartlocation="High Springs, Florida                   ";
WriteString[outfile,SPSchartlocation];
SPSchartchannels=outputbincount;
BinaryWrite[outfile,SPSchartchannels,"Integer16"];
SPSchartnote="*[[*SWEEPS"<>ToString[SPSsweepsperobservation]<>"ÿLOWF"<>ToString[Round[SPSlof*10^6]]<>"ÿHIF"<>ToString[Round[SPShif*10^6]]<>"ÿSTEPS411ÿDUALSPECFILEFalseÿRCVRÿCOLORRES1ÿ*]]*";
SPSchartnotelength=StringLength[SPSchartnote];
BinaryWrite[outfile,SPSchartnotelength,"Integer32"];
WriteString[outfile,SPSchartnote];

(* Generate text report entries *)
txtoutput=Table["",{i,1,60}];
txtoutput[[1]]=Style["TWB Gage Signal File to RSS SPS File Converter",Larger,Darker[Darker[Blue]],Bold];
txtoutput[[2]]=" Analysis run date: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

txtoutput[[10]]=Style["Data Conversion Analysis Report",Bold];

txtoutput[[12]]="Observation start time: "<>SPSchartstartfr;
txtoutput[[13]]="Duration of observation: "<>ToString[observationduration]<>" real-time seconds";

txtoutput[[15]]="Data directory: "<>filebase;
txtoutput[[16]]="Number of digitized input files: "<> ToString[filecount];
txtoutput[[17]]="First input filename: "<>infiles[[1]];
txtoutput[[18]]="Last input filename: "<>infiles[[filecount]];

txtoutput[[20]]="Digitized burst file size: "<>ToString[chartsamples]<>" samples per file";
txtoutput[[21]]="Digitized burst file sample rate: "<>ToString[samplerate]<>" MHz";
txtoutput[[22]]="Digitized burst file duration: "<>ToString[dburstduration]<>" ms";
txtoutput[[23]]="Digitized burst cycle time: "<>ToString[cycletime]<>" ms";
txtoutput[[24]]="Dead time between data bursts: "<>ToString[SPSpaddingtime]<>" ms";
txtoutput[[25]]="Digitization coverage: "<>ToString[dburstduration/cycletime*100.]<>" percent";

txtoutput[[27]]="FFT bins: "<>ToString[fftbins];
txtoutput[[28]]="FFT sweep time: "<>ToString[fftbins/samplerate*1.]<>" μs";
txtoutput[[29]]="FFT sweeps per digitized data burst: "<>ToString[fftsweeps];
txtoutput[[30]]="Dead FFT sweeps between each digitized data burst: "<>ToString[SPSpaddingsweeps];
txtoutput[[31]]="FFT sweeps per digitized data burst including dead time padding: "<>ToString[SPSsweepsperburst];
txtoutput[[32]]="Total FFT sweeps for "<>ToString[filecount]<>" input files, including padding: "<>ToString[SPSsweepsperobservation];

txtoutput[[34]]="FFT BW: "<>ToString[fftrbw*(fftbins/2)/10^6]<>" MHz";
txtoutput[[35]]="FFT RBW: "<>ToString[fftrbw/1000.]<>" kHz";
txtoutput[[36]]="FFT Windowing: "<>"None (uniform window)";
txtoutput[[37]]="FFT display low frequency: "<>ToString[displaylof]<>" MHz ( FFT bin # "<>ToString[lofelement]<>" )";
txtoutput[[38]]="FFT display high frequency: "<>ToString[displayhif]<>" MHz ( FFT bin # "<>ToString[hifelement]<>" )";
txtoutput[[39]]="Total FFT bins exported to SPS file: "<>ToString[outputbincount];

(* txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW"; *)
txtoutput[[42]]="DC offset applied to FFT before calculating dBm: "<>ToString[dcoffset]<>" μW";
txtoutput[[43]]="DC offset applied to FFT after calculating dBm: "<>ToString[postdcoffset]<>" dBm";
txtoutput[[44]]="SPS file detector sensitivity: "<>ToString[adcsens]<>" ADC counts per dB";
txtoutput[[45]]="DC offset applied to SPS data before export to SPS file: "<>ToString[spsoffset]<>" ADC counts";

txtoutput[[47]]="SPS output file name: "<>SPSoutfilename<>".sps";
txtoutput[[48]]="SPS data file sweep rate: "<>ToString[SPSsweeprate]<>" sweeps (FFT spectra) per second";
txtoutput[[49]]="SPS file start time: "<>SPSchartstartf;
txtoutput[[50]]="SPS file end time: "<>SPSchartendf;
(*
(* not needed w=now that RSS can display milliseconds -- until we need mircosecond resolution *)
txtoutput[[51]]="SPS file duration: "<>ToString[SPSfileduration]<>" hours";
txtoutput[[52]]="SPS file time expansion ratio: "<>ToString[SPStimeexpansionratio]<>" to 1";
txtoutput[[53]]="One minute of SPS file time represents: "<>ToString[SPSminute*1000.]<>" milliseconds of real time";
*)
(* close first .sig file to reset processing -- main loop must start with the header read operations *)

*)
Close[infile];

(***********************************************************)
(*                                                         *)
(* MAIN LOOP to cycle through all the available .sig files *)
(*                                                         *)
(***********************************************************)

Do[
{
infile=OpenRead[infiles[[k]],BinaryFormat->True];

Print["Processing file "<>infiles[[k]]];

(* Read fixed length header portion of Gage sig file - 512 bytes total *)
chartversion="";
chartversion=ReadStringFunc[infile,14];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,9];
dummy=BinaryRead[infile,"Integer16"];
dummy=ReadStringFunc[infile,256];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamplerateindex="";
chartsamplerateindex=BinaryRead[infile,"Integer16"];
chartchannels="";
chartchannels=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsamples="";
chartsamples=BinaryRead[infile,"Integer32"];
chartinputrangeindex="";
chartinputrangeindex=BinaryRead[infile,"Integer16",ByteOrdering->-1];
chartinputcoupling="";
chartinputcoupling=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"Integer32"];
charttime="";
charttime=BinaryRead[infile,"UnsignedInteger16"];
chartdate="";
chartdate=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartboardtype="";
chartboardtype=BinaryRead[infile,"UnsignedInteger16"];
chartresolution="";
chartresolution=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
chartsampleoffset="";
chartsampleoffset=BinaryRead[infile,"Integer16"];
chartsampleresolution="";
chartsampleresolution=BinaryRead[infile,"Integer16"];
chartsamplebits="";
chartsamplebits=BinaryRead[infile,"Integer16"];
chartextendedtriggertime="";
chartextendedtriggertime=BinaryRead[infile,"UnsignedInteger32"];
chartinputimedance="";
chartinputimedance=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Integer16"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Real32"];
dummy=BinaryRead[infile,"Integer32"];
dummy=BinaryRead[infile,"UnsignedInteger16"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=BinaryRead[infile,"UnsignedInteger32"];
dummy=ReadStringFunc[infile,127];
(* End of header data *)

(* Read all signal data from one file *)
signal=Table[0.,{i,1,chartsamples}];
Do[
signal[[i]]=BinaryRead[infile,"Integer16"]
,{i,1,chartsamples}
];

Print["File name: ",infiles[[k]]];
Print["Samples: ",chartsamples];
Print["Min: ",Min[signal]];
Print["Max: ",Max[signal]];
Print["Median: ",Median[signal]];
Print["Mean: ",Mean[signal]*1.];
Print["Std Dev = ",StandardDeviation[signal]*1.];

(*
(* Perform FFT analysis of signal data for one file *)
Do[
{
fsignal=Abs[Fourier[signal[[fftbins*j-fftbins+1;;fftbins*j]]]]^2/50; (* power spectrum in uW into 50 ohms *)
fsignal = fsignal+dcoffset; (* add DC offset to spectrum prior to conversion to dBm *)
fsignal=fsignal/1000; (* convert uW to mW *)
fsignal=10*Log10[fsignal/1]; (* convert mW to dBm *)
fsignal = fsignal+postdcoffset;  (* bring floor above 0 dBm prior to conversion to SPS data *)
spssignal=Round2[fsignal[[lofelement;;hifelement]]*adcsens+spsoffset]; (* convert to SPS data and add DC offset *)

(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,spssignal[[i]],"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];

}
,{j,1,fftsweeps}
];

(* Add one set of inter-burst padding sweeps to SPS file *)
Do[
{
(* Write one FFT sweep to the SPS file *)
Do[
{
BinaryWrite[outfile,0,"UnsignedInteger16",ByteOrdering->+1];
}
,{i,1,outputbincount}
];
(* Write EOR marker *)
(* The EOR marker is two consecutive 0xFE characters, ASCII "þ" *)
(* This is seens as 65278 decimal when read as a 2-byte integer  *)
BinaryWrite[outfile,65278,"UnsignedInteger16",ByteOrdering->+1];
}
,{j,1,SPSpaddingsweeps}
];

*)

Close[infile];

}
,{k,1,5}
];

(*
Close[outfile];

(* Output the analysis report *)
txtoutput[[41]]="DC offset per FFT element zero: "<>ToString[fsignal[[1]]]<>" μW (last FFT sweep of last data file)"; 
txtoutput[[3]]=" Analysis complete: "<>DateString[{"Day"," ","MonthNameShort"," ","Year"," ","Hour24",":","Minute",":","Second"," Local"}];

panelout=Panel[Column[{
Column[txtoutput[[10;;11]]],
Column[txtoutput[[12;;15]],Alignment->":"],
Column[txtoutput[[16;;51]],Alignment->":"]
}],
Column[txtoutput[[1;;4]]]];

Export[PDFoutfilename<>".pdf",panelout];
Export[PDFoutfilename<>".png",Rasterize[panelout]];
Export[PDFoutfilename<>".wmf",Rasterize[panelout]];
*)
Print["Processing ended "<>DateString[]]

Test Area

filebase="R:\\Observation Records\\AJ4CO Archive\\2013\\TWB\\Gage CS1220\\20140311 Io-B";
fileext=".sig";
SetDirectory[filebase];
infiles=Select[FileNames[],DirectoryQ];
dirs=infiles//Length;
Print["Found ",ToString[dirs]," directories to process in ",filebase];

Do[
{
filebase2=filebase<>"\\"<>infiles[[dirscounter]];
SetDirectory[filebase2];
infiles2=Select[FileNames[],DirectoryQ];
dirs2=infiles2//Length;
Print["Found ",ToString[dirs2]," directories to process in ",filebase2];

Do[
{
filebase3=filebase2<>"\\"<>infiles2[[dirscounter2]];
SetDirectory[filebase3];
infiles3=FileNames["*"<>fileext];
filecount=infiles3//Length;
Print[dirscounter,"  Found ",ToString[filecount]," files to process in ",filebase3];

(**************************************************)
(* Pricessing code goes here                      *)
(**************************************************)

},{dirscounter2,1,dirs2}
]

},{dirscounter,1,dirs}
]

filebase="R:\\Observation Records\\AJ4CO Observatory\\TWB\\Gage CS1220\\2014 09 26 Test";
SetDirectory[filebase];
freqs=Import["freqs.csv"];
freqs[[2,7]]
freqs

freqs

test=RotateLeft[freqs,{1,0}]