├── .gitignore ├── LICENSE.md ├── README.md ├── apm_struct_ext.m ├── apply_detection.m ├── beam_pattern.m ├── compute_crb.m ├── compute_emitters_from_lr.m ├── convert_fol_ix.m ├── cs_average.m ├── cs_from_fft.m ├── cs_header_struct.m ├── cs_load.m ├── cs_ship_rm.m ├── data ├── BML1 │ ├── APM │ │ ├── BML1_Header.txt │ │ └── MeasPattern_BML1.txt │ ├── CSS │ │ ├── CSS_BML1_19_02_17_1700.cs │ │ ├── CSS_BML1_19_02_17_1710.cs │ │ ├── CSS_BML1_19_02_17_1720.cs │ │ ├── CSS_BML1_19_02_17_1730.cs │ │ ├── CSS_BML1_19_02_17_1740.cs │ │ ├── CSS_BML1_19_02_17_1750.cs │ │ ├── CSS_BML1_19_02_17_1800.cs │ │ ├── CSS_BML1_19_02_17_1810.cs │ │ ├── CSS_BML1_19_02_17_1820.cs │ │ ├── CSS_BML1_19_02_17_1830.cs │ │ ├── CSS_BML1_19_02_17_1840.cs │ │ ├── CSS_BML1_19_02_17_1850.cs │ │ ├── CSS_BML1_19_02_17_1900.cs │ │ ├── CSS_BML1_19_02_17_1910.cs │ │ ├── CSS_BML1_19_02_17_1920.cs │ │ ├── CSS_BML1_19_02_17_1930.cs │ │ ├── CSS_BML1_19_02_17_1940.cs │ │ ├── CSS_BML1_19_02_17_1950.cs │ │ ├── CSS_BML1_19_02_17_2000.cs │ │ ├── CSS_BML1_19_02_17_2010.cs │ │ ├── CSS_BML1_19_02_17_2020.cs │ │ ├── CSS_BML1_19_02_17_2030.cs │ │ ├── CSS_BML1_19_02_17_2040.cs │ │ ├── CSS_BML1_19_02_17_2050.cs │ │ ├── CSS_BML1_19_02_17_2100.cs │ │ ├── CSS_BML1_19_02_18_1700.cs │ │ ├── CSS_BML1_19_02_18_1710.cs │ │ ├── CSS_BML1_19_02_18_1720.cs │ │ ├── CSS_BML1_19_02_18_1730.cs │ │ ├── CSS_BML1_19_02_18_1740.cs │ │ ├── CSS_BML1_19_02_18_1750.cs │ │ ├── CSS_BML1_19_02_18_1800.cs │ │ ├── CSS_BML1_19_02_18_1810.cs │ │ ├── CSS_BML1_19_02_18_1820.cs │ │ ├── CSS_BML1_19_02_18_1830.cs │ │ ├── CSS_BML1_19_02_18_1840.cs │ │ ├── CSS_BML1_19_02_18_1850.cs │ │ ├── CSS_BML1_19_02_18_1900.cs │ │ ├── CSS_BML1_19_02_18_1910.cs │ │ ├── CSS_BML1_19_02_18_1920.cs │ │ ├── CSS_BML1_19_02_18_1930.cs │ │ ├── CSS_BML1_19_02_18_1940.cs │ │ ├── CSS_BML1_19_02_18_1950.cs │ │ ├── CSS_BML1_19_02_18_2000.cs │ │ ├── CSS_BML1_19_02_18_2010.cs │ │ ├── CSS_BML1_19_02_18_2020.cs │ │ ├── CSS_BML1_19_02_18_2030.cs │ │ ├── CSS_BML1_19_02_18_2040.cs │ │ ├── CSS_BML1_19_02_18_2050.cs │ │ └── CSS_BML1_19_02_18_2100.cs │ └── RDLm │ │ ├── RDLm_BML1_2019_02_17_1700.ruv │ │ ├── RDLm_BML1_2019_02_17_1800.ruv │ │ ├── RDLm_BML1_2019_02_17_1900.ruv │ │ ├── RDLm_BML1_2019_02_17_2000.ruv │ │ ├── RDLm_BML1_2019_02_17_2100.ruv │ │ ├── RDLm_BML1_2019_02_18_1700.ruv │ │ ├── RDLm_BML1_2019_02_18_1800.ruv │ │ ├── RDLm_BML1_2019_02_18_1900.ruv │ │ ├── RDLm_BML1_2019_02_18_2000.ruv │ │ └── RDLm_BML1_2019_02_18_2100.ruv └── Mapping │ └── mvco_map_gshhs_f.mat ├── doa_column_index.m ├── doa_on_cs.m ├── doa_on_range_cell.m ├── doa_struct.m ├── getDopplerVelocities.m ├── getFirstOrder.m ├── getNameValuePair.m ├── getVelocities.m ├── get_SNR.m ├── get_array_matrix.m ├── get_radial_meta.m ├── glrt.m ├── hamming.m ├── install_hfr_cs_proc.m ├── make_cov.m ├── make_ula_pattern.m ├── mle_ap.m ├── mle_ap_ss.m ├── mle_test.m ├── music.m ├── music_error.m ├── music_error2.m ├── music_weighted.m ├── other_peoples ├── HFR_Progs-2_1_2 │ └── matlab │ │ ├── general │ │ ├── getNameValuePair.m │ │ └── true2math.m │ │ ├── m_map │ │ ├── m_contour.m │ │ ├── m_contourf.m │ │ ├── m_coord.m │ │ ├── m_elev.m │ │ ├── m_etopo2.m │ │ ├── m_fdist.m │ │ ├── m_grid.m │ │ ├── m_gshhs_f.m │ │ ├── m_gshhs_h.m │ │ ├── m_hatch.m │ │ ├── m_idist.m │ │ ├── m_ll2xy.m │ │ ├── m_pcolor.m │ │ ├── m_proj.m │ │ ├── m_xy2ll.m │ │ ├── mu_coast.m │ │ └── private │ │ │ ├── mc_coords.m │ │ │ └── mu_util.m │ │ └── radials │ │ ├── RADIALmatvars.m │ │ └── getRDLHeader.m ├── imageFOLs-master │ ├── imageFOLs.m │ └── pksfinder.m └── peakfinder.m ├── rad2_to_deg.m ├── run_cs_processing.m ├── run_cs_processing_demo.m ├── run_cs_processing_test.m ├── run_param_test.m ├── signal_power.m ├── signal_power_for_doa_struct.m ├── sml_ap.m ├── test_data_tonys.m ├── tonys_test_data.m ├── tools ├── analysis │ ├── binData.m │ ├── mean_noNaN.m │ ├── mean_weighted.m │ ├── stats_noNaN.m │ └── timeseries │ │ ├── mvave3.m │ │ └── rmsdiff.m ├── codar │ ├── ReadCS.m │ ├── antenna_pattern │ │ ├── apm_struct.m │ │ ├── dbm2volts.m │ │ ├── interp_apm.m │ │ ├── load_pattern_file.m │ │ ├── loop_to_apm.m │ │ ├── magPhase2RealImag.m │ │ ├── make_ideal_pattern.m │ │ ├── plot_apm.m │ │ ├── plot_apm_polar.m │ │ ├── realImag2MagPhase.m │ │ └── volts2dbm.m │ ├── codar_sites.m │ ├── cosFileNameParts.m │ ├── cs_dbm2volts.m │ ├── cs_fieldnames.m │ ├── cs_get_noise_level.m │ ├── cs_make_field_names.m │ ├── cs_plot.m │ ├── cs_plot_bragg_lines.m │ ├── cs_plot_map.m │ ├── cs_read.m │ ├── cs_struct.m │ ├── cs_volts2dbm.m │ ├── ctfReader.m │ ├── ctf_descriptions.m │ ├── ctf_formats.m │ ├── my_hfrp_tools │ │ ├── RADIALstruct.m │ │ ├── loadDataFileWithChecks.m │ │ └── loadRDLFile.m │ ├── private │ │ └── save_ctf_formats.m │ └── radial │ │ └── compute_heading.m ├── general │ ├── add_filesep.m │ ├── conversions │ │ ├── ccwE2cwN.m │ │ ├── cwN2ccwE.m │ │ ├── km2lonlat.m │ │ ├── km2lonlat_new.m │ │ ├── lonlat2km.m │ │ ├── radians.m │ │ ├── rangeBear2LonLat.m │ │ └── rngbear2km.m │ ├── creation_info.m │ ├── datestrq.m │ ├── diff_centered.m │ ├── diff_centered2.m │ ├── dist.m │ ├── fileparts_name.m │ ├── fnames_to_times.m │ ├── get_file_list.m │ ├── max_2d.m │ ├── short_cuts │ │ └── w.m │ ├── strjust2.m │ ├── strparser.m │ └── struct │ │ ├── field_check.m │ │ ├── struct_cat.m │ │ ├── struct_pack.m │ │ ├── struct_unpack.m │ │ └── subsref_struct.m ├── maps │ ├── bathymetry │ │ └── c_line.m │ └── mercat.m └── plotting │ ├── cdot2d.m │ ├── colorbar_label.m │ ├── colorbar_my.m │ ├── errorbarx.m │ ├── legend_append.m │ ├── line_colors.m │ ├── line_style_groups.m │ ├── makesubplots.m │ ├── plot_struct.m │ ├── publicationStandards.m │ ├── set_ylims_auto.m │ └── subplot_add_letters.m └── wsf.m /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled source 2 | *.com 3 | *.class 4 | *.dll 5 | *.exe 6 | *.o 7 | *.so 8 | 9 | # OS generated 10 | .DS_Store 11 | .DS_Store? 12 | ._* 13 | .Spotlight-V100 14 | .Trashes 15 | ehthumbs.db 16 | Thumbs.db 17 | 18 | # Mercurial 19 | .hg/ 20 | .hgignore 21 | .hgsigs 22 | .hgsub 23 | .hgsubstate 24 | .hgtags 25 | -------------------------------------------------------------------------------- /apm_struct_ext.m: -------------------------------------------------------------------------------- 1 | function APM = apm_struct_ext(N) 2 | % APM STRUCT EXT - extended APM struct initialization 3 | % APM = apm_struct_ext(N) 4 | % 5 | % Initialize the APM output structure. *Pre-allocates and 6 | % includes non-standard fields* used in the calculation of 7 | % APMs from ships of opportunity. 8 | 9 | 10 | % Copyright (C) 2009-2010 Brian M. Emery 11 | % June 2009 12 | 13 | 14 | % General, HFRP like stuff 15 | APM.Type = ['Measured Antenna Pattern']; 16 | APM.Creator = 'B. Emery'; 17 | APM.SiteName = 'XXXX'; 18 | APM.SiteOrigin = [NaN NaN]; 19 | APM.FileName = []; 20 | 21 | 22 | % EXPANSION FOR AIS derived APM 23 | % expand README 24 | APM.README.TimeStamp = 'Interpolated from AIS based on RadVel'; 25 | APM.README.BEAR = 'Bearing from HF site to ship using AIS'; 26 | APM.README.fbinIdx = 'Freq Bin Index in the CSQ'; 27 | APM.README.dopplerRadVel = 'Doppler spectrum bin velocities of ship peak (cm/s)'; 28 | APM.README.SNR = 'Various SNR calculations (snr_calculations.m)'; 29 | APM.README.shipID = 'Ship ID from AIS'; 30 | APM.README.Evalue = 'Eigen Values sm to lg'; 31 | APM.README.Evec1 = 'Noise Eigen Vector'; 32 | APM.README.Evec2 = 'Noise Eigen Vector'; 33 | APM.README.Evec3 = 'Signal Eigen Vector (APM components)'; 34 | APM.README.RadVel = 'Mean Ship Radial Velocity and stats'; 35 | APM.README.Lon = 'Interpolated from AIS based on CS radvel'; 36 | APM.README.Lat = 'Interpolated from AIS based on CS radvel'; 37 | 38 | 39 | % DEFINE STANDARD FIELDS 40 | vars = {'TimeStamp','BEAR', 'Lon','Lat'... 41 | 'A13R','A13I','A23R','A23I', ... 42 | 'A13M','A13P','A23M' ,'A23P', ... 43 | 'A33R','A33I'}; 44 | APM = create_empties(APM,vars,N,1); 45 | 46 | 47 | % DEFINE NON-STANDARD FIELDS 48 | vars = {'dopplerRadVel','shipID'... 49 | 'fbinIdx','rCellIdx'}; 50 | APM = create_empties(APM,vars,N,1); 51 | 52 | 53 | % MEAN SHIP RADIAL VELOCITY AND STATS 54 | APM.RadVel.xbar =[]; 55 | vars={'xbar','stdev','hi','lo','median','N'}; 56 | APM.RadVel = create_empties(APM.RadVel,vars,N,1); 57 | 58 | 59 | % EIGEN VALUES AND VECTORS 60 | vars = {'Evalue','Evec1','Evec2','Evec3'}; 61 | APM = create_empties(APM,vars,N,3); 62 | 63 | % SNR DATA 64 | APM.SNR(1).README = {'stdCodar = Standard Codar Method'; ... 65 | 'backGrnd = Above Backgound (from cs_filter.m)' ; ... 66 | 'localDopp = Local adjacent doppler bins (no bragg)' ; ... 67 | 'inRange = Adjacent range cells'}; 68 | vars = {'stdCodar','backGrnd','localDopp','inRange'}; 69 | APM.SNR = create_empties(APM.SNR,vars,N,3); 70 | 71 | 72 | % Empty cells 73 | APM.csqFileName = cell(N,1); 74 | APM.ProcessingSteps = {}; 75 | 76 | % Time, other meta info 77 | APM.CreationInfo = creation_info; 78 | 79 | 80 | end 81 | % -------------------------- 82 | function APM = create_empties(APM,vars,r,c) 83 | 84 | for i = 1:numel(vars) 85 | APM.(vars{i}) = NaN(r,c); 86 | end 87 | 88 | 89 | end 90 | -------------------------------------------------------------------------------- /beam_pattern.m: -------------------------------------------------------------------------------- 1 | function B = beam_pattern(A,ix) 2 | % COMPUTE BEAM PATTERN - see Van Trees, 2002 3 | % B = beam_pattern(A,ix) 4 | % 5 | % INPUT 6 | % A - Array Manifold (Matrix) 7 | % ix - Bearing index of (column) to use in forming the beam pattern 8 | % 9 | % Given one input (A), this assumes uniform weighing. 10 | % 11 | % Note that (abs(B)).^2 gives 12 | % the power as a function of theta, and thus that this 13 | % can be used to find the half power beamwidth 14 | % 15 | % Used to validate make_ula_pattern.m 16 | % 17 | % See also beamwidth.m 18 | 19 | % Copyright(C) 2017 Brian Emery 20 | % 21 | % May 2017 22 | 23 | if strcmp(A,'--t'), test_case, return, end 24 | 25 | 26 | [M,~] = size(A); 27 | 28 | if nargin < 2 29 | % compute the beam pattern with uniform weighting 30 | wt = (1/M)*ones(M,1); % eqn 2.90 31 | 32 | else 33 | % otherwise define the 'conventional beam pattern' as on pg 53 which 34 | % essentially steers the direction and gives the beam pattern in that 35 | % direction. With this B is determined by equation 2.124 36 | wt = (1/M)*A(:,ix); 37 | 38 | end 39 | 40 | % Eqn 2.69 41 | B = wt'*A; 42 | 43 | 44 | 45 | 46 | end 47 | 48 | function test_case 49 | 50 | % theta relative to array axis 51 | th = 0:180; 52 | M = 10; 53 | 54 | [A,dm] = make_ula_pattern(th,M,'vt02'); 55 | 56 | % get the beam pattern 57 | B = beam_pattern(A); 58 | 59 | % Plot half the bottom figure 2.18, pg 46, which plots the magnitude of B 60 | plot(th,abs(B)), title('Compare wtih VT02 Fig 2.18, pg 46') 61 | 62 | hold on 63 | 64 | % Same as broadsize steering 65 | B = beam_pattern(A, find(th==90) ); 66 | 67 | plot(th,abs(B),'o') 68 | 69 | 70 | B = beam_pattern(A, find(th==0) ); 71 | 72 | keyboard 73 | 74 | end 75 | 76 | % first try 77 | function p = compute_beamform(A) 78 | % SEE TF09 pg 6 and try to make the beam pattern fig. This is close 79 | % 80 | % ... something not quite right, not sure what. Their figure is much closer 81 | % to a 10 element array 82 | % 83 | % NOTATION NOTE 84 | % abs(vector) in TF09 is the 2-norm (that is the sum(abs(vector)) 85 | 86 | % see pg 5 for frequency domain beam forming 87 | for i = 1:size(A,2), 88 | W = A(:,i)/norm(A(:,i)); 89 | p(i) = norm( W'*A(:,81) ).^2; 90 | end 91 | 92 | end 93 | -------------------------------------------------------------------------------- /compute_emitters_from_lr.m: -------------------------------------------------------------------------------- 1 | function em = compute_emitters_from_lr(LR,cut) 2 | % COMPUTE EMITTERS FROM LR - find number of emitters given matrix of LR 3 | % [em,tf] = compute_emitters_from_lr(LR,cut) 4 | % 5 | % .. this returns the first column that meets the 6 | % threshold ... thus minimizing the number of emitters 7 | % 8 | % ... also returned is a boolean that is true if the threshold was met 9 | % (and thus false if NOT met) ... in theory ... not done yet? 10 | % 11 | % Assumes: 12 | % % get LR data to use ... could be an input? 13 | % LR = -2*log(S.LR.ML); 14 | % ... this means n when LR drops below the threshold cuttoff value is 15 | % considered the correct value of the number of emitters. (Alternatively, 16 | % this means the LR becomes larger if the -2*log is not applied - the 17 | % treshold is crossed going the other direction. 18 | % 19 | % OUTPUT 20 | % em - array that gives the number of emitters for each row of a DOA matrix 21 | % (structured as in ?) 22 | % tf - ** seems to be unused ** 23 | % 24 | % SEE ALSO 25 | % glrt.m, apply_detection.m 26 | 27 | if nargin < 2, cut = 200; end 28 | 29 | 30 | % create an array that gives the number of emitters for each row 31 | em = NaN(size(LR,1),1); 32 | %tf = false(size(LR,1),1); 33 | 34 | 35 | % look one row at a time 36 | for i = 1:size(LR,1) 37 | 38 | % get a column index .. this returns the first column the meets the 39 | % threshold ... thus minimizing the number of emitters 40 | try em(i) = find( LR(i,:) < cut,1); 41 | 42 | catch 43 | 44 | em(i) = size(LR,2); % disp(['eheck ' num2str(i)]) 45 | 46 | %tf(i) = false; % threshold NOT met 47 | 48 | end % NAN's if N=3?! 49 | 50 | % convert to absolute? 51 | end 52 | 53 | end 54 | 55 | -------------------------------------------------------------------------------- /convert_fol_ix.m: -------------------------------------------------------------------------------- 1 | function peakIdx = convert_fol_ix(FOregi) 2 | % CONVERT FOL IX - convert output of ImageFOLs to cell based format 3 | % 4 | % INTPUT 5 | % FOregi -- The range/Doppler velocity indices of all points marked as 6 | % First Order (FO) in a cross spectra data matrix (sized 7 | % number of range cells by FFT length). 8 | % 9 | % OUTPUT 10 | % peakIdx - A cell array (with numel = (# range cells)), each containing the 11 | % row index points within the First Order peaks. 12 | % 13 | % OUTPUT 14 | % peakIdx - one range cell per cell index, each containing an array of the 15 | % indecies of the first order 16 | % 17 | 18 | % Copyright (C) 2019 Brian Emery 19 | 20 | rng = unique(FOregi(:,1)); 21 | 22 | peakIdx = cell(length(rng),1); 23 | 24 | for i = 1:length(rng) 25 | 26 | peakIdx{i} = FOregi(FOregi==rng(i),2)'; 27 | 28 | end 29 | 30 | 31 | end -------------------------------------------------------------------------------- /cs_average.m: -------------------------------------------------------------------------------- 1 | function [AV,K] = cs_average(CS) 2 | % CS AVERAGE - compute mean of fields in multi element CS structs 3 | % [CSA,K] = cs_average(CS) 4 | % 5 | % Uses all the data in the multi-element input ... robust to empties 6 | % 7 | % For converting CSQ to CSS, or CSS to CSA for example 8 | % 9 | % Given input in dB, with phases resulting from a complex number converted 10 | % to dB, this will compute the average of both, such that the result can be 11 | % converted back to volts^2. "This is one of the simplest examples of 12 | % statistics of non-Euclidean spaces." From: 13 | % https://en.wikipedia.org/wiki/Mean_of_circular_quantities 14 | % 15 | % Now also provides a rough estimate of K, in that it outputs the number of 16 | % files in the average. 17 | % 18 | % SEE ALSO 19 | % cs_dbm2volts.m and related 20 | 21 | % Copyright (C) 2017 Brian Emery 22 | % 23 | % Originally From the COS simulation code, but now much different 24 | 25 | % TO DO 26 | % rm filename 27 | 28 | 29 | % check for test case 30 | if strcmp('--t',CS), test_case, return, end 31 | 32 | 33 | % get data field names 34 | fn = cs_fieldnames(CS); 35 | 36 | 37 | % check for bad files/data, eg. one CSQ with the wrong amount of data 38 | sz = NaN(numel(CS),2); 39 | 40 | for i = 1:numel(CS), sz(i,:) = size(CS(i).(fn{1})); end 41 | 42 | CS = CS(ismember(sz,mode(sz),'rows')); 43 | 44 | 45 | % create output with meta data fields from CS(1) 46 | AV = CS(1); 47 | 48 | for i = 1:numel(fn) 49 | 50 | % need this to get the size 51 | X = cat(3,CS.(fn{i})); 52 | 53 | % compute average 54 | AV.(fn{i}) = sum(X,3)./size(X,3); 55 | end 56 | 57 | % provide for the output 58 | % K = size( cat(3,CSL.antenna3Self) ,3); 59 | K = size(X,3); 60 | 61 | 62 | % run on phases to if we have them 63 | if isfield(CS,'Phases') 64 | 65 | % make a new Phases struct that is multi-elemnent 66 | Ph = [CS.Phases]; 67 | 68 | for i = 1:numel(fn) 69 | 70 | % need this to get the size 71 | X = cat(3,Ph.(fn{i})); 72 | 73 | % compute average of circular quantities 74 | AV.Phases.(fn{i}) = atan2(sum(sin(X),3),sum(cos(X),3)); 75 | 76 | end 77 | end 78 | 79 | % Meta data 80 | AV.ProcessingSteps{end+1} = 'cs_average'; 81 | 82 | % Do I want to compute this? I don't think so 83 | AV.Header.averagingTimeMin = NaN; 84 | 85 | end 86 | 87 | 88 | function test_case 89 | % TEST CASE 90 | % 91 | % test case directory: /m_files/test_data/ 92 | % 93 | % Get data together for this 94 | % wd = '/projects/soo_apm/data/Data_COP1/for_figure/'; 95 | % 96 | % flist = get_file_list(wd,'CSQ*'); 97 | % 98 | % for i = 1:numel(flist) 99 | % CS(i) = ReadCS(flist{i}); 100 | % end 101 | % 102 | % save /m_files/test_data/cs_ship_rm.mat CS 103 | 104 | % TEST for use of Phase info for dB input 105 | 106 | % Get data 107 | load /m_files/test_data/cs_ship_rm.mat CS 108 | 109 | CS = cs_volts2dbm(CS); 110 | 111 | tic 112 | CSA = cs_average(CS); 113 | toc 114 | 115 | keyboard 116 | 117 | 118 | % FUNCTIONAL TEST - Compare with previous 119 | 120 | % % NOTES 121 | % tic, CSA = cs_average(CS); toc 122 | % Elapsed time is 0.013143 seconds. 123 | 124 | 125 | % Get data 126 | load /m_files/test_data/cs_ship_rm.mat CS 127 | 128 | 129 | [CS(1:end).ProcessingSteps] = deal({''}); 130 | [CS(1:end).Units] = deal({''}); 131 | [CS(1:end).freqs] = deal({''}); 132 | [CS(1:end).Vrad] = deal({''}); 133 | 134 | % empty out the center and see if averaging can handle it 135 | CS(3) = cs_struct(1); 136 | 137 | 138 | 139 | % COS VERSION 140 | % Elapsed time is 0.053224 seconds. 141 | % tic 142 | % CS = cs_average(CS,numel(CS)); 143 | % toc 144 | % Elapsed time is 0.018301 seconds. 145 | % tic 146 | % CS = cs_average(CS,numel(CS)); 147 | % toc 148 | % Elapsed time is 0.017488 seconds. 149 | 150 | 151 | % NEW VERSION 152 | % Elapsed time is 0.030244 seconds. 153 | % cs_average('--t') 154 | % Elapsed time is 0.024711 seconds. 155 | % 156 | % ... similar performance: check 157 | tic 158 | CSA = cs_average(CS); 159 | toc 160 | 161 | H = cs_plot(CS(1),12); hold on, 162 | 163 | LS = line_style_groups; 164 | 165 | h = cs_plot(CSA,12,LS(3),H); 166 | 167 | h = cs_plot(CS(5),12,LS(2),h); 168 | 169 | 170 | keyboard 171 | 172 | % EXTRA 173 | % test the 3d mean of the phases 174 | x = [-175 175 120 145 -177]; % arithmetic mean is ~77 which is not right! 175 | for i = 1:5 176 | X(1:10,1:10,i) = x(i)*pi/180; 177 | end 178 | 179 | X_ = atan2(sum(sin(X),3),sum(cos(X),3)); % gets about 162 deg 180 | 181 | 182 | end 183 | -------------------------------------------------------------------------------- /cs_from_fft.m: -------------------------------------------------------------------------------- 1 | function CS = cs_from_fft( fftm,CFG) %V1,V2,V3,CFG) 2 | % FORM THE CROSS SPECTRA - from FFTs 3 | % 4 | % INPUTS 5 | % = fftm - The N rows by length(FFT) columns 6 | % V1,V2,V3 - Doppler spectra, ie the output of the FFT performed on the 7 | % Range data 8 | % CFG - Optional configuration specifying some of the outputs 9 | % 10 | % This function was made for simulation data, which assumes one range cell 11 | % at at time. Thus the input = fftm is # antennas x # length(fft) 12 | 13 | 14 | % NOTES 15 | % "In most practical situations, this level of information is not 16 | % available, however, and one must resort to estimating a given signal's 17 | % power spectral density. One very straightforward approach is to take 18 | % the magnitude squared of its Fourier transform (or, perhaps, take the 19 | % squared magnitude of several short-time Fourier transforms and average 20 | % them) as the estimate of the PSD." 21 | % 22 | % So the Auto spectra are the PSD! 23 | % (from https://dsp.stackexchange.com/questions/4691/) 24 | 25 | % check for test case 26 | if strcmp('--t', fftm), test_case, return, end 27 | 28 | 29 | 30 | % set defaults 31 | if nargin < 2 32 | CFG.output_ts = false; 33 | CFG.output_fft = false; 34 | end 35 | 36 | % get number of antennas 37 | m = size(fftm,1); 38 | 39 | if m == 3 40 | 41 | % Get struct setup 42 | CS = cs_struct; 43 | 44 | else 45 | CS = cs_struct(1,m); 46 | 47 | end 48 | 49 | 50 | % use subfunction to make a header 51 | CS.Header = cs_header_struct; 52 | 53 | 54 | if nargin == 2 55 | 56 | % Reconcile range and CS header data 57 | CS.Header.freqMHz = CFG.txfreq; 58 | CS.Header.SwBWkHz = CFG.bw; 59 | CS.Header.SwRfreqHz = CFG.srf; 60 | CS.Header.nRangeCells = CFG.nRC; 61 | CS.Header.fftLength = CFG.nfft; 62 | 63 | end 64 | 65 | 66 | 67 | 68 | if m == 3 69 | 70 | % use previous method and formats ... wants columns 71 | CS = old_way( fftm(1,:).', fftm(2,:).', fftm(3,:).',CS); 72 | 73 | else 74 | 75 | % new way - arbitrary arrays 76 | CS = new_way( fftm,CS); 77 | 78 | 79 | end 80 | 81 | 82 | % add couple things 83 | 84 | % Quality array from zero to one in value. 85 | [ CS.spectraQualNum ] = deal(zeros(size( fftm,2),1)); 86 | 87 | CS.rdCSErr = 0; 88 | CS.FileName = ''; 89 | 90 | [CS.freqs,CS.Vrad,~] = getVelocities(CS.Header); 91 | 92 | 93 | if CFG.output_fft 94 | 95 | % need to fix this .. or punt! 96 | % CS.V1 = V1; 97 | CS. fftm = fftm; 98 | 99 | end 100 | 101 | 102 | 103 | 104 | end 105 | 106 | function CS = old_way(V1,V2,V3,CS) 107 | 108 | CS.antenna1Self = abs(V1).^2 ; 109 | CS.antenna2Self = abs(V2).^2 ; 110 | CS.antenna3Self = abs(V3).^2 ; 111 | CS.antenna12CrossSp = V1.*conj(V2) ; 112 | CS.antenna13CrossSp = V1.*conj(V3) ; 113 | CS.antenna23CrossSp = V2.*conj(V3) ; 114 | 115 | 116 | end 117 | 118 | function CS = new_way( fftm,CS) 119 | % 120 | 121 | % get number of antennas 122 | m = size( fftm,1); 123 | 124 | % Apply transpose to row shape (CS are nfft x nRC) typically 125 | fftm = fftm.'; 126 | 127 | 128 | % get field names (could also read these?), and corresponding row,col 129 | % indecies 130 | [fn,I,J] = cs_make_field_names(m); 131 | 132 | for i = 1:length(I) 133 | 134 | % ... ok, very slight differences from old way unless I do this 135 | if I(i) == J(i) 136 | 137 | CS.(fn{i}) = abs( fftm(:,I(i))).^2 ; 138 | 139 | else 140 | 141 | % now calc auto and cross products 142 | CS.(fn{i}) = fftm(:,I(i)) .* conj( fftm(:,J(i))) ; 143 | 144 | end 145 | end 146 | 147 | 148 | end 149 | 150 | 151 | function test_case 152 | % TEST CASE 153 | % 154 | % Test new method vs old method functionality 155 | % 156 | % data for this created with radar_simulation.m test 157 | % 158 | 159 | 160 | 161 | % load data 162 | load /m_files/test_data/cs_from_fft.mat 163 | 164 | % Create data using old way 165 | CSo = old_way( fftm(1,:).', fftm(2,:).', fftm(3,:).',CS); 166 | 167 | fno = cs_fieldnames(CSo); 168 | 169 | % Create data using new way 170 | CSn = new_way( fftm,CS); 171 | 172 | 173 | % compare 174 | % fno = 175 | % 176 | % 'antenna1Self' 177 | % 'antenna2Self' 178 | % 'antenna3Self' 179 | % 'antenna12CrossSp' 180 | % 'antenna13CrossSp' 181 | % 'antenna23CrossSp' 182 | % 183 | 184 | fnn = {'a11','a22','a33','a12','a13','a23'}; 185 | 186 | disp('cs_from_fft.m ...') 187 | 188 | for i = 1:length(fnn) 189 | compare_results(CSn.(fnn{i}),CSo.(fno{i})) 190 | end 191 | 192 | keyboard 193 | 194 | end 195 | 196 | 197 | function compare_results(old,new) 198 | 199 | 200 | if isequal(old,new) 201 | disp(' ... ok') 202 | else 203 | disp(' ... NOT OK') 204 | keyboard 205 | end 206 | 207 | 208 | 209 | end -------------------------------------------------------------------------------- /cs_header_struct.m: -------------------------------------------------------------------------------- 1 | function H = cs_header_struct 2 | % MAKE CS HEADER - Make the header for a CS file 3 | % Header = cs_header_struct 4 | % 5 | % SEE WRITE CS HEADER.M 6 | % 7 | % Note that the file name appears to be the start time of the data in the 8 | % file. 9 | 10 | %//For dateSec, 695422 == Jan 1, 1904, 4294967296 == 2^32 11 | %//dateSec = fix((daysAD - 695422)*(24*60*60)); %// int32 12 | H.dateTimeSec04 = (now - 695422)*(24*60*60) - 4294967296; 13 | 14 | 15 | H.kindOfData = 1; % 1 is 'raw', 2 is averaged 16 | H.siteStr = ''; 17 | H.averagingTimeMin = []; 18 | H.freqMHz = []; %13.4900; 19 | H.SwRfreqHz = []; %2; 20 | H.SwBWkHz = []; %100.7080; 21 | H.sweepUp = []; %0; 22 | H.nRangeCells = []; 23 | H.firstRangeCell = 0; 24 | H.distToFirstRangeCell = [];% 1.4895; 25 | H.dTHex = []; 26 | H.deleteRawSpectra = 0; 27 | H.overrideRemHeader = 0; 28 | H.fftLength = []; %512; 29 | 30 | % 31 | % %// Collect header data 32 | % version = 4; %// int16 33 | % dateSec = (daysAD - 695422)*(24*60*60) - 4294967296; 34 | % bytesLeft1 = 62; %// int32 35 | % if simOpt(5) == 1 36 | % dataKind = 1; %// int16 (Raw CS) 37 | % else 38 | % dataKind = 2; %// int16 (Averaged CS) 39 | % end 40 | % bytesLeft2 = 56; %// int32 41 | % site = simSite; %// char, 4 bytes 42 | % bytesLeft3 = 48; %// int32 43 | % if simOpt(5) == 1 44 | % averagingTime = 0; %// int32 (raw CS) 45 | % else 46 | % averagingTime = avgTime; %// int32 47 | % end 48 | % deleteAfter = 0; %// int32 49 | % overrideHeader = 0; %// int32 50 | % frequency = txfreq; %// float32 51 | % sweepRepFreq = simSRF; %// float32 52 | % sweepBandwidth = simSBW; %// float32 %//(=150.0/deltaRC) 53 | % sweepIsUp = 0; %// int32 54 | % sizeOfFFT = 512; %// int32 55 | % numberOfRCs = nRCs; %// int32 56 | % firstRC = simFirstRC; %// int32 57 | % distToFirst = firstRC*150.0/sweepBandwidth; %// float32 58 | % bytesLeft4 = 0; 59 | % 60 | % fn = '/m_files/test_data/getDopplerVelocities/CSQ_cop1_08_12_06_200428.cs'; 61 | % dat = cs_read(fn,':',1); 62 | % 63 | % Header = dat.Header; 64 | % Header.siteStr = 'SCrz'; 65 | % Header.freqMHz = 13.45; %txfreq; 66 | % Header.SwBWkHz = 100; 67 | % Header.nRangeCells = 1; 68 | 69 | end 70 | -------------------------------------------------------------------------------- /data/BML1/APM/BML1_Header.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/APM/BML1_Header.txt -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1700.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1700.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1710.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1710.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1720.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1720.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1730.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1730.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1740.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1740.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1750.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1750.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1800.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1800.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1810.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1810.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1820.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1820.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1830.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1830.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1840.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1840.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1850.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1850.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1900.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1900.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1910.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1910.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1920.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1920.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1930.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1930.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1940.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1940.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_1950.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_1950.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2000.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2000.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2010.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2010.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2020.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2020.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2030.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2030.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2040.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2040.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2050.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2050.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_17_2100.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_17_2100.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1700.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1700.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1710.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1710.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1720.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1720.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1730.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1730.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1740.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1740.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1750.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1750.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1800.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1800.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1810.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1810.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1820.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1820.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1830.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1830.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1840.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1840.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1850.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1850.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1900.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1900.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1910.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1910.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1920.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1920.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1930.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1930.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1940.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1940.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_1950.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_1950.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2000.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2000.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2010.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2010.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2020.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2020.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2030.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2030.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2040.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2040.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2050.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2050.cs -------------------------------------------------------------------------------- /data/BML1/CSS/CSS_BML1_19_02_18_2100.cs: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/BML1/CSS/CSS_BML1_19_02_18_2100.cs -------------------------------------------------------------------------------- /data/Mapping/mvco_map_gshhs_f.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/data/Mapping/mvco_map_gshhs_f.mat -------------------------------------------------------------------------------- /doa_column_index.m: -------------------------------------------------------------------------------- 1 | function col = doa_column_index(max_n) 2 | % CREATE DOA COLUMN INDEX - map of number of emitters to the column index 3 | % 4 | % DOA structs have a matrix of (for example) the DOA solution for 1 5 | % emitter, 2 emitter, etc solutions, where these are placed in columns. 6 | % This creates the indexing that maps the number of emitters to the columns of 7 | % the DOA matrix. (Note that the DOA stuct holds data prior to the 8 | % application of detection methods). 9 | % 10 | % EXAMPLE OUTPUT` 11 | % col{:} 12 | % ans = 1 13 | % ans = 2 3 14 | % ans = 4 5 6 15 | % ans = 7 8 9 10 16 | % ans = 11 12 13 14 15 17 | % ans = 16 17 18 19 20 21 18 | % ans = 22 23 24 25 26 27 28 19 | % 20 | % SEE ALSO 21 | % doa_on_range_cell.m 22 | 23 | % Copyright (C) 2020 Brian M. Emery 24 | 25 | % ... worked out empirically ... 26 | 27 | % preallocate 28 | col = cell(1,max_n); 29 | 30 | % create the indexing 31 | for i = 1:max_n 32 | 33 | % get the starting index 34 | i1 = sum(1:i) - i + 1; 35 | 36 | % create the column indexing 37 | col{i} = i1: (i1+i-1); 38 | 39 | end 40 | 41 | end 42 | 43 | -------------------------------------------------------------------------------- /doa_on_cs.m: -------------------------------------------------------------------------------- 1 | function S = doa_on_cs(CS,APM,peakIdx,K,CFG) %,n,dmth) 2 | % DOA ON CS - run DOA processing on CS data 3 | % S = doa_on_cs(CS,APM,peakIdx,K,CFG) 4 | % 5 | % A more general version of radial_from_cs.m, called by run_cs_processing.m 6 | % and run_rng_processing.m 7 | % 8 | % Make sure CS have not been converted to dBm 9 | % 10 | % INPUTS 11 | % CS struct, APM struct, peakIdx as a cell 12 | % ... K snapshots for music error 13 | % peakIdx - A cell array (with numel = (# range cells)), each containing the 14 | % row index points within the First Order peaks. 15 | % CFG should have: 16 | % Nemit, dmth, use_parfor,mus_params ... 17 | % 18 | % OUTPUTS 19 | % doa struct 20 | % 21 | % FROM doa_on_range_cell.m, which it now calls 22 | % 23 | % SEE ALSO 24 | % radial_from_cs.m (old) 25 | 26 | % Copyright (C) 2017 Brian Emery 27 | % 28 | % version 10-Apr-2017 14:56:35 29 | % derived from earlier versions of radial_from_cs.m 30 | % 31 | % updates Nov 2018 to merge with doa_on_range_cell.m 32 | 33 | % TO DO 34 | % 35 | % appear to sometimes get dual= true when there is only one velocity 36 | % solution ... see vr_averaging_investigation.m for evidence, but code here 37 | % could probably test that there is a 2nd velocity and mark it single 38 | % otherwise 39 | 40 | 41 | % Check for test 42 | if strcmp('--t',CS), test_case, return, end 43 | 44 | 45 | % CONFIGURE, CHECK INPUTS 46 | 47 | if nargin < 4 48 | % Infer the number of data snapshots (about 3.5?) ... less desirable 49 | K = CS.Header.averagingTimeMin/((CS.Header.fftLength/CS.Header.SwRfreqHz)/60); 50 | 51 | % disp(['Computed value of K from Header info: ' num2str(K) ]) 52 | 53 | end 54 | 55 | if nargin < 5 56 | % also set emitters to search for 57 | CFG.Nemit = 2; 58 | CFG.dmth = {'mu'}; 59 | CFG.use_parfor = false; 60 | CFG.mus_param = [10 5 8]; 61 | end 62 | 63 | n = CFG.Nemit; 64 | 65 | 66 | % make sure units are *NOT* dbm 67 | if isfield(CS,'Units') && strcmp('dBm',CS.Units) 68 | CS = cs_dbm2volts(CS); 69 | end 70 | 71 | % Pre-pre allocate, more or less 72 | [S(1:numel(peakIdx))] = deal(doa_struct(1,n,n,CFG.dmth)); 73 | 74 | 75 | 76 | 77 | 78 | % GET THE DOAS WITH CONDITIONAL PARFOR 79 | % [~,r] = system('hostname'); % r = 'parfor disabled' 80 | 81 | if ~(CFG.use_parfor) %|| strncmp(r,'yourcomputer',12) ... strncmp(r,'ekman',5) && 82 | 83 | for rc = 1:numel(peakIdx) 84 | 85 | S(rc) = doa_on_range_cell(CS,APM,peakIdx{rc},rc,K,CFG); %,n,dmth); 86 | 87 | end 88 | 89 | elseif CFG.use_parfor 90 | 91 | parfor rc = 1:numel(peakIdx) % %PARFOR over different range cells 92 | 93 | S(rc) = doa_on_range_cell(CS,APM,peakIdx{rc},rc,K,CFG); %n,dmth); 94 | 95 | end 96 | 97 | end 98 | 99 | 100 | % Concat all the range cells 101 | S = struct_cat(1,S); 102 | 103 | % Document 104 | try, S.ProcessingSteps = {'doa_on_range_cell','doa_on_cs.m'}; catch, end 105 | 106 | 107 | end 108 | 109 | 110 | function test_case 111 | % TEST CASE 112 | % 113 | % dev test data from cs_read.m 114 | 115 | % Get cs test filename 116 | fn = '/m_files/test_data/compute_apm_from_csq/CSQ_cop1_08_12_06_205124.cs'; 117 | 118 | % probably not a valid APM for this CS but good enough for the functional 119 | % test ... 120 | load /m_files/test_data/doa_on_range_cell.mat APM 121 | 122 | 123 | % load subset of range cells and see how they compare 124 | CS = ReadCS(fn); 125 | 126 | [CS.freqs,CS.Vrad,CS.fb] = getVelocities(CS.Header); 127 | 128 | % FOL processing (rows are range cells) 129 | user_param = [40 100 5]; 130 | 131 | % ... from subfunction to run_cs_processing ... 132 | [~,Vrad,~] = getVelocities(CS.Header); 133 | 134 | [~,~,dv] = getDopplerVelocities(CS.Header); 135 | 136 | n = length(Vrad)/2; 137 | 138 | % get approx indecies of Bragg lines ... in general 139 | [~,iBragg(1)] = min( abs( Vrad(1:n)) ) ; 140 | [~,iBragg(2)] = min( abs( Vrad(n:end)) ) ; 141 | 142 | % adjust last result 143 | iBragg(2) = iBragg(2) + n - 1; 144 | 145 | % velocity increment m/s 146 | v_incr = dv/100; %mode(diff(Vrad))/100; 147 | 148 | % get distance to first range cell 149 | rkm = CS.Header.distToFirstRangeCell; 150 | 151 | % ... 152 | 153 | [~, FOregi, ~] = imageFOLs(CS.antenna3Self.',iBragg,v_incr,user_param); 154 | 155 | % convert FOregi to peakIdx 156 | peakIdx = convert_fol_ix(FOregi); 157 | 158 | 159 | % check plot 160 | rc = 25; 161 | plot(1:512,real(10*log10(CS.antenna12CrossSp(:,rc))),'-'), hold on 162 | 163 | plot(peakIdx{rc},real(10*log10(CS.antenna12CrossSp(peakIdx{rc},rc))),'*'), hold on 164 | 165 | 166 | S = doa_on_cs(CS,APM,peakIdx); 167 | 168 | 169 | keyboard 170 | 171 | 172 | 173 | 174 | % OLDER SIMPLER TEST (AND TIMES, PERHAPS) 175 | 176 | % % .. a low SNR case from who knows where ... 177 | % load /m_files/test_data/doa_on_range_cell.mat 178 | 179 | [CS.freqs,CS.Vrad,CS.fb] = getVelocities(CS.Header); 180 | 181 | CS.SNR = get_SNR(CS); 182 | 183 | 184 | plot(CS.freqs,10*log10(CS.antenna3Self)) 185 | hold on 186 | plot(CS.freqs(peakIdx),10*log10(CS.antenna3Self(peakIdx)),'ro') 187 | 188 | % doa_on_cs requires cell input for peakIdx 189 | px = peakIdx; 190 | peakIdx = {px}; 191 | peakIdx{2} = px; % build up for parfor testing ... must match nmber of rc's 192 | 193 | 194 | 195 | tic 196 | [MU,ML] = doa_on_cs(CS,APM,peakIdx); 197 | 198 | toc 199 | % With PARFOR 200 | % Elapsed time is 27.734820 seconds. 201 | % 202 | % Witout PARFOR 203 | % Elapsed time is 98.712372 seconds. 204 | keyboard 205 | 206 | end 207 | -------------------------------------------------------------------------------- /doa_struct.m: -------------------------------------------------------------------------------- 1 | function R = doa_struct(r,n,m,fn) 2 | % DOA STRUCT - create empty struct for DOA solutions 3 | % R = doa_struct(r,n,m,dmth) 4 | % 5 | % r = number of rows for each field 6 | % n = number of emitters that will be searched for 7 | % m = size of cov matrix 8 | % dmth = cell of doa methods ({'MU','ML','WM','WF','SM'};) 9 | % 10 | % NOTES 11 | % 12 | % 1) that this creates large matricies containing the single, dual, three, 13 | % ... up to n DOA solutions, so these are intended as an intermediate data 14 | % structure that could be transitioned to a Radial struct after applying 15 | % the hypothesis testing (aka signal detection) step. 16 | % 17 | % 2) These are created such that each radvel (in a given range cell) is a 18 | % row, and so it should be possible to vertically concat these to create a 19 | % Radial struct for a single time. And then temporally concat them after 20 | % signal detection step. 21 | % 22 | % see doa_on_range_cell, and doa_on_cs.m 23 | % 24 | % EXAMPLE 25 | % MU = doa_struct(length(peakIdx)); 26 | % 27 | % Notes 28 | % dBear formerly used by compute_doa_errors.m, see 29 | % clean_up_and_recompute_errors.m, which calls 30 | % compute_doa_errors_wrt_roms.m 31 | % 32 | 33 | % CHANGE LOG 34 | % 14 Mar 2022 - Idx changed from struct with cells to struct with arrays 35 | 36 | if nargin < 2, n = 2; end 37 | 38 | if nargin < 3, m = n; end 39 | 40 | if nargin < 4, fn = {'MU','ML'}; end 41 | 42 | fn = upper(fn); 43 | 44 | % Expand for all possible emitters 45 | mx = (n*(n+1))/2; 46 | 47 | R = RADIALstruct(1); 48 | 49 | % Usually Ideal or Meas so putting the APM type here is appropriate 50 | R.Type = ''; 51 | 52 | % Clear these out 53 | [R.SiteName] = deal(''); 54 | 55 | % Add these for DOA processing 56 | [R.RadVel,R.Bear,R.SNR,R.dBear,R.Err, ... 57 | R.Params,R.Apprch,R.PkPwr,R.PkWdth] = deal(NaN(r,mx)); 58 | 59 | % Snr matrix 60 | R.SNR = NaN(r,3); 61 | 62 | % Guess at the size of these 63 | R.eigValues = NaN(r,m); 64 | 65 | % EigenVectors and Cov matrix as a cell array 66 | R.OtherMatrixVars.eigVectors{r,1} = []; 67 | R.OtherMatrixVars.cov{r,1} = []; 68 | 69 | % dont need these here 70 | R.OtherMatrixVars = rmfield(R.OtherMatrixVars,{'ERSC','ERTC','ESPC','MAXV','MINV','SPRC','VFLG'}); 71 | 72 | % Needed by CS processing 73 | R.RngIdx = ones(r,1); 74 | 75 | % Expand eventually for arbitrary arrays .. NaNs here to prevent errors 76 | R.Dual = NaN(r,1); 77 | 78 | % Track DOA compute time 79 | R.RunTime = 0; 80 | 81 | R(1).README.Bear = '(Struct) Estimated DOA for Method'; 82 | R(1).README.RadVel = 'Radial Velocity'; 83 | R(1).README.Params = 'MUSIC parameters'; 84 | R(1).README.SNR = 'From get_SNR.m'; 85 | R(1).README.Err = 'SN89 stddev (deg)'; 86 | R(1).README.RunTime = '(Struct) DOA Method Total Compute Time (s)'; 87 | R(1).README.LR = 'Likelihood Ratio (glrt.M)'; 88 | R(1).README.Pwr = 'Signal Power (signal_power.m)'; 89 | R(1).README.PkPwr = 'MUSIC DOA Peak Power (dB)'; 90 | R(1).README.PkWdth = 'MUSIC DOA Peak Width (deg)'; 91 | 92 | R.README.RmsBrgErr = 'RMS bearing error (Struct with fields for DOA algo)'; 93 | R.README.BrgDiff = 'Bearing Difference (ROMS vs DOA method) (Struct with fields for DOA algo)'; 94 | R.README.RomsBrg = 'Bearing for nearest ROMS current (cwN)'; % see roms_to_radvel.m and m_idist.m 95 | R.README.Rm = 'Model covariance from glrt.m'; 96 | R.README.Idx = 'struct of doa method detection APM indecies'; 97 | R.README.K = 'Estimated number of independent data snapshots'; 98 | 99 | R(1).RADIAL_struct_version = 'doa_struct'; 100 | 101 | 102 | % MAKE DOA METHOD SUBSTRUCTS 103 | 104 | % if x, 105 | % fn = {'MU','ML','WM','WF','SM'}; 106 | % else 107 | % fn = {'MU','ML'}; 108 | % end 109 | % 110 | 111 | % create containers size r x mx 112 | for i = 1:numel(fn) 113 | S.(fn{i}) = NaN(r,mx); 114 | end 115 | 116 | [R.Bear,R.dBear,R.RmsBrgErr,R.BrgDiff,R.RomsBrg,R.Pwr,R.Pwr2,R.Pwr3] = deal(S); 117 | 118 | 119 | % create runtime count 120 | for i = 1:numel(fn) 121 | S.(fn{i}) = 0; 122 | end 123 | 124 | [R.RunTime] = deal(S); 125 | 126 | 127 | % create detection containers 128 | for i = 1:numel(fn) 129 | S.(fn{i}) = NaN(r,n); 130 | end 131 | 132 | [R.LR] = deal(S); 133 | 134 | 135 | % storage for model cov from glrt 136 | for i = 1:numel(fn) 137 | S.(fn{i}) = cell(r,n); 138 | end 139 | 140 | % Idx has to be cell to prevent getting NaN indexes 141 | [R.Rm,R.Idx] = deal(S); 142 | 143 | 144 | % this is a single value for the whole CS file 145 | R.K = NaN; 146 | 147 | 148 | 149 | % OLDER - MAYBE USERFUL? 150 | 151 | % % add detection matricies 152 | % [S.MU,S.ML,S.WM,S.WF,S.SM] = deal(NaN(r,n)); 153 | % 154 | % [R.LR,R.GM,R.LR2] = deal(S); 155 | % 156 | % % storage for model cov from glrt 157 | % [R.Rm.MU,R.Rm.ML,R.Rm.WM,R.Rm.WF,R.Rm.SM] = deal(cell(r,n)); 158 | 159 | 160 | % 161 | % % Specify both DOA method and array type 162 | % S.MU.Type = [APM.Type ' MUSIC']; 163 | % S.ML.Type = [APM.Type ' MLE-AP']; 164 | % S.WM.Type = [APM.Type ' WMUSIC']; 165 | % S.WF.Type = [APM.Type ' WSF']; 166 | % S.SM.Type = [APM.Type ' SML']; 167 | 168 | 169 | end -------------------------------------------------------------------------------- /getNameValuePair.m: -------------------------------------------------------------------------------- 1 | function [ii,nn,vv] = getNameValuePair( name, names, values, varargin ) 2 | % GETNAMEVALUEPAIR From a cell array of names and values, picks out 3 | % that element that matches a given string. 4 | % 5 | % Note that this function is useful for picking out fields from CODAR's 6 | % RDL radial file header format. 7 | % 8 | % Usage: [Index,Name,Value] = getNameValuePair( name, names, values, ... ) 9 | % 10 | % Inputs 11 | % ------ 12 | % name = string to match on using strmatch 13 | % names = cell array of string names to match using the strmatch 14 | % function. 15 | % values = cell array of values to pick from. If absent or empty, will be 16 | % ignored. 17 | % ... = additional arguments to strmatch (perhaps 'exact') 18 | % 19 | % Outputs 20 | % ------- 21 | % Index = the indices that match the given string 22 | % Name = the names that match the given string 23 | % Value = values that match 24 | % 25 | % Note: There may be multiple matches. Also, the return of this will 26 | % always be a cell array even if there is just one match. 27 | % 28 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 29 | % 30 | % $Id: getNameValuePair.m 425 2007-05-18 18:05:04Z dmk $ 31 | % 32 | % Copyright (C) 2007 David M. Kaplan 33 | % Licence: GPL (Gnu Public License) 34 | % 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | 37 | ii = strmatch( name, names, varargin{:} ); 38 | 39 | if isempty( ii ) 40 | warning( [ mfilename ':NO_MATCHES' ], 'No matches found for ''%s''', name ); 41 | end 42 | 43 | if numel( ii ) > 1 44 | warning( [ mfilename ':MULT_MATCHES' ], 'Multiple matches found.' ); 45 | end 46 | 47 | nn = names(ii); 48 | 49 | if ~exist( 'values', 'var' ) || ( isempty(values) && ~isempty(names) ) 50 | return 51 | end 52 | 53 | vv = values(ii); 54 | -------------------------------------------------------------------------------- /get_array_matrix.m: -------------------------------------------------------------------------------- 1 | function A = get_array_matrix(APM) 2 | % GET ARRAY MATRIX - Array matrix from SeaSondes APM struct 3 | % A = get_array_matrix(APM) 4 | % 5 | % A is the Array Manifold Matrix (c.f. Van Trees 2002, pg 31), aka the 6 | % collection of vectors that incorporate all of the spatial characteristics 7 | % of the array. 8 | % 9 | % DATA FORMAT DEFINITION 10 | % - The array matrix A is #elements x #bearings (THIS IS OUTPUT) 11 | % - Similar data in the APM struct is the reverse, #bearings x #elements 12 | % (historical reasons) 13 | 14 | % Copyright (C) 2016 Brian Emery 15 | 16 | 17 | % 18 | % if isfield(APM,'A') && ~isempty(APM.A) 19 | % A = APM.A.'; 20 | % 21 | % else 22 | 23 | % Get the array matrix from the APM struct 24 | A(1,:) = APM.A13R + 1i*APM.A13I; 25 | A(2,:) = APM.A23R + 1i*APM.A23I; 26 | A(3,:) = APM.A33R + 1i*APM.A33I; 27 | 28 | % end 29 | end -------------------------------------------------------------------------------- /get_radial_meta.m: -------------------------------------------------------------------------------- 1 | function R = get_radial_meta(R,APM,ftime,rkm) 2 | % GET RADIAL META - meta data and hfrp struct formatting 3 | % 4 | % Gets meta data and formats radial struct per HFRP formatting. 5 | % 6 | % Called by run_cs_processing*, but this is also used by Radar Simulation 7 | % code on not-real data (eg check_plot_dales_stuff.m). 8 | % 9 | % Typically these run together: 10 | % - get_radial_meta.m 11 | % - apply_detection.m 12 | % - doa_to_radial_struct.m or maybe detection_codar_post_proc.m 13 | 14 | 15 | % Copyright (C) 2019 Brian Emery 16 | 17 | % 20220407 Adding code to handle empty struct input for R, which happens 18 | 19 | % CONVERT DOA STRUCT TO HFRP RADIAL STRUCT 20 | 21 | % special case 22 | if nargin < 4, rkm =[]; end 23 | 24 | R(1).Type = APM.Type(1:end); 25 | 26 | R.SiteName = APM.SiteName; 27 | 28 | R.SiteOrigin = APM.SiteOrigin; 29 | 30 | R.SiteCode = 1; 31 | 32 | % R.FileName = fileparts_name(fname); 33 | 34 | R.TimeStamp = ftime; % fnames_to_times(fname,['CSS_' R.SiteName '_'],'yy_mm_dd_HHMM'); 35 | 36 | R.FileName = ['RDLm_' R.SiteName '_' datestr(R.TimeStamp,'yyyy_mm_dd_HHMM') '.mat']; 37 | 38 | R.RangeBearHead = []; 39 | 40 | 41 | if ~isempty(R.Bear) 42 | 43 | if ~isempty(rkm) 44 | % Generate Range 45 | R.RangeBearHead(:,1) = R.RngIdx(:,1) * rkm; 46 | else 47 | try R.RangeBearHead(:,1) = R.Range; catch, end 48 | end 49 | 50 | % CUSTOM FOR GLRT TESTING 51 | fn = fieldnames(R.Bear); 52 | for i = 1:numel(fn) 53 | R.Bear.(fn{i}) = cwN2ccwE(R.Bear.(fn{i})); % <--- NOTE THIS IS NOT RANGEBEARHEAD! 54 | % if isfield(R.Bear,'ML') 55 | % R.Bear.ML = cwN2ccwE(R.Bear.ML); 56 | end 57 | 58 | 59 | % Idempodent fix I hope 60 | R.LonLatUnits = {'Decimal Degrees','Decimal Degrees'}; 61 | R.RangeBearHeadUnits = {'km','Degrees_ccw_from_east','Degrees_ccw_from_east'}; 62 | 63 | end 64 | 65 | 66 | 67 | % % final cleanup - stuff not used on real data 68 | % % .. FUTURE maybe remove these if empty? 69 | % R = rmfield(R,{'RmsBrgErr','BrgDiff','RomsBrg'}); 70 | 71 | % need this 72 | R.ProcessingSteps{1,end+1} = 'get_radial_meta'; 73 | 74 | 75 | 76 | end 77 | 78 | -------------------------------------------------------------------------------- /hamming.m: -------------------------------------------------------------------------------- 1 | function d = hamming(n) 2 | % HAMMING.M - returns the N-point Hamming window. 3 | % d = hamming(n) 4 | % 5 | % Input : n = number 6 | % 7 | % Output : w = vector 8 | % 9 | % Usage : w = hamming (n) 10 | % 11 | % Comments : allows also the call: hamming(xx), taking only format from signal xx 12 | % 13 | % See also : HAMMING2 14 | 15 | % modification of original MATLAB (3.5) file 16 | % HGFei, 1990 17 | 18 | n = n(:); 19 | % [hig, wid] = size(n); 20 | % 21 | % if wid > 1; n = wid; end; 22 | 23 | d = (.54 - .46*cos(2*pi*(0:n-1)'/(n-1))).'; 24 | 25 | % if hig > 1; 26 | % ww = w; 27 | % for jj = 2 : hig; 28 | % w(jj,:) = ww; 29 | % end; 30 | % end; 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /install_hfr_cs_proc.m: -------------------------------------------------------------------------------- 1 | % HFR CS PROCESSING - installation script 2 | % 3 | % INSTRUCTIONS 4 | % - download and unzip the toolbox (eg via the clone or download button) 5 | % - cd into the directory, eg: 6 | % cd ~/Downloads/hfr_cs_processing-master/ 7 | % - run this script: 8 | % >> install_hfr_cs_proc 9 | % 10 | 11 | % June 2020 Brian Emery 12 | 13 | % get the directory locating this file 14 | wd = fileparts( mfilename('fullpath') ); 15 | 16 | % list the directories 17 | flist = dir(fullfile(wd, ['**' filesep '*.*'])); 18 | 19 | % get just the directories 20 | flist = flist([flist.isdir]); 21 | 22 | % ... in a cell array 23 | flist = unique({flist.folder}'); 24 | 25 | % scrub out .git and private 26 | flist = flist(cellfun('isempty',regexp(flist,'.git'))); 27 | flist = flist(cellfun('isempty',regexp(flist,'private'))); 28 | 29 | % add these to the path 30 | disp('Modifying MATLAB Path ...') 31 | 32 | addpath(wd) 33 | 34 | for i = 1:numel(flist) 35 | addpath(flist{i}) 36 | end 37 | 38 | clear -------------------------------------------------------------------------------- /make_cov.m: -------------------------------------------------------------------------------- 1 | function C = make_cov(CS,fbin,rdx) 2 | % MAKE COV - make covariance matrix from CS data 3 | % C = make_cov(CS,fbin,rdx) 4 | % 5 | % From doa_on_range_cell.m for example 6 | % 7 | % Expects CS to contain matricies of complex voltages oriented 8 | % as length fft x length range cells 9 | 10 | % Copyright (C) 2016 Brian Emery 11 | 12 | % check for test case 13 | if strcmp('--t',CS), test_case, return, end 14 | 15 | 16 | if nargin < 3 17 | rdx = 1; 18 | 19 | end 20 | 21 | if isfield(CS,'antenna1Self') 22 | % old way 23 | 24 | % fbin = find(CS.Vrad > Vr -2 & CS.Vrad < Vr +2); 25 | % 26 | % H = cs_plot(CS,1); hold on 27 | % LS = line_style_groups; 28 | % h = cs_plot(CS,1,LS(1),H,fbin); 29 | % 30 | % keyboard 31 | 32 | % fbin = 399; % Need to fix the off by one aspect of the velocity 33 | 34 | % build covariance matrix - These are the averaged complex voltages 35 | % < ViVj* > with units volts^2 36 | C(1,1) = CS.antenna1Self(fbin,rdx); 37 | C(1,2) = CS.antenna12CrossSp(fbin,rdx); 38 | C(1,3) = CS.antenna13CrossSp(fbin,rdx); 39 | 40 | C(2,1) = conj(CS.antenna12CrossSp(fbin,rdx)); 41 | C(2,2) = CS.antenna2Self(fbin,rdx); 42 | C(2,3) = CS.antenna23CrossSp(fbin,rdx); 43 | 44 | C(3,1) = conj(CS.antenna13CrossSp(fbin,rdx)); 45 | C(3,2) = conj(CS.antenna23CrossSp(fbin,rdx)); 46 | C(3,3) = CS.antenna3Self(fbin,rdx); 47 | 48 | 49 | else 50 | 51 | 52 | % get field names 53 | fo = cs_fieldnames(CS); 54 | 55 | % detect number of antennas 56 | % solve n(n+1) = 2*length(fn) with quadratic eqn 57 | m = (-1 + sqrt(1 + 8*length(fo)))/2; 58 | 59 | % make the row,col indecies 60 | [fn,I,J] = cs_make_field_names(m); 61 | 62 | % might as well check on this 63 | if ~all(ismember(fn,fo)), disp('CS field name discrepancy'), keyboard, end 64 | 65 | 66 | % preallocate 67 | C = NaN(m); 68 | 69 | for i = 1:numel(fn) 70 | 71 | % get row and column index from the field name 72 | r = I(i); 73 | c = J(i); 74 | 75 | % CS contains the upper triangle, lower gets conj'd 76 | C(r,c) = CS.(fn{i})(fbin,rdx); 77 | 78 | if r~=c, 79 | % now fill in the lower triangle and conjugate 80 | C(c,r) = conj(CS.(fn{i})(fbin,rdx)); 81 | end 82 | end 83 | end 84 | 85 | 86 | 87 | 88 | end 89 | 90 | function test_case 91 | % TEST CASE 92 | % 93 | % Test new method vs old method functionality 94 | % 95 | % data for this created with radar_simulation.m test 96 | % 97 | 98 | % declare! (for R2014b 'bug') 99 | fftn = []; 100 | 101 | % load data 102 | load /m_files/test_data/cs_from_fft.mat 103 | 104 | % make the cs 105 | CS = cs_from_fft(fftn,CFG); 106 | 107 | % make a copy with new field names 108 | fn = cs_fieldnames(CS); 109 | 110 | fnn = {'a11','a22','a33','a12','a13','a23'}; 111 | 112 | CSn = cs_struct(1,3); 113 | 114 | for i = 1:numel(fn) 115 | % it's essential that fnn and fn refer to right fields! 116 | CSn.(fnn{i}) = CS.(fn{i}); 117 | end 118 | 119 | % choose bin 158 which is in the peak 120 | fbin = 158; 121 | 122 | C1 = make_cov(CS,fbin,1); 123 | 124 | C2 = make_cov(CSn,fbin,1); 125 | 126 | if isequal(C1,C2) 127 | disp(' ...passed') 128 | else 129 | disp(' ... NOT passed') 130 | keyboard 131 | end 132 | 133 | 134 | end -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/general/getNameValuePair.m: -------------------------------------------------------------------------------- 1 | function [ii,nn,vv] = getNameValuePair( name, names, values, varargin ) 2 | % GETNAMEVALUEPAIR From a cell array of names and values, picks out 3 | % that element that matches a given string. 4 | % 5 | % Note that this function is useful for picking out fields from CODAR's 6 | % RDL radial file header format. 7 | % 8 | % Usage: [Index,Name,Value] = getNameValuePair( name, names, values, ... ) 9 | % 10 | % Inputs 11 | % ------ 12 | % name = string to match on using strmatch 13 | % names = cell array of string names to match using the strmatch 14 | % function. 15 | % values = cell array of values to pick from. If absent or empty, will be 16 | % ignored. 17 | % ... = additional arguments to strmatch (perhaps 'exact') 18 | % 19 | % Outputs 20 | % ------- 21 | % Index = the indices that match the given string 22 | % Name = the names that match the given string 23 | % Value = values that match 24 | % 25 | % Note: There may be multiple matches. Also, the return of this will 26 | % always be a cell array even if there is just one match. 27 | % 28 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 29 | % 30 | % $Id: getNameValuePair.m 425 2007-05-18 18:05:04Z dmk $ 31 | % 32 | % Copyright (C) 2007 David M. Kaplan 33 | % Licence: GPL (Gnu Public License) 34 | % 35 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 36 | 37 | ii = strmatch( name, names, varargin{:} ); 38 | 39 | if isempty( ii ) 40 | warning( [ mfilename ':NO_MATCHES' ], 'No matches found for ''%s''', name ); 41 | end 42 | 43 | if numel( ii ) > 1 44 | warning( [ mfilename ':MULT_MATCHES' ], 'Multiple matches found.' ); 45 | end 46 | 47 | nn = names(ii); 48 | 49 | if ~exist( 'values', 'var' ) || ( isempty(values) && ~isempty(names) ) 50 | return 51 | end 52 | 53 | vv = values(ii); 54 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/general/true2math.m: -------------------------------------------------------------------------------- 1 | function mathDir = true2math(trueDir) 2 | %TRUE2MATH Converts angle in degrees from the true system to math system. 3 | % 4 | % MATHDIR = TRUE2MATH(TRUEDIR) converts angle in degrees from the true 5 | % convention to the math convention. 6 | % I call the math convention, for lack of a better term, the direction of a 7 | % vector angle measured in degrees ccw from east, where east = 0 degrees, 8 | % north = 90 degrees, etc. 9 | % true convention is the direction of a vector angle measured in degrees 10 | % cw from north, where north = 0 degrees, east = 90 degrees, etc. This is 11 | % also commonly referred to as compass angle. 12 | % 13 | % NOTE: It is assumed that the angles are in degrees 0 < angle < 360. 14 | % 15 | % See also MATH2TRUE, SPDDIR2UV, UV2SPDIR, MET2OC. 16 | % 17 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 18 | % Copyright (C) 2007 Mike Cook, Naval Postgraduate School 19 | % License: GPL (Gnu Public License) 20 | % 21 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | % Mike Cook - NPS Oceanography Dept., OCT 96 24 | % v 1.1 - replaced find code with mod code - apr 99. 25 | 26 | mathDir = 90 - trueDir; 27 | mathDir = mod(mathDir,360); 28 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_contour.m: -------------------------------------------------------------------------------- 1 | function [cs,h]=m_contour(long,lat,data,varargin); 2 | % M_CONTOUR Draws contour lines on a map 3 | % M_CONTOUR(LONG,LAT,DATA,...) draw contours on a map. Behavior 4 | % is the same as for CONTOUR except that LONG and LAT vectors or 5 | % matrices must be specified. 6 | % 7 | % [CS,H]=M_CONTOUR(...) returns a contour matrix C and a vector 8 | % H of handles to LINE or PATCH objects for use by CLABEL. 9 | % 10 | % See also CONTOUR 11 | 12 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 17/Jan/1998 13 | % 14 | % This software is provided "as is" without warranty of any kind. But 15 | % it's mine, so you can't sell it. 16 | 17 | % 9/Dec/98 - made sure bad things don't happen if all your lat/long 18 | % points are out of the plot region. 19 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 20 | 21 | global MAP_PROJECTION 22 | 23 | % Have to have initialized a map first 24 | 25 | if isempty(MAP_PROJECTION), 26 | disp('No Map Projection initialized - call M_PROJ first!'); 27 | return; 28 | end; 29 | 30 | if min(size(long))==1 & min(size(lat))==1, 31 | [long,lat]=meshgrid(long,lat); 32 | end; 33 | 34 | [X,Y]=m_ll2xy(long,lat,'clip','on'); 35 | 36 | i=isnan(X); % For these we set the *data* to NaN... 37 | data(i)=NaN; 38 | 39 | % And then recompute positions without clipping. THis 40 | % is necessary otherwise contouring fails (X/Y with NaN 41 | % is a no-no. 42 | if any(i(:)), [X,Y]=m_ll2xy(long,lat,'clip','off'); end; 43 | 44 | if any(~i(:)), 45 | [cs,h]=contour(X,Y,data,varargin{:}); 46 | set(h,'tag','m_contour'); 47 | else 48 | cs=[];h=[]; 49 | end; 50 | 51 | if nargout==0, 52 | clear cs h 53 | end; 54 | 55 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_contourf.m: -------------------------------------------------------------------------------- 1 | function [cs,h]=m_contourf(long,lat,data,varargin); 2 | % M_CONTOURF Adds filled contours to a map 3 | % M_CONTOURF(LONG,LAT,DATA,...) is the same as M_CONTOUR except 4 | % that contours are filled. Areas of data above a given level are 5 | % filled, areas below are left blank or are filled by a lower level. 6 | % NaN's in the data leave holes in the filled plot/ 7 | % 8 | % [CS,H] = M_CONTOURF(...) returns contour matrix C as described in 9 | % CONTOURC and a vector H of handles to PATCH objects (for use by 10 | % CLABEL). 11 | % 12 | % See also M_CONTOUR, CONTOURF 13 | 14 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 17/Jan/1998 15 | % 16 | % This software is provided "as is" without warranty of any kind. But 17 | % it's mine, so you can't sell it. 18 | 19 | % 19/02/98 - type - should have been 'clip','patch', rather than 'off'. 20 | % 9/12/98 - handle all-NaN plots without letting contour crash. 21 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 22 | % Apr/06 - workaround for v7 bug in contourf. 23 | 24 | 25 | global MAP_PROJECTION 26 | 27 | % Have to have initialized a map first 28 | 29 | if isempty(MAP_PROJECTION), 30 | disp('No Map Projection initialized - call M_PROJ first!'); 31 | return; 32 | end; 33 | 34 | if min(size(long))==1 & min(size(lat))==1, 35 | [long,lat]=meshgrid(long,lat); 36 | end; 37 | 38 | [X,Y]=m_ll2xy(long,lat,'clip','on'); %First find the points outside 39 | 40 | i=isnan(X); % For these we set the *data* to NaN... 41 | data(i)=NaN; 42 | 43 | % And then recompute positions without clipping. THis 44 | % is necessary otherwise contouring fails (X/Y with NaN 45 | % is a no-no. Note that this only clips properly down 46 | % columns of long/lat - not across rows. In general this 47 | % means patches may nto line up properly a right/left edges. 48 | if any(i(:)), [X,Y]=m_ll2xy(long,lat,'clip','patch'); end; 49 | 50 | if any(~i(:)), 51 | 52 | % Bug in contourf call - Solution Number: 1-1W36E8 53 | if any(strfind(version,'(R14) Service Pack 3')) | ... 54 | any(strfind(version,'7.2.0.294 (R2006a)')) | .... 55 | any(strfind(version,'7.2.0.232 (R2006a)')), 56 | [cs,h]=contourf('v6',X,Y,data,varargin{:}); 57 | else 58 | [cs,h]=contourf(X,Y,data,varargin{:}); 59 | end; 60 | 61 | set(h,'tag','m_contourf'); 62 | else 63 | cs=[];h=[]; 64 | end; 65 | 66 | if nargout==0, 67 | clear cs h 68 | end; 69 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_coord.m: -------------------------------------------------------------------------------- 1 | function coordsys=m_coord(coordsys); 2 | % M_COORD Initializes the coordinate system for varous conversions. 3 | % 4 | % M_COORD('set') tells you the current coordinate system 5 | % M_COORD('get') gives you the current possibilities 6 | % M_COORD(SYSTEM) sets the coordinate system to SYSTEM. 7 | % 8 | % Currently the available coordinate systems are: 9 | % 'geographic' (usual lat/long) 10 | % 'geomagnetic' (referenced to magnetic poles) 11 | 12 | % Rich Pawlowicz (rich@ocgy.ubc.ca) nOV/2001 13 | % 14 | % This software is provided "as is" without warranty of any kind. But 15 | % it's mine, so you can't sell it. 16 | 17 | 18 | global MAP_COORDS 19 | 20 | if nargin==0, coordsys='usage'; end; 21 | 22 | coordsys=lower(coordsys); 23 | 24 | coords=mc_coords('name'); 25 | 26 | switch coordsys, 27 | 28 | case 'get', 29 | disp(' '); 30 | disp('Available coordinate systems are:'); 31 | for k=1:length(coords.name), 32 | disp([' ' coords.name{k}]); 33 | end; 34 | 35 | case 'set', 36 | if isempty(MAP_COORDS), 37 | disp('No coordinate system initialized'); 38 | m_coord('usage'); 39 | else 40 | if nargout==0, 41 | disp(MAP_COORDS.name); 42 | else 43 | coordsys=MAP_COORDS; 44 | end; 45 | end; 46 | 47 | case 'usage', 48 | disp(' '); 49 | disp('Possible calling options are:'); 50 | disp(' ''usage'' - this list'); 51 | disp(' ''set'' - list of coordinate systems'); 52 | disp(' ''get'' - get current coordinate (if defined)'); 53 | disp(' ''system'' - initialize coordinate system\n'); 54 | 55 | otherwise 56 | k=strmatch(coordsys,lower(coords.name)); 57 | MAP_COORDS=mc_coords('parameters',coords.name{k}); 58 | 59 | end; 60 | % Check to see if a non-lat/long coordinate system is being used. 61 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_elev.m: -------------------------------------------------------------------------------- 1 | function [values,longs,lats]=m_elev(varargin) 2 | % M_ELEV Contour elevation onto a map using a 1-degree database 3 | % M_ELEV contours elevations at 1000m intervals for the map. 4 | % M_ELEV(OPTN (,LEVELS) (,ARGS,...) ) lets you change various options. 5 | % if OPTN=='contour', contour lines are drawn. for OPTN=='contourf', 6 | % filled contours are drawn. LEVELS are the levels used, and ARGS 7 | % are optional patch arguments of line types, colors, etc. 8 | % 9 | % [CS,H]=M_ELEV(...) allows access to the return arguments of the 10 | % contour/contourf call. 11 | % 12 | % [ELEV,LONG,LAT]=M_ELEV([LONG_MIN LONG_MAX LAT_MIN LAT_MAX]) 13 | % extracts elevation data for the given lat/long limits (without plotting). 14 | % 15 | % See also M_PROJ, M_GRID, M_COAST 16 | 17 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 18 | % 19 | % This software is provided "as is" without warranty of any kind. But 20 | % it's mine, so you can't sell it. 21 | % 22 | % 20/5/97 - moved registration over by 1/2 degree (seems to fit better) 23 | % 2/10/97 - a minor bug in the edge-handling for filled contours! 24 | % 8/ 1/98 - better handling for options. 25 | % 23/1/98 - redid everything to allow for raw bathymetry output option. 26 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 27 | 28 | global MAP_PROJECTION MAP_VAR_LIST 29 | 30 | % Have to have initialized a map first 31 | 32 | draw_map=1; 33 | if nargin==1 & ~isstr(varargin{1}) & length(varargin{1})==4 34 | draw_map=0; 35 | end 36 | 37 | 38 | if draw_map==1 & isempty(MAP_PROJECTION) 39 | disp('No Map Projection initialized - call M_PROJ first!'); 40 | return; 41 | end 42 | 43 | % Set current projection to geographic 44 | Currentmap=m_coord('set'); 45 | m_coord('geographic'); 46 | 47 | if draw_map 48 | 49 | blat=max(floor(MAP_VAR_LIST.lats(1)+.5),-89)-.5; 50 | tlat=min(ceil(MAP_VAR_LIST.lats(2)+.5),90)-.5; 51 | llong=floor(MAP_VAR_LIST.longs(1)+.5)-.5; 52 | rlong=ceil(MAP_VAR_LIST.longs(2)+.5)-.5; 53 | 54 | else 55 | 56 | blat=max(floor(varargin{1}(3)+.5),-89)-.5; 57 | tlat=min(ceil(varargin{1}(4)+.5),90)-.5; 58 | llong=floor(varargin{1}(1)+.5)-.5; 59 | rlong=ceil(varargin{1}(2)+.5)-.5; 60 | 61 | end 62 | 63 | load topo 64 | 65 | 66 | 67 | if rlong>360, rlong=rlong-360; llong=llong-360; end 68 | if llong<-360, rlong=rlong+360; llong=llong+360; end 69 | 70 | lts=(blat:tlat); 71 | lgs=(llong:rlong); 72 | 73 | if rlong<0, 74 | topo=topo(lts+90.5,lgs+360.5); 75 | elseif llong<0 & rlong>=0 76 | topo=topo(lts+90.5,[(360.5+llong:end) (1:rlong+0.5)]); 77 | else 78 | topo=topo(lts+90.5,lgs+.5); 79 | end 80 | 81 | 82 | if draw_map, 83 | 84 | if nargin==0, 85 | levels=[-7000:1000:-1000 1000:1000:5000]; 86 | optn='contour'; 87 | n_opt=1; 88 | else 89 | if isstr(varargin{1}), 90 | optn=varargin{1}; 91 | end; 92 | if nargin==1, 93 | levels=[-7000:1000:-1000 1000:1000:5000]; 94 | n_opt=2; 95 | else 96 | if isstr(varargin{2}), 97 | levels=[-7000:1000:-1000 1000:1000:5000]; 98 | n_opt=2; 99 | else 100 | levels=varargin{2}; 101 | n_opt=3; 102 | end; 103 | end; 104 | end; 105 | 106 | [lg,lt]=meshgrid(lgs,lts); 107 | [X,Y]=m_ll2xy(lg,lt,'clip','on'); 108 | 109 | 110 | hold on; 111 | switch optn, 112 | case 'contour', 113 | [values,longs]=m_contour(lg,lt,topo,levels); 114 | case 'contourf', 115 | [values,longs]=m_contourf(lg,lt,topo,levels); 116 | case 'pcolor', 117 | [longs]=m_pcolor(lg,lt,topo); 118 | end; 119 | 120 | set(longs,'tag','m_elev'); 121 | if n_opt1 & strcmp(varargin{1},'save'), 32 | [ncst,Area,k]=mu_coast('f',FILNAME); 33 | eval(['save ' varargin{2} ' ncst k Area']); 34 | else 35 | mu_coast('f',FILNAME,varargin{:},'tag','m_gshhs_f'); 36 | end; 37 | 38 | m_coord(Currentmap.name); 39 | 40 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_gshhs_h.m: -------------------------------------------------------------------------------- 1 | function m_gshhs_h(varargin); 2 | % M_GSHHS_H Add a coastline to a given map using the 'high' resolution of 3 | % the Global Self-consistant Hierarchical High-resolution 4 | % Shorelines. 5 | % 6 | % M_GSHHS_H( (standard line option,...,...) ) draws the coastline 7 | % as a simple line. 8 | % M_GSHHS_H('patch' ( ,standard patch options,...,...) ) draws the 9 | % coastline as a number of patches. 10 | % 11 | % M_GSHHS_H('save',FILENAME) saves the extracted coastline data 12 | % for the current projection in a file FILENAME. This allows 13 | % speedier replotting using M_USERCOAST(FILENAME). 14 | % 15 | % See also M_PROJ, M_GRID, M_COAST, M_GSHHS_L, M_GSHHS_I, M_GSHHS_C 16 | % M_USERCOAST 17 | 18 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 15/June/98 19 | % 20 | % 21 | % This software is provided "as is" without warranty of any kind. But 22 | % it's mine, so you can't sell it. 23 | 24 | 25 | FILNAME='private/gshhs_h.b'; 26 | 27 | % Set current projection to geographic 28 | Currentmap=m_coord('set'); 29 | m_coord('geographic'); 30 | 31 | if length(varargin)>1 & strcmp(varargin{1},'save'), 32 | [ncst,Area,k]=mu_coast('h',FILNAME); 33 | eval(['save ' varargin{2} ' ncst k Area']); 34 | else 35 | mu_coast('h',FILNAME,varargin{:},'tag','m_gshhs_h'); 36 | end; 37 | 38 | m_coord(Currentmap.name); 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_ll2xy.m: -------------------------------------------------------------------------------- 1 | function [X,Y,I]=m_ll2xy(varargin); 2 | % M_LL2XY Converts long,lat to X,Y coordinates using the current projection 3 | % [X,Y]=m_ll2xy(LONGITUDE,LATITUDE); 4 | % 5 | % Extra properties can be added after the latitude variable: 6 | % ...,'clip', ( 'on' | 'off' | 'patch' | 'point' ) 7 | % where normal clipping sets out-of-range values to NaN, and patch 8 | % clipping sets out-of-range values to border values (useful for 9 | % drawing patches). A border point is interpolated for line 10 | % segments crossing the border; line segments are assumed for 11 | % one-dimensional input arrays and for the columns of 2-dimensional 12 | % arrays. The interpolation can be disabled using the 'point' 13 | % option (i.e. data is composed of discrete unrelated points). 14 | % 15 | % [X,Y,I]=m_ll2xy(...) returns an index to tell you which 16 | % points have been modified (I=1). 17 | 18 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 19 | % 20 | % This software is provided "as is" without warranty of any kind. But 21 | % it's mine, so you can't sell it. 22 | 23 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 24 | 25 | global MAP_PROJECTION MAP_COORDS 26 | 27 | 28 | if nargin==0 | isstr(varargin{1}), 29 | disp(' Usage'); 30 | disp(' [X,Y]=m_ll2xy(LONGITUDES,LATITUDES <,''clip'',( ''on''|''off''|''patch'' | ''point'' ) >)'); 31 | else 32 | if strcmp(MAP_COORDS.name,MAP_PROJECTION.coordsystem.name), 33 | % Sneaky way of making default clipping on (sneaky 'cause only the 4th 34 | % input parameter is checked for the clipping property) 35 | [X,Y,I]=feval(MAP_PROJECTION.routine,'ll2xy',varargin{:},'clip','on'); 36 | elseif strcmp(MAP_COORDS.name,'geographic'), 37 | [LONG,LAT]=mc_coords('geo2mag',varargin{1:2}); 38 | args={varargin{3:end},'clip','on'}; 39 | [X,Y,I]=feval(MAP_PROJECTION.routine,'ll2xy',LONG,LAT,args{:}); 40 | elseif strcmp(MAP_COORDS.name,'IGRF2000-geomagnetic'), 41 | [LONG,LAT]=mc_coords('mag2geo',varargin{1:2}); 42 | args={varargin{3:end},'clip','on'}; 43 | [X,Y,I]=feval(MAP_PROJECTION.routine,'ll2xy',LONG,LAT,args{:}); 44 | else 45 | error('m_ll2xy: Unrecognized coordinate system'); 46 | end; 47 | end; 48 | 49 | if nargout==0, 50 | clear X Y I 51 | end; 52 | 53 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_pcolor.m: -------------------------------------------------------------------------------- 1 | function [h]=m_pcolor(long,lat,data,varargin); 2 | % M_PCOLOR Makes a pcolor image on a map. 3 | % M_PCOLOR(LONG,LAT,DATA,...) is a pseudocolor plot of matrix DATA. 4 | % The values of the elements of DATA specify the color in each 5 | % cell of the plot. In the default shading mode, 'faceted', 6 | % each cell has a constant color and the last row and column of 7 | % DATA are not used. With shading('interp'), each cell has color 8 | % resulting from bilinear interpolation of the color at its 9 | % four vertices and all elements of DATA are used. 10 | % The smallest and largest elements of DATA are assigned the first and 11 | % last colors given in the color table; colors for the remainder of the 12 | % elements in DATA are determined by table-lookup within the remainder of 13 | % the color table. 14 | % 15 | % See also M_CONTOUR, CONTOURF, PCOLOR 16 | 17 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 17/Jan/1998 18 | % 19 | % This software is provided "as is" without warranty of any kind. But 20 | % it's mine, so you can't sell it. 21 | 22 | % 19/02/98 - type - should have been 'clip','patch', rather than 'off'. 23 | % 9/12/98 - handle all-NaN plots without letting contour crash. 24 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 25 | 26 | 27 | global MAP_PROJECTION 28 | 29 | % Have to have initialized a map first 30 | 31 | if isempty(MAP_PROJECTION), 32 | disp('No Map Projection initialized - call M_PROJ first!'); 33 | return; 34 | end; 35 | 36 | if min(size(long))==1 & min(size(lat))==1, 37 | [long,lat]=meshgrid(long,lat); 38 | end; 39 | 40 | [X,Y]=m_ll2xy(long,lat,'clip','on'); %First find the points outside 41 | 42 | i=isnan(X); % For these we set the *data* to NaN... 43 | data(i)=NaN; 44 | 45 | % And then recompute positions without clipping. THis 46 | % is necessary otherwise contouring fails (X/Y with NaN 47 | % is a no-no. Note that this only clips properly down 48 | % columns of long/lat - not across rows. In general this 49 | % means patches may nto line up properly a right/left edges. 50 | if any(i(:)), [X,Y]=m_ll2xy(long,lat,'clip','patch'); end; 51 | 52 | if any(~i(:)), 53 | [h]=pcolor(X,Y,data,varargin{:}); 54 | set(h,'tag','m_pcolor'); 55 | else 56 | h=[]; 57 | end; 58 | 59 | if nargout==0, 60 | clear h 61 | end; 62 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/m_xy2ll.m: -------------------------------------------------------------------------------- 1 | function [long,lat]=m_xy2ll(X,Y); 2 | % M_XY2LL Converts X,Y to long,lat coordinates using the current projection 3 | % [LONGITUDE,LATITUDE]=m_ll2xy(X,Y) 4 | % This is useful for finding locations using ginput. 5 | 6 | % Rich Pawlowicz (rich@ocgy.ubc.ca) 2/Apr/1997 7 | % 8 | % This software is provided "as is" without warranty of any kind. But 9 | % it's mine, so you can't sell it. 10 | 11 | % 6/Nov/00 - eliminate returned stuff if ';' neglected (thx to D Byrne) 12 | 13 | global MAP_PROJECTION MAP_COORDS 14 | 15 | if nargin==0 | isstr(X), 16 | disp(' Usage:'); 17 | disp(' [LONGITUDE,LATITUDE]=m_xy2ll(X,Y);'); 18 | else 19 | [long,lat]=feval(MAP_PROJECTION.routine,'xy2ll',X,Y); 20 | if ~strcmp(MAP_COORDS.name,MAP_PROJECTION.coordsystem.name), 21 | if strcmp(MAP_COORDS.name,'geographic'), 22 | [long,lat]=mc_coords('mag2geo',long,lat); 23 | else 24 | [long,lat]=mc_coords('geo2mag',long,lat); 25 | end; 26 | end; 27 | end; 28 | 29 | if nargout==0, 30 | clear long lat 31 | end; 32 | 33 | 34 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/m_map/private/mc_coords.m: -------------------------------------------------------------------------------- 1 | function [longOUT,latOUT,phiVecOUT,thetaVecOUT]=mc_coords(optn,longIN,latIN,phiVecIN,thetaVecIN) 2 | % MP_COORD Converts between coordinate systems based on different 3 | % poles. Generally used in space physics to plot things in 4 | % geomagnetic (dipole) coordinate systems. 5 | % 6 | % This function should not be used directly; instead it is 7 | % is accessed by various high-level functions named M_*. 8 | % 9 | % Vector rotations can be carried out using the following: 10 | % 11 | % [latOUT,longOUT,phiVecOUT,thetaVecOUT]=M_GEO2MAG(latIN,longIN,phiVecIN,thetaVecIN) 12 | % 13 | % where 14 | % 15 | % thetaVecIN - north component of the vector in geographic coordinates 16 | % phiVecIN - east component of the vector in geographic coordinates 17 | % thetaVecOUT - north component of the vector in geomagnetic coordinates 18 | % phiVecOUT - east component of the vector in geomagnetic coordinates 19 | % 20 | 21 | % References: 22 | % 23 | % Hapgood, M.A., Space Physics Coordinate Transformations: 24 | % A User Guide, Planet. Space Sci., Vol. 40, N0. 5, 1992. 25 | 26 | % Antti Pulkkinen, September 2001. 27 | % R. Pawlowicz 9/01 - Vectorized, changed functionality, put into standard M_MAP form. 28 | % 29 | % 29/Sep/2005 - fixed bug (apparently no-one ever used this option before now!) 30 | 31 | 32 | global MAP_PROJECTION MAP_COORDS 33 | 34 | pi180=pi/180; 35 | 36 | 37 | switch optn, 38 | case 'name' 39 | 40 | longOUT.name={'geographic','IGRF2000-geomagnetic'}; 41 | return; 42 | 43 | case 'parameters', 44 | switch longIN, 45 | case 'geographic', 46 | longOUT.name='geographic'; 47 | longOUT.lambda = 0; 48 | longOUT.phi = 0; 49 | 50 | case 'IGRF2000-geomagnetic', 51 | g10=-29615; 52 | g11=-1728; 53 | h11=5186; 54 | longOUT.name='IGRF2000-geomagnetic'; 55 | longOUT.lambda= atan(h11/g11); 56 | longOUT.phi = atan((g11*cos(longOUT.lambda)+h11*sin(longOUT.lambda))/g10); 57 | 58 | otherwise 59 | error('Unrecognized coordinate system'); 60 | end; 61 | return; 62 | case 'geo2mag', 63 | 64 | % Rotation matrices 65 | lambda=MAP_PROJECTION.coordsystem.lambda; 66 | phi=MAP_PROJECTION.coordsystem.phi; 67 | Tz=[ cos(lambda) sin(lambda) 0 ; 68 | -sin(lambda) cos(lambda) 0 ; 69 | 0 0 1 ]; 70 | 71 | Ty=[ cos(phi) 0 -sin(phi) ; 72 | 0 1 0 ; 73 | sin(phi) 0 cos(phi) ]; 74 | T=Ty*Tz; 75 | 76 | case 'mag2geo', 77 | % Rotation matrices 78 | lambda=MAP_COORDS.lambda; 79 | phi=MAP_COORDS.phi; 80 | Tz=[ cos(-lambda) sin(-lambda) 0 ; 81 | -sin(-lambda) cos(-lambda) 0 ; 82 | 0 0 1 ]; 83 | 84 | Ty=[ cos(-phi) 0 -sin(-phi) ; 85 | 0 1 0 ; 86 | sin(-phi) 0 cos(-phi) ]; 87 | T=Tz*Ty; 88 | 89 | 90 | end; 91 | 92 | [n,m]=size(latIN); 93 | 94 | % Degrees to radians, and make into rows. 95 | latIN=(90 - latIN(:)')*pi180; 96 | longIN=longIN(:)'*pi180; 97 | 98 | 99 | 100 | % Transformation to cartesian coordinates. 101 | x=sin(latIN).*cos(longIN); 102 | y=sin(latIN).*sin(longIN); 103 | z=cos(latIN); 104 | 105 | % Rotations of the coordinates. 106 | tmp=T*[x; y; z]; 107 | xp=tmp(1,:);yp=tmp(2,:);zp=tmp(3,:); 108 | 109 | % Transformation back to spherical coordinates. Choosing the correct quadrant. 110 | latOUT=acos(zp./sqrt(xp.^2+yp.^2+zp.^2)); 111 | longOUT=atan2(yp,xp); 112 | 113 | if nargin > 3, 114 | % Sign change due to sign convention used here. 115 | thetaVecIN=-thetaVecIN(:)'; 116 | phiVecIN=phiVecIN(:)'; 117 | 118 | % Computing vector rotations. 119 | % First, transformation to cartesian coordinates. 120 | 121 | % Rotation matrix is 122 | % [x] [ sLcG cLcG -sG ][radial] 123 | % [y]=[ sLsG cLsG cG ][south ] 124 | % [z] [ cL -sL 0 ][east ] 125 | 126 | % Radial component is zero. 127 | Xvec= 0+ cos(latIN).*cos(longIN).*thetaVecIN - sin(longIN).*phiVecIN; 128 | Yvec= 0+ cos(latIN).*sin(longIN).*thetaVecIN + cos(longIN).*phiVecIN; 129 | Zvec= 0+ -sin(latIN).*thetaVecIN + 0; 130 | 131 | % Rotations of the system. 132 | tmp=T*[Xvec;Yvec; Zvec]; 133 | Xvecp=tmp(1,:);Yvecp=tmp(2,:);Zvecp=tmp(3,:); 134 | 135 | % Transformation back to spherical coordinates. 136 | 137 | thetaVecOUT=cos(latOUT).*cos(longOUT).*Xvecp + cos(latOUT).*sin(longOUT).*Yvecp -sin(latOUT).*Zvecp ; 138 | phiVecOUT = -sin(longOUT).*Xvecp + cos(longOUT).*Yvecp +0 ; 139 | 140 | % Sign change due to sign convention used here. 141 | thetaVecOUT=-reshape(thetaVecOUT,n,m); 142 | phiVecOUT = reshape(phiVecOUT,n,m); 143 | end; 144 | 145 | 146 | % Radians to degrees. 147 | latOUT=90 - reshape(latOUT,n,m)/pi180; 148 | longOUT=reshape(longOUT,n,m)/pi180; 149 | 150 | 151 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/radials/RADIALmatvars.m: -------------------------------------------------------------------------------- 1 | function mm = RADIALmatvars 2 | % RADIALMATVARS Simple function that returns list of variables 3 | % in a RADIAL structure that should be matrices. 4 | % 5 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 6 | % 7 | % $Id: RADIALmatvars.m 396 2007-04-02 16:56:29Z mcook $ 8 | % 9 | % Copyright (C) 2007 David M. Kaplan 10 | % Licence: GPL (Gnu Public License) 11 | % 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | mm = {'U','V','RadComp','Error','Flag'}; 15 | -------------------------------------------------------------------------------- /other_peoples/HFR_Progs-2_1_2/matlab/radials/getRDLHeader.m: -------------------------------------------------------------------------------- 1 | function [h,fn,ff] = getRDLHeader( filename ) 2 | % GETRDLHEADER Gets the header of RDL files 3 | % 4 | % The "header" of RDL files is any line beginning with "%", regardless of 5 | % whether or not it is at the beginning of the file. 6 | % 7 | % Usage: header = getRDLHeader( filename ) 8 | % [names, values] = getRDLHeader( filename ) 9 | % [header, names, values] = getRDLHeader( filename ) 10 | % 11 | % In the first usage, the raw header (i.e., any line beginning with "%") 12 | % is returned as a cell array of strings. 13 | % 14 | % In the second usage, each line of the header is split into field names 15 | % (i.e., anything before the first ":") and field values (anything after 16 | % the first ":"). This is the current CODAR file format convention. 17 | % 18 | % In the third usage, all three are returned. 19 | % 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % 22 | % $Id: getRDLHeader.m 396 2007-04-02 16:56:29Z mcook $ 23 | % 24 | % Copyright (C) 2007 David M. Kaplan 25 | % Licence: GPL (Gnu Public License) 26 | % 27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28 | 29 | if ~exist( filename, 'file' ) 30 | error( [ filename ' does not appear to exist.' ] ); 31 | end 32 | 33 | % Reads entire file and then trims it down to header. 34 | h = textread(filename,'%[^\n]',-1); 35 | n = strmatch( '%', h ); 36 | h = h(n); 37 | 38 | % Next split lines if desired. 39 | if nargout > 1 40 | fn = {}; ff = {}; 41 | for k = 1:length(h) 42 | % This way is considerably more efficient than using strtok 43 | ii = min( [ find( h{k} == ':' ), length(h{k})+1 ] ); 44 | fn{end+1,1} = strtrim(h{k}(2:ii-1)); % Remove initial % 45 | ff{end+1,1} = strtrim(h{k}(ii+1:end)); % Removie initial : 46 | end 47 | end 48 | 49 | % If exactly two args out do this: 50 | if nargout == 2 51 | h = fn; 52 | fn = ff; 53 | clear ff 54 | end 55 | 56 | 57 | -------------------------------------------------------------------------------- /other_peoples/imageFOLs-master/pksfinder.m: -------------------------------------------------------------------------------- 1 | function [pks,dzdt] = pksfinder(db,db_level); 2 | 3 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 4 | %function [pks,dzdt] = pksfinder(db,db_level); 5 | % 6 | % same as updown.m, renamed for HFR_DP 7 | % 8 | % Creates an indexing array marking when a moving profiler has changed 9 | % directions. Also creates a flag array, equal in length to the 10 | % original data, indicating the direction of travel. Note, the direction 11 | % is relative to the pressure record's syntax. 12 | % 13 | % Inputs: 14 | % db -- depth/pressure record 15 | % db_level -- threshold indicating a "true" 16 | % change in direction. 17 | % 18 | % Outputs: 19 | % pks -- indexing array marking when the direction of 20 | % travel (up or down) changes. 21 | % dzdt -- flag array indicating the direction the 22 | % profiler is moving. equal in length to db. 23 | % note: dzdt is relative to pressure record 24 | % syntax. 25 | % 26 | % Example: 27 | % [pks,dzdt] = updown(ctd(:,2),10); 28 | % 29 | % Originally written by: 30 | % Christopher Wingard 31 | % Sr. Faculty Research Assistant 32 | % College of Oceanic and Atmospheric Sciences 33 | % Oregon State University 34 | % Corvallis, Oregon 35 | % March 2003 36 | % 37 | % Editted by (slower, but more accurate): 38 | % Anthony Kirincich 39 | % Ph.D. Candidate 40 | % College of Oceanic and Atmospheric Sciences 41 | % Oregon State University 42 | % Corvallis, Oregon 43 | % January 2005 44 | % 45 | % Re-Editted by Chris Wingard (faster and more accurate) March 2005 46 | % 47 | % Special note: 48 | % Calls the MM6 Toolbox function mmpeaks. 49 | % For more info see http://www.eece.maine.edu/mm/. 50 | % -- I coppied the relevant code into here (small violation I know, don't 51 | % -- shoot me!) so others could use this without having to get the mm6 52 | % -- toolbox. 53 | 54 | % determine the up/down cycle of the profiler and mark the local min/max extrema 55 | % via an indexing array (code from mmpeaks.m). 56 | % pks = mmpeaks(db,'all'); % note pks equals an indexing array 57 | y = db; ys = size(y); x = reshape(y,1,prod(ys)); 58 | j = sign(diff([-inf x -inf])); 59 | j = find(diff(j+(j==0)) == -2); 60 | k = sign(diff([inf x inf])); 61 | k = find(diff(k+(k==0)) == 2); 62 | pks = sort([k j])'; clear y ys x j k 63 | 64 | %%%%%%%%% new code as of March 2005 from cwingard %%%%%%%%% 65 | 66 | % mark and delete index locations where there isn't a "true" direction change 67 | cnt = 1; step = 1; m = []; 68 | while cnt < length(pks) 69 | if cnt + step == length(pks) 70 | break 71 | end %if 72 | % compare consequtive extrema 73 | dz1 = db(pks(cnt)) - db(pks(cnt+step)); % magnitude of difference 74 | sg1 = sign(dz1); 75 | if abs(dz1) < db_level % change is not large enough 76 | m = [m; cnt + step]; % mark extrema for deletion 77 | step = step + 1; % bump the stepper 78 | else % change is large enough, but does it qualify as a direction change? 79 | if cnt + step == length(pks) 80 | break 81 | end %if 82 | % compare the next set of extrema to see if this is a real change 83 | dz2 = db(pks(cnt+step)) - db(pks(cnt+step+1)); % magnitude 84 | sg2 = sign(dz2); j = cnt + step; 85 | if abs(dz2) < db_level % change is not large enough -- or is it ??? 86 | if sg1 == sg2 % nahh, we're still going the same way 87 | m = [m; cnt + step]; % mark extrema for deletion 88 | step = step + 1; % bump the stepper 89 | else % maybe -- this slows things down 90 | % find extrema > db_level to the left of the current point 91 | lft = db(pks(1:j-1)) - db(pks(j)); 92 | i = find(abs(lft) > db_level); 93 | if isempty(i) == 1 94 | a = 1; 95 | else 96 | a = i(end); 97 | end 98 | % find extrema > db_level to the right of the current point 99 | rght = db(pks(j+1:end)) - db(pks(j)); 100 | i = find(abs(rght) > db_level); 101 | if isempty(i) == 1 102 | b = length(pks); 103 | else 104 | b = j + i(1); 105 | end 106 | % set the min and max of the window 107 | mn = min(db(pks(a:b))); 108 | mx = max(db(pks(a:b))); 109 | % see if our point is a min or max of this window 110 | if mx == db(pks(j)) | mn == db(pks(j)) 111 | % we have a valid turn -- reset the counters 112 | cnt = j; step = 1; 113 | else % it's not a valid peak 114 | m = [m; j]; % mark extrema for deletion 115 | step = step + 1; % bump the stepper 116 | end %if 117 | end %if 118 | else % we have a valid turn -- reset the counters 119 | cnt = j; step = 1; 120 | end %if 121 | end %if 122 | end %while 123 | pks(m) = []; clear cnt step j lft rght i a b mn mx m dz 124 | 125 | % mark the tail 126 | if pks(end) ~= length(db) 127 | pks = [pks; length(db)]; 128 | end %if 129 | 130 | flg = ones(length(pks),1); 131 | for i = 2:length(pks) - 1 132 | flg(i) = (db(pks(i)) > db(pks(i-1)) & db(pks(i)) > db(pks(i+1))) | ... 133 | (db(pks(i)) < db(pks(i-1)) & db(pks(i)) < db(pks(i+1))); 134 | end 135 | pks(flg==0) = []; clear flg i 136 | 137 | % create the direction array 138 | dz = sign(diff(db(pks))); dzdt = zeros(length(db),1); 139 | for i = 1:length(pks)-1 140 | dzdt(pks(i):pks(i+1)) = dz(i); 141 | end 142 | clear dz i 143 | 144 | return -------------------------------------------------------------------------------- /rad2_to_deg.m: -------------------------------------------------------------------------------- 1 | function deg = rad2_to_deg(rads2) 2 | % RAD^2 TO DEG - radians squared to degrees 3 | % ... converts the variance to a standard deviation 4 | % 5 | % c.f. music_error.m, music_error2.m 6 | 7 | deg = sqrt( rads2.* ((180/pi)^2) ); 8 | 9 | 10 | end -------------------------------------------------------------------------------- /run_param_test.m: -------------------------------------------------------------------------------- 1 | function [Pvalues,testResult] = run_param_test(eigValues,eigVectors,A,dualIdx,P) 2 | % RUN MUSIC PARAMETER TESTS.M - determine 1 or 2 bearing solution 3 | % [Pvalues,testResult] = run_param_test(eigValues,eigVectors,A,dualIdx,P) 4 | % 5 | % Apply Codar's MUSIC parameters to determine if the 2bearing or 1bearing 6 | % hypothesis is more valid. Since the test is run on the dual brg solution, 7 | % testResult is * TRUE IF DUAL *, false if single. 8 | % 9 | % INPUTS 10 | % eigValues,eigVectors - of the covariance matrix 11 | % A - antenna pattern data matrix ( m antennas x nbearings ) 12 | % dualIdx - two indicies of the APM bearings (dual brg soln) 13 | % P - the MUSIC parameters, eg [20 10 3] or [40 20 2] 14 | % 15 | % OUTPUTS 16 | % Pvalues - Computed paramter values 17 | % testResults - boolean, true if DUAL BEARING 18 | % 19 | % References: 20 | % SeaSonde_Radial_Processing.pdf 21 | % Radar Angle Determination with MUSIC Direction Finding, Nov 1999, U.S. Patent 5,990,834 22 | % 23 | % NOTES 24 | % % plot the parameters in 3d space with the cube of dual == true 25 | % plot3(S.Params(:,1),S.Params(:,2),S.Params(:,3),'.'), hold on 26 | % grid 27 | % xlabel('P1'),ylabel('P2'),zlabel('P3') 28 | % axis([0 100 0 100 0 20]) 29 | % h = patch([0 40 40 0 0],[0 0 20 20 0],[2 2 2 2 2],'c'); 30 | % h = patch([40 40 40 40 40],[0 20 20 0 0],[2 2 100 100 2 ],'c'); 31 | % h = patch([0 40 40 0 0],[20 20 20 20 20],[2 2 100 100 2 ],'c'); 32 | % 33 | % 34 | % See also: apply_test_result.m, detection_codar_post_proc.m 35 | 36 | % Brian Emery 3 Giugno 2008 37 | % Notes: 38 | % Run the check vs tony's paper to get the music param values. the numbers 39 | % I get are slightly different from his. I'm not sure why. This mfile 40 | % should be pretty solid. The method of combining the real and imag parts 41 | % of the APM is the only possible suspect. (29Jul08) 42 | % 43 | % 29 Jan 2015 44 | % made this into a function, added test case 45 | % 46 | % 16 Jun 2015 47 | % Coded a solution to the problem of detecting two peaks in the music 48 | % spectrum, where only one peak is detected, and dualIdx is numel = 1. 49 | 50 | 51 | 52 | 53 | % check for test case 54 | if strcmp('--t',eigValues), test_case; return, end 55 | 56 | % check for null case 57 | if any(isnan(dualIdx)) || length(dualIdx) <= 1 58 | 59 | Pvalues = NaN(1,3); 60 | testResult = false; 61 | 62 | return 63 | end 64 | 65 | 66 | % INPUTS 67 | 68 | % Set music parameters? 69 | % see [[music setting notes]]. This allows more dual solutions 70 | if nargin < 5, P = [40 20 2]; end 71 | 72 | % input must be vector of eigenvalues 73 | if ~isvector(eigValues), eigValues = diag(eigValues); end 74 | 75 | % trivial check smallest to largest 76 | [eigValues,ie] = sort(eigValues); eigVectors = eigVectors(:,ie); 77 | 78 | % initialize the actual values for output 79 | Pvalues = NaN(1,3); 80 | 81 | % Get the APM manifold ... code below wants it nbearings x m antennas 82 | A = A.'; 83 | 84 | 85 | 86 | % RUN TESTS 87 | % TWO bearing solution if: 88 | 89 | % 1) the ratio of the largest eigenvalue to the 2nd largest is less 90 | % than P1 91 | Pvalues(1) = eigValues(end)./eigValues(end-1); 92 | 93 | 94 | 95 | % 2) "the ratio of the largest two signal powers to the smallest [of the 96 | % two signal powers] is be less than P2. This based on COS's Patent 97 | % Version. 98 | 99 | G = conj(A(dualIdx,:))*eigVectors(:,[3 2]); 100 | Gt = eigVectors(:,[3 2])'*A(dualIdx,:)'; 101 | 102 | % S = inv(Gt)*[eigValues(end) 0; 0 eigValues(end-1) ]*inv(G); 103 | S = Gt\[eigValues(end) 0; 0 eigValues(end-1) ]/(G); 104 | 105 | % Get Signal Power Ratio: 106 | sigPowers = sort(diag(S)); 107 | 108 | Pvalues(2) = real(sigPowers(end))./real(sigPowers(end-1)); 109 | 110 | 111 | 112 | % 3) for the signal matrix, the ratio of the product of the diagonal 113 | % elements to the product of the off diagonal elements must be greater 114 | % than P3. 115 | Pvalues(3) = real(prod(diag(S)) ./ prod(S([2 3])) ); 116 | 117 | % if isnan(Pvalues(3)), keyboard, end 118 | 119 | % Run test (TRUE IF DUAL BEARING) 120 | if Pvalues(1) < P(1) && Pvalues(2) < P(2) && Pvalues(3) > P(3) 121 | testResult = true; 122 | else 123 | testResult = false; 124 | end 125 | 126 | 127 | 128 | end 129 | 130 | 131 | function test_case 132 | % TEST CASE 133 | 134 | % EXAMPLE FROM 135 | % Properties of HF RADAR Compact Antenna Arrays and Their Effect 136 | % on the MUSIC Algorithm by dePaolo and Terril 137 | 138 | % Create the covariance matrix from de Paolo's example: 139 | C = [ 0.2162 0.0303-0.0090i 0.3170-0.0063i; ... 140 | 0.0303+0.0090i 0.0436 -0.0091+0.0213i; ... 141 | 0.3170+0.0063i -0.0091-0.0213i 0.5416]; 142 | 143 | [V,D] = eig(C); 144 | 145 | 146 | APM = make_ideal_pattern(225); 147 | A = get_array_matrix(APM); 148 | 149 | %[DOA,singleIdx,dualIdx] = getDOAs(A,V,D); 150 | % instead of using getDOAs, use the fact that the known signal input 151 | % bearing are 205 and 330 deg (from the reference) 152 | dualIdx = [find(APM.BEAR == 205) find(APM.BEAR == 330)]; 153 | 154 | 155 | [Pvalues,testResult] = run_param_test(D,V,A,dualIdx,[20 10 3]); 156 | 157 | 158 | % check with values given in figure 9 159 | if isequal(round(Pvalues*100)/100,[11.2800 4.4300 2.7200]) 160 | disp('test case ... ok') 161 | else 162 | disp('test case ... NOT ok') 163 | keyboard 164 | end 165 | 166 | 167 | keyboard 168 | 169 | return 170 | 171 | figure 172 | subplot(2,1,1), plot(A.BEAR,10*log(DOA(:,1))) 173 | 174 | subplot(2,1,2), plot(A.BEAR,10*log(DOA(:,2)),'-r') 175 | 176 | 177 | 178 | 179 | 180 | end 181 | -------------------------------------------------------------------------------- /signal_power_for_doa_struct.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/signal_power_for_doa_struct.m -------------------------------------------------------------------------------- /test_data_tonys.m: -------------------------------------------------------------------------------- 1 | function [C,APM] = test_data_tonys 2 | % TONYS TEST ... EXAMPLE FROM 3 | % Properties of HF RADAR Compact Antenna Arrays and Their Effect 4 | % on the MUSIC Algorithm by dePaolo and Terril 5 | % 6 | % DUAL! BEARING EXAMPLE FROM GETDOA.M 7 | % 8 | % Makes a figure showing the DOA function vs bearing just like fig 9 in the 9 | % De Paolo and Terrill Scripps report 10 | % 11 | % NOTE that he made this from a simulation with currents input at 205 and 12 | % 330 degrees which MUSIC gets kind of wrong 13 | % 14 | % Lots of code from music.m 15 | % 16 | % (APM,DOA,singleIdx,dualIdx) 17 | 18 | 19 | % Create the covariance matrix from de Paolo's example: 20 | C=[ 0.2162 0.0303-0.0090i 0.3170-0.0063i; ... 21 | 0.0303+0.0090i 0.0436 -0.0091+0.0213i; ... 22 | 0.3170+0.0063i -0.0091-0.0213i 0.5416]; 23 | 24 | % Create the idealized pattern 25 | APM = make_ideal_pattern(225, 100:0.1:359); 26 | 27 | 28 | 29 | end -------------------------------------------------------------------------------- /tonys_test_data.m: -------------------------------------------------------------------------------- 1 | function [C,APM] = tonys_test_data 2 | % TONYS TEST DATA - data for testing DOA methods 3 | % [C,APM] = tonys_test_data; 4 | % 5 | % TEST DATA EXAMPLE FROM 6 | % Properties of HF RADAR Compact Antenna Arrays and Their Effect 7 | % on the MUSIC Algorithm by dePaolo and Terril 8 | % 9 | % DUAL! BEARING EXAMPLE FROM GETDOA.M 10 | % 11 | % 12 | % EXAMPLE 13 | % Makes a figure showing the DOA function vs bearing just like fig 9 in the 14 | % De Paolo and Terrill Scripps report 15 | % 16 | % SEE ALSO 17 | % music.m 18 | 19 | % Copyright (C) 2016 Brian Emery 20 | 21 | % Create the covariance matrix from de Paolo's example: 22 | C=[ 0.2162 0.0303-0.0090i 0.3170-0.0063i; ... 23 | 0.0303+0.0090i 0.0436 -0.0091+0.0213i; ... 24 | 0.3170+0.0063i -0.0091-0.0213i 0.5416]; 25 | 26 | % Create the idealized pattern 27 | APM = make_ideal_pattern(225, 0:5:360); 28 | 29 | 30 | return 31 | % TESTING CODE BELOW - USEFUL FOR COPY AND PASTE 32 | 33 | ix = mle_test(APM,C); % !!! THIS WORKS 34 | APM.BEAR(ix) 35 | 36 | keyboard 37 | 38 | % MUSIC SOLUTION 39 | [DOA,singleIdx,dualIdx] = music(APM,C); 40 | 41 | % instead of using getDOAs, use the fact that the known signal input 42 | % bearing are 205 and 330 deg (from the reference) 43 | dualIdx = [find(A.BEAR == 205) find(A.BEAR == 330)]; %APM? 44 | 45 | 46 | % FIGURES 47 | figure 48 | 49 | subplot(211) 50 | plot_doa(APM,DOA(:,1),singleIdx,'Single Bearing DOA function') 51 | axis([0 360 -4 12]) 52 | 53 | 54 | subplot(212) 55 | plot_doa(APM,DOA(:,2),dualIdx,'Dual Bearing DOA function') 56 | axis([0 360 -5 30]) 57 | 58 | end -------------------------------------------------------------------------------- /tools/analysis/mean_noNaN.m: -------------------------------------------------------------------------------- 1 | function abar=mean_noNaN(a) 2 | 3 | % MEAN_NONAN 4 | % abar=mean_noNaN(a) 5 | % Computes the mean of each row of a 6 | % matrix after removing NaN's. 7 | 8 | % see also mean_noNaN_old.m 9 | 10 | % Copyright (C) 1999-2010 Brian Emery 11 | % Updated 5Oct1999 12 | 13 | ad=a'; 14 | i=isnan(ad); 15 | ad(i)=0; 16 | abar=(sum(ad)./sum(~i))'; 17 | end 18 | 19 | 20 | -------------------------------------------------------------------------------- /tools/analysis/mean_weighted.m: -------------------------------------------------------------------------------- 1 | function abar = mean_weighted(a,wt) 2 | % MEAN WEIGHTED - compute weighted mean 3 | % abar = mean_weighted(a,wt) 4 | % 5 | % Computes the weighted mean of each row of a 6 | % matrix after removing NaN's. 7 | % 8 | % INPUTS 9 | % a, wt, values and weights. Weights can be a vector equal to the number of 10 | % columns, otherwise must be a matrix the same size as 'a' 11 | % 12 | 13 | % TO DO 14 | % need an example, needs to work on rows of matricies 15 | 16 | % Copyright (C) 2009-2010 Brian M. Emery 17 | % Jun 2009 18 | % Jul 2012 - added test case, expanded for matricies 19 | % 20 | % NOTE 2023 See: 21 | % https://en.wikipedia.org/wiki/Weighted_arithmetic_mean 22 | 23 | 24 | % INPUTS 25 | 26 | % run test case? 27 | if strcmp(a,'--t'), test_case, abar =[]; return, end 28 | 29 | % check same number of columns 30 | if size(a,2) ~= size(wt,2) 31 | error([mfilename ':TooFewWeightsColumns']) 32 | end 33 | 34 | % check number of rows 35 | if size(a,1) ~= size(wt,1) 36 | 37 | % expand wt if this is true 38 | wt = ones(size(a,1),1)*wt; 39 | 40 | end 41 | 42 | 43 | % COMPUTE WEIGHTED MEAN 44 | 45 | % set NaN's to zero in the data matrix and weights so that they do not 46 | % contribute 47 | i=isnan(a+wt); 48 | 49 | a(i) = 0; wt(i) = 0; 50 | 51 | % compute weighted mean 52 | abar = dot(a,wt,2)./sum(wt,2); 53 | 54 | % if we've inserted an entire row of NaN, set this back to NaN 55 | j = find(sum(i,2) == size(a,2)); 56 | 57 | if ~isempty(j) 58 | abar(j) = NaN; 59 | end 60 | 61 | 62 | 63 | end 64 | 65 | function test_case 66 | % TEST CASE 67 | % using data from wikipedia: 68 | 69 | 70 | % VECTOR TEST 71 | am = [62, 67, 71, 74, 76, 77, 78, 79, 79, 80, 80, 81,81, 82, 83, 84, 86, 89, 93, 98]; 72 | 73 | pm = [81, 82, 83, 84, 85, 86, 87, 87, 88, 88, 89, 89, 89, 90, 90, 90, 90, 91, 91, 91, 92, 92, 93, 93, 94, 95, 96, 97, 98, 99]; 74 | 75 | % straight mean 76 | mn = mean_noNaN([am pm]); 77 | 78 | % check by weight by n 79 | am_ = mean_noNaN(am); 80 | pm_ = mean_noNaN(pm); 81 | 82 | % weight by n 83 | wt = mean_weighted([am_ pm_],[length(am) length(pm)]); 84 | 85 | % test 86 | run_test(mn,wt) 87 | 88 | 89 | 90 | % MATRIX TEST 91 | dat = [am_ pm_; am_ pm_; am_ pm_;]; 92 | wt = mean_weighted(dat,[length(am) length(pm)]); 93 | 94 | % test 95 | run_test([mn mn mn]',wt) 96 | 97 | 98 | % TEST WITH NANS 99 | % want to make sure I'm not biasing the result, so the 2nd row should get 100 | % 86 (as before), different than having a zero 101 | dat(:,3) = [0 NaN 10]'; 102 | 103 | % add an entire row of NaN's also 104 | dat(4,:) = NaN; 105 | 106 | % define weights 107 | wts = [length(am) length(pm) 30]; 108 | 109 | % compute 110 | wt = mean_weighted(dat,wts); 111 | 112 | % test vs pre-computed result 113 | run_test([53.75 86 57.5 NaN]',wt) 114 | 115 | end 116 | 117 | function run_test(mn,wt) 118 | 119 | if isequalwithequalnans(mn,wt) 120 | disp('testing mean_weighted.m ... ok') 121 | else 122 | disp('testing mean_weighted.m ... not ok') 123 | end 124 | 125 | end 126 | 127 | 128 | -------------------------------------------------------------------------------- /tools/analysis/stats_noNaN.m: -------------------------------------------------------------------------------- 1 | function [xbar,stdev,hi,lo,med,n]=stats_noNaN(x) 2 | % STATS_NONAN 3 | % [xbar,stdev,hi,lo,median,n] = stats_noNaN(x) 4 | % Computes the mean, std, and ranges of each row of a 5 | % matrix after removing NaN's. Also returns number of 6 | % non-NaN values used in the calc. 7 | % 8 | % SEE ALSO 9 | % mean_noNaN.m 10 | % make_stats_table.m 11 | 12 | % Copyright (C) 1999-2010 Brian M. Emery 13 | % Brian Emery 13Sept99 14 | % try-catch added 3apr09 15 | 16 | % check for test case 17 | if strcmp('--t',x), test_case, return, end 18 | 19 | 20 | [r,c]=size(x); 21 | 22 | % if x is row vector, orient it so that it computes the 23 | % mean of the vector 24 | if r==1 || c==1 25 | x=x(:)'; 26 | r=size(x,1); 27 | end 28 | 29 | % create empty outputs 30 | [xbar,stdev,hi,lo,med,n]=deal(NaN(r,1)); 31 | 32 | % If there is a way to do this without a loop, I'd like to know what it is. 33 | for i=1:r 34 | row = x(i,~isnan(x(i,:))); 35 | 36 | n(i) = length(row); 37 | xbar(i) = mean(row); 38 | stdev(i) = std(row); 39 | med(i) = median(row); 40 | 41 | % when NaN's are put in, these return empty matricies and an error 42 | try hi(i) = max(row); 43 | catch 44 | hi(i)=NaN; 45 | end 46 | 47 | try lo(i) = min(row); 48 | catch 49 | lo(i)=NaN; 50 | end 51 | 52 | end 53 | 54 | 55 | 56 | end 57 | 58 | function test_case 59 | % test cases: 60 | % Generate normal values with mean 1 and standard deviation 2. 61 | % 62 | n = 10000; 63 | x = 1 + 2.*randn(n,1); 64 | 65 | plot(x,'-b.') 66 | hold on 67 | 68 | 69 | % Generate 10% NaNs, use random integers uniform on the set 1:n 70 | n = ceil(100.*rand(n/10,1)); 71 | 72 | 73 | % insert some NaN's 74 | x(n)=NaN; 75 | 76 | plot(x,'r.') 77 | 78 | tic 79 | [xbar,stdev,hi,lo,med]=stats_noNaN(x); 80 | toc 81 | 82 | keyboard 83 | 84 | 85 | return 86 | 87 | 88 | clear 89 | % make x a matrix to test that too 90 | x(1,:)= 1 + 2.*randn(100,1); 91 | x(2,:)= 2 + 4.*randn(100,1); 92 | x(3,:)= 3 + 6.*randn(100,1); 93 | x(4,:)= 4 + 8.*randn(100,1); 94 | x(5,:)= 5 + 10.*randn(100,1); 95 | 96 | n = ceil(500.*rand(50,1)); 97 | x(n)=NaN; 98 | 99 | end 100 | -------------------------------------------------------------------------------- /tools/analysis/timeseries/mvave3.m: -------------------------------------------------------------------------------- 1 | function flt = mvave3(dat,wn) 2 | % MVAVE3.M 3 | % [flt]=mvave3(data,i); 4 | % Filter data using a moving average. Where: 5 | % -'data' is the data to be filtered (vector or matrix) 6 | % -'i' is a number which gives the size of 7 | % the filter (7 for tow 6, and tow 2 salinities) 8 | % -flt is the filtered data 9 | % 10 | % This function computes a moving average for each row if 'data' 11 | % is a matrix 12 | 13 | % Copyright 1995-2010 Brian Emery 14 | % 15 | % Version 1 Written by Brian Emery, sometime in 1995, using Libe 16 | % Washburn's idea. 17 | 18 | 19 | flt = dat; % this allows you to keep the ends 20 | 21 | % half window length 22 | wi = round(wn/2); 23 | 24 | % loop over rows 25 | for k = 1:size(dat,1) 26 | 27 | flt(k,wi:end-wi) = row_mv_ave(dat(k,:),wn); 28 | 29 | % % name the current row 'data' 30 | % data = data2(k,:); 31 | % 32 | % % initthe matrix to be averaged 33 | % D = zeros(i,c+(i-1)); 34 | % 35 | % % populate the matrix to be averaged 36 | % for m = 1:i 37 | % D(m,m:c+(m-1))=data; 38 | % end 39 | % 40 | % % filter the data using mean to take the average 41 | % flt = mean_noNaN(D(:,i:c).').'; 42 | % 43 | % % build the matrix back up 44 | % filter2(k,:) = data; 45 | % filter2(k, ) = flt; keyboard 46 | 47 | end 48 | 49 | end 50 | 51 | function flt = row_mv_ave(dat,wn) 52 | % Compute Moving Average of just one row vector 53 | 54 | c = size(dat,2); 55 | 56 | % initthe matrix to be averaged 57 | D = zeros(wn,c+(wn-1)); 58 | 59 | % populate the matrix to be averaged 60 | for m = 1:wn 61 | D(m,m:c+(m-1)) = dat; 62 | end 63 | 64 | flt = mean_noNaN(D.').'; 65 | 66 | % only keep meaningful stuff 67 | flt = flt( (wn-1):(end-wn-1)); 68 | 69 | 70 | end 71 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /tools/analysis/timeseries/rmsdiff.m: -------------------------------------------------------------------------------- 1 | function [rmsd,bias,N,mae]=rmsdiff(a,b) 2 | % RMSDIFF.M - RMS differences 3 | % [rmsd, bias, N, mae]=rmsdiff(x,y); 4 | % Computes the unbiased root-mean-square difference 5 | % between 2 timeseries. This function assumes that 6 | % input data time increments columnwise, allowing it 7 | % to accept matricies. Bias's, the difference of the 8 | % means, is output. 9 | % 10 | % Also outputs the old rms diff for comparison, and now 11 | % and the mean absolute error (MAE) 12 | % 13 | % see also rsquared.m, mean_noNaN.m 14 | % 15 | % CONFIDENCE INTERVALS 16 | % 17 | % % rmsd ci? ... using matlab's bootstrap 18 | % [ci,bootstat] = bootci(1000,@rmsdiff,x,y); 19 | % [ci,bootstat] = bootci(1000,{@rmsdiff,x',y'},'Type','norm'); 20 | % 21 | % rmsd_ci(1,i) = ci(2); 22 | % rmsd_ci(3,i) = ci(1); 23 | % rmsd_ci(2,i) = rmsdiff(x,y); 24 | 25 | 26 | % 20mar99 Brian Emery 27 | % 21Feb01 Updated: Remove means, report bias's, 28 | % Matrixified the code. 29 | 30 | % get rid of NaN's. ad and bd have time increment row-wise 31 | ad=a'; bd=b'; 32 | c=ad+bd; 33 | i=isnan(c); 34 | ad(i)=0; bd(i)=0; 35 | 36 | 37 | abar=(sum(ad,1)./sum(~i,1))'; 38 | 39 | bbar=(sum(bd,1)./sum(~i,1))'; 40 | 41 | % compute N 42 | N=sum(~i,1); 43 | 44 | % compute bias 45 | bias=abar-bbar; 46 | 47 | % Re-insert NaN's, remove means and compute the difference of the 2 timeseries's 48 | ad(i)=NaN; bd(i)=NaN; 49 | del=(ad-(abar*ones(1,size(ad,1)))')-(bd-(bbar*ones(1,size(bd,1)))'); 50 | 51 | % compute rms diff, again using careful treatment of NaN's 52 | del(i)=0; 53 | rmsd=sqrt(sum(del.^2,1)./N)'; % previously ./(sum(~i,1)) 54 | 55 | % compute mae https://en.wikipedia.org/wiki/Mean_absolute_error 56 | mae = (sum(abs(del),1)./N)'; 57 | 58 | 59 | 60 | % % output rms from old method for comparison 61 | % rmsold=oldmethod(a,b); 62 | 63 | return 64 | 65 | 66 | %%%% 67 | % alternative method of computing rmsDiff: 68 | rmsd2=[]; rmsdiff=[]; 69 | 70 | for i=1:row 71 | % get rid of NaN's, j is the column index 72 | j=find(~isnan(a(i,:)+b(i,:))); 73 | 74 | del=a(i,j)-b(i,j); 75 | 76 | [xbar,stdev,hi,lo]=stats_noNaN(del); 77 | rmsdiff=sqrt((stdev.^2)+ (xbar.^2)); 78 | rmsd2=[rmsd2 rmsdiff]; 79 | end 80 | end 81 | 82 | 83 | function rmsold=oldmethod(a,b) 84 | % OLD METHOD: 85 | % run a loop one row at a time 86 | [row,col]=size(a); 87 | rmsd=[]; 88 | 89 | for i=1:row 90 | % get rid of NaN's, j is the column index 91 | j=find(~isnan(a(i,:)+b(i,:))); 92 | 93 | del=a(i,j)-b(i,j); 94 | 95 | rmsdiff=sqrt( (1/(length(del)-1))*sum(del.^2) ); 96 | 97 | rmsd=[rmsd rmsdiff]; 98 | end 99 | 100 | rmsold=rmsd; 101 | end 102 | -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/apm_struct.m: -------------------------------------------------------------------------------- 1 | function APM = apm_struct(tf) 2 | % APM_STRUCT Initialize a standard APM structure 3 | % APM = apm_struct 4 | % 5 | % Initialize the APM output structure. 6 | % 7 | % Use these: 8 | % BEAR A13R A13I A23R A23I FLAG A13M A13P A23M A23P 9 | % 10 | % for field names (they come out of loop files) 11 | % 12 | % Specify/standardize that fields are column vectors 13 | % 14 | % Given the input 'true', creates an expanded APM struct for APMs derived 15 | % from ships of opportunity. 16 | % 17 | % Also when the array matrix is specified in the APM struct, orient it 18 | % #bearings x #elements, while the output of get_array_matrix is output as 19 | % #elements x #bearings, eg: 20 | % APM.A = APM.A.'; 21 | % 22 | % NOTE ABOUT UNITS 23 | % APMs seem to usually be in 'degCWN', but RADIALstruct has 24 | % Degrees_ccw_from_east. In run_cs_processing.m, get_radial_meta makes the 25 | % change from deg cwN to ccwE. 26 | % 27 | % SEE ALSO 28 | % apm_struct_ext.m 29 | 30 | % Copyright (C) 2009-2010 Brian M. Emery 31 | % June 2009 32 | 33 | % TO DO 34 | % add this to extended: 35 | % targe distance in meters 36 | % S.TRGD 37 | % might want to use other LOOP file keys as field names, see 38 | % write_loop_files.m 39 | 40 | % optionally expand struct for AIS derived patterns 41 | if nargin < 1, tf = 0; end 42 | 43 | % General, HFRP like stuff 44 | APM.Type = 'Measured Antenna Pattern' ; 45 | APM.Creator = 'B. Emery'; 46 | APM.SiteName = []; 47 | APM.SiteOrigin = []; 48 | APM.FileName = []; 49 | 50 | % Time 51 | APM.CreateTimeStamp = datestr(now); 52 | 53 | 54 | % define standard fields 55 | vars = {'README','BEAR','A13R','A13RQ','A13I','A13IQ', ... 56 | 'A23R','A23RQ','A23I','A23IQ', ... 57 | 'A13M','A13P' ,'A23M' ,'A23P', ... 58 | 'A33R','A33I','Units','A'}; 59 | 60 | % create empties 61 | for i = 1:numel(vars) 62 | APM.(vars{i}) = []; 63 | end 64 | 65 | APM.README.A = 'Array Matrix, #bearings x #elements'; 66 | 67 | %------------------------------ 68 | % EXPANSION FOR AIS derived APM 69 | %-------------------------------- 70 | if tf 71 | % expand README 72 | APM.README.BEAR = 'Bearing from HF site to ship using AIS'; 73 | APM.README.BEARMean = 'Mean of AIS for each CSQ time'; 74 | APM.README.BEARCOS = 'Bearing of ship using MUSIC and measured APM [cwN]'; 75 | APM.README.fbinIdx = 'Freq Bin Index in the CSQ'; 76 | APM.README.dopplerRadVel = 'Doppler spectrum bin velocities of ship peak'; 77 | APM.README.meanAPM = 'Mean of APM values derived from each CSQ ship peak'; 78 | 79 | 80 | vars = {'SNR','BEARMean','BEARCOS','fbinIdx','dopplerRadVel', ... 81 | 'rCellIdx'}; 82 | 83 | % create empties 84 | for i = 1:numel(vars) 85 | APM.(vars{i}) = []; 86 | end 87 | 88 | % Empty cell for csq names 89 | APM.csqFileName={}; 90 | 91 | end 92 | 93 | 94 | APM.ProcessingSteps = {}; 95 | APM.Footer = struct([]); 96 | 97 | 98 | end 99 | -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/dbm2volts.m: -------------------------------------------------------------------------------- 1 | function v2 = dbm2volts(dBm,phs) 2 | % DBM 2 VOLTS SQUARED - convert seasonde signal to in dBm to volts 3 | % v2 = dbm2volts(dBm,phs) 4 | % 5 | % Inputs in dBm, with optional second input including the phase 6 | % in radians (on interval -pi to pi, such that a complex number 7 | % is produced: 8 | % 9 | % 10 | % 11 | % See File_CrossSpectra.pdf from the COS documentation, and also 12 | % https://en.wikipedia.org/wiki/Complex_logarithm 13 | % "Problems with inverting the complex exponential function" 14 | % 15 | % See also cs_volts2dbm.m for converting units on a 16 | % whole cross spectra file. 17 | % 18 | % NOTE on units 19 | % SpectraPlotterMap suggests that the units on the signal is volts, while 20 | % File_CrossSpectra.pdf suggests volts^2. File_TimeSeries.pdf refers to 21 | % volts as well as signal power ... (see note from Bill) 22 | % 23 | % See also mag2db, and db2mag for non HFR related applications (they use 24 | % 20*log10), magPhase2RealImag, abs, angle. 25 | 26 | 27 | % Copyright (C) 2012 Brian M. Emery 28 | % 29 | % From volts2dbm.m 30 | 31 | % optional test 32 | if strcmp('--t',dBm), test_case, return, end 33 | 34 | % get the magnitude back 35 | v2 = 10.^( (dBm + 40 -5.8 )./10); 36 | 37 | if nargin > 1 38 | 39 | % use the phase to compute the complex output 40 | v2 = v2.*cos(phs) + v2.*1i.*sin(phs); 41 | 42 | end 43 | 44 | % From File_CrossSpectra.pdf: 45 | % Note to convert Antenna1,2,3 to dBm use: 46 | % 10*log10(abs(voltagesquared)) + (40.0 ? 5.8) 47 | % The 40.0 is an adjustment to conversion loss in the receiver. 48 | % The 5.8 is an adjustment to processing gain in SeaSondeAcquisition. 49 | % 50 | % It seems the above is in error, this checks out with 51 | % SpectraPlotterMap (see test below): 52 | % 53 | % % Y = DB2MAG(YDB) computes Y such that YDB = 20*log10(Y). 54 | % 55 | % Copyright 1986-2007 The MathWorks, Inc. 56 | % $Revision $ $Date: 2009/10/16 06:11:22 $ 57 | % y = 10.^(ydb/20); 58 | 59 | 60 | % dBm = 10*log10(abs(v2)) - 40 + 5.8; 61 | % 62 | % % Output phase in degrees 63 | % deg = atand(imag(v2)./real(v2)); 64 | 65 | end 66 | 67 | % -------------------------------------------------------- 68 | function test_case 69 | % TEST CASE 70 | 71 | % FROM SPECTRA PLOTTER 72 | % Some numbers from CSQ_cop1_08_12_06_202548.cs, range 14, doppler 269 73 | % A1, A2, A2 (shows volts??), 74 | 75 | v2 = [7.6137e-9 9.8172e-9 7.8471e-8]; 76 | dB = volts2dbm(v2); 77 | 78 | run_check(round(dbm2volts(dB)*1e14)/1e14,v2) 79 | 80 | 81 | % Here's a second check from SpectraPlotterMap (v11.1.2) 82 | % (also shows volts instead of v^2) 83 | v2 = [1.1906e-3 3.1938e-4 5.2024e-4]; 84 | dB = [-63.4 -69.2 -67.0]; 85 | 86 | run_check(dB,round(volts2dbm(v2).*10)./10) 87 | 88 | 89 | % CHECK FOR REVERSIBILITY 90 | % complex to db and back 91 | % ... from volts2dbm.m: 92 | % A13, A23, A12 (complex numbers) 93 | v2 = [4.216e-9 - 2.4081e-8i; 2.769e-8 + 1.846e-9i; 9.214e-10 - 8.596e-9i ]; 94 | 95 | 96 | [dBm,phs] = volts2dbm(v2); 97 | 98 | v2_ = dbm2volts(dBm,phs); 99 | 100 | 101 | % This tests reversibility ... to about 7 decimal places 102 | run_check(round(v2*1e13)./1e13,round(v2_*1e13)./1e13) 103 | 104 | 105 | % ... with zero phases? 106 | v2 = [1.1906e-3 3.1938e-4 5.2024e-4]; 107 | 108 | [dBm,phs] = volts2dbm(v2); 109 | 110 | v2_ = dbm2volts(dBm,phs); 111 | 112 | run_check(round(v2*1e13)./1e13,round(v2_*1e13)./1e13) 113 | 114 | keyboard 115 | 116 | end 117 | 118 | % -------------------------------------------------------- 119 | function run_check(db,v2) 120 | 121 | if isequal(db,v2) 122 | disp('test passed') 123 | else 124 | disp('test not passed'), 125 | end 126 | 127 | 128 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/interp_apm.m: -------------------------------------------------------------------------------- 1 | function Ai = interp_apm(A,BEAR) 2 | % INTERP APM - interpolate APM data to given bearings 3 | % Ai = interp_apm(A,BEAR) 4 | % 5 | % Bearings in A should equal or exceed the range of bearings in BEAR 6 | % 7 | % OUTPUTS 8 | % Ai = APM struct with fields same size as BEAR 9 | % 10 | % TODO 11 | % change name to apm_interp.m 12 | % 13 | % SEE ALSO 14 | % struct_interp.m 15 | 16 | % Copyright (C) 2011 Brian Emery 17 | % 18 | % updates 18 Feb 2022 19 | % - column vector output, test check code 20 | 21 | % TO DO 22 | % % should error or something if the APM bearings dont cover range(BEAR)? 23 | % 24 | % NOTE 1 25 | % at this moment the goal of this function is to expand the APM to the size 26 | % of the BEAR input. Thus, unique doesn't matter, just lookup the table at 27 | % ever given bearing. DOes this goal change? 28 | % 29 | % NOTE 2 30 | % extrap must be used on line 41 when bearings are even just a bit off 31 | 32 | % % check just in case (sorts also) 33 | % BEAR = unique(round(BEAR*10)/10); % SEE NOTE (1) 34 | 35 | % Transfer and update meta data 36 | Ai = A; 37 | Ai.Type = [A.Type ' (Interpolated)']; 38 | Ai.BEAR = BEAR; 39 | 40 | 41 | % Get list of fields to interp 42 | fn = {'A13R', 'A13I', 'A23R', 'A23I','A33R','A33I'}; 43 | 44 | 45 | % do the interpolation 46 | for i = 1:numel(fn) 47 | 48 | if isfield(A,fn{i}) && ~isempty(A.(fn{i})) 49 | Ai.(fn{i}) = interp1(A.BEAR,A.(fn{i}),Ai.BEAR,'linear','extrap'); 50 | 51 | % make sure it's column vectors 52 | Ai.(fn{i}) = Ai.(fn{i})(:); 53 | 54 | end 55 | 56 | end 57 | 58 | 59 | 60 | 61 | % Recompute Mag and Phase 62 | try 63 | Ai = realImag2MagPhase(Ai); 64 | catch 65 | end 66 | 67 | % clear fields not (yet) used 68 | fn = {'A13RQ','A13IQ', 'A23RQ','A23IQ'}; 69 | 70 | for i = 1:numel(fn) 71 | try 72 | Ai = rmfield(Ai,fn{i}); 73 | catch 74 | end 75 | end 76 | 77 | % recompute the array matrix 78 | Ai.A =[]; 79 | Ai.A = get_array_matrix(Ai); 80 | 81 | 82 | % Update processing info 83 | Ai.ProcessingSteps{end+1} = mfilename; 84 | 85 | 86 | end 87 | 88 | function test_case 89 | 90 | apm_file = ['/projects/hf_winds/data/cop1/RadialConfigs/MeasPattern.txt']; 91 | 92 | APM = load_pattern_file(apm_file); 93 | 94 | M = interp_apm(APM,min(APM.BEAR):0.1:max(APM.BEAR)); 95 | 96 | % fn = {'A13M','A13P','A23M','A23P'}; 97 | 98 | LS = get_linestyles(8); 99 | 100 | 101 | fn = {'A13R', 'A13I', 'A23R', 'A23I'}; 102 | 103 | hx = plot_struct(M,'BEAR',fn,LS(4:7)); 104 | hold on 105 | hx = plot_struct(APM,'BEAR',fn,LS(1:5),hx); hold on 106 | 107 | 108 | 109 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/loop_to_apm.m: -------------------------------------------------------------------------------- 1 | function APM = loop_to_apm(S) 2 | % LOOP TO APM - convert ctfRead of Loop files to APM standard format 3 | % 4 | % Originaly used for SOO data, now for regular SS LOOP files ... 5 | % 6 | % SEE ALSO 7 | % translate_loop.m ... (for use with SOO loop data ) 8 | % load_pattern_file.m 9 | 10 | % Updates/Breakage 7 Dec 2021 (80 yr anniversary of Pearl Harbor) 11 | % - converting to work with SeaSonde Loop files 12 | % - need to test with the other kind, or just use translate_loop for those 13 | 14 | if strcmp(S.Type,'LOOP') 15 | 16 | APM = apm_struct; 17 | % set the APM type 18 | APM.Type = 'LOOP'; 19 | 20 | else 21 | % create empty APM struct 22 | APM = apm_struct_ext(numel(S.TIME)); 23 | 24 | % set the APM type 25 | APM.Type = 'SOO'; 26 | end 27 | 28 | 29 | % TRANSLATE FIELDS 30 | 31 | % Get TimeStamp from array 32 | APM.TimeStamp = datenum(strcat(num2str(S.DATE),num2str(S.TIME,'%06.0f')),'yyyymmddHHMMSS'); 33 | 34 | % Char fields that directly match 35 | fn = {'SiteName','SiteOrigin','FileName'}; 36 | 37 | for i = 1:numel(fn) 38 | try APM.(fn{i}) = S.(fn{i})(1,:); catch, end 39 | end 40 | 41 | % Numeric fields that directly match 42 | fn = {'A13M','A13P','A23M','A23P'}; 43 | 44 | for i = 1:numel(fn) 45 | APM.(fn{i}) = S.(fn{i}); 46 | end 47 | 48 | 49 | % Input/Output fields 50 | in = {'TRGB','DPRV','PKRC','PKDC'}; 51 | out = {'BEAR','dopplerRadVel','rCellIdx','fbinIdx'}; 52 | 53 | for i = 1:numel(in) 54 | try 55 | APM.(out{i}) = S.(in{i}); 56 | catch E 57 | disp(['No ' in{i} ' field']) 58 | end 59 | end 60 | 61 | % target radial velocity (output cm/s) 62 | try APM.RadVel.xbar = S.TGRV; catch, end 63 | 64 | % stdev of target radial velocity during CSQ (cm/s) 65 | try APM.RadVel.stdev = S.TGSD; catch, end 66 | 67 | 68 | 69 | % APM Fields to compute 70 | APM = magPhase2RealImag(APM); 71 | 72 | % SNR fields 73 | APM.SNR.stdCodar = [S.A1SN S.A2SN S.A3SN]; 74 | try APM.SNR.backGrnd = [S.SBG1 S.SBG2 S.SBG3]; catch, end 75 | try APM.SNR.localDopp = [S.SLD1 S.SLD2 S.SLD3]; catch, end 76 | try APM.SNR.inRange = [S.SIR1 S.SIR2 S.SIR3]; catch, end 77 | 78 | 79 | if isfield(S,'AR3D') && isfield(S,'AR3P') 80 | 81 | % S.AR3D, S.AR3P to A33R A33I 82 | APM.A33R = 10.^(S.AR3D./10).* cosd(S.AR3P); 83 | APM.A33I = 10.^(S.AR3D./10).* sind(S.AR3P); 84 | 85 | % add these too 86 | APM.A33M = 10.^(S.AR3D./10); % convert to volts 87 | APM.A33P = S.AR3P; % deg 88 | 89 | end 90 | 91 | APM = add_units(APM); 92 | 93 | end 94 | 95 | 96 | function APM = add_units(APM) 97 | 98 | 99 | % % Meta 100 | APM.README.BEAR_Units = 'degCWN'; 101 | APM.README.loop1Brg_Units = 'degCWN'; 102 | APM.ProcessingSteps{end+1} = 'loop_to_apm'; 103 | 104 | % Add to README: 105 | APM.Units.BEAR = 'degCWN'; 106 | 107 | fn = {'A13M','A23M','A33M'}; 108 | for i = 1:numel(fn), APM.Units.(fn{i}) = 'volts'; end 109 | 110 | fn = {'A13P','A23P','A33P'}; 111 | for i = 1:numel(fn), APM.Units.(fn{i}) = 'deg'; end 112 | 113 | 114 | 115 | 116 | 117 | end 118 | 119 | -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/magPhase2RealImag.m: -------------------------------------------------------------------------------- 1 | function APM = magPhase2RealImag(APM) 2 | % MAG PHASE 2 REAL IMAG - APM real and imaginary from mag and phase 3 | % 4 | % APM = magPhase2RealImag(APM) 5 | % APM must contain the fields 'A13M','A23M','A13P','A23P', 6 | % where phases are in degrees. 7 | % 8 | % Optionally does s 'A12M','A12P', 9 | % 10 | % See also realImag2MagPhase, abs, angle. 11 | 12 | % Copyright (C) 2010 Brian M. Emery 13 | % verified method with mag_phase_calc_experiments.m 14 | 15 | if strcmp('--t',APM), test_case, return, end 16 | 17 | field_check(APM,{'A13M','A23M','A13P','A23P'}) 18 | 19 | % COMPUTE REAL AND IMAGINARY COMPONENTS 20 | % r cos(p) + r i sin(p) 21 | % real = r cos(p) 22 | % imag = r sin(p) 23 | APM.A13R = APM.A13M .* cosd(APM.A13P); 24 | APM.A13I = APM.A13M .* sind(APM.A13P); 25 | 26 | APM.A23R = APM.A23M .* cosd(APM.A23P); 27 | APM.A23I = APM.A23M .* sind(APM.A23P); 28 | 29 | % Optional cross terms 30 | if all(isfield(APM,{'A12M','A12P'})) 31 | 32 | APM.A12R = APM.A12M .* cosd(APM.A12P); 33 | APM.A12I = APM.A12M .* sind(APM.A12P); 34 | 35 | end 36 | 37 | 38 | end 39 | 40 | function test_case 41 | % TEST CASE 42 | % originally verified method with mag_phase_calc_experiments.m 43 | % make sure this works by testing on a 360 deg ideal pattern 44 | 45 | % load ideal 360 deg pattern 46 | APM = make_ideal_pattern(0); 47 | 48 | % plot 49 | plot_apm_polar(APM) 50 | 51 | % recompute the real and imag components 52 | APM = magPhase2RealImag(APM); 53 | 54 | % re-plot 55 | figure 56 | plot_apm_polar(APM) 57 | 58 | 59 | keyboard 60 | 61 | 62 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/plot_apm.m: -------------------------------------------------------------------------------- 1 | function H = plot_apm(A,LS,HH) 2 | % PLOT APM - antenna patter plots like CrossLoopPatterner 3 | % h = plot_apm(APM,LSH) 4 | % Make Plots like Cross Loop Patterner - not just polar 5 | % 6 | % INPUT 7 | % Standard APM structure (minimum required fields are BEAR A13M A23M, see 8 | % apm_struct.m) 9 | % 10 | % Optionally include Handle Struct (from previous run of this function) to 11 | % enable adding second APM to plot 12 | % 13 | % EXAMPLE 14 | % % Load and plot 15 | % I = load_pattern_file('/m_files/test_data/make_ideal_pattern/IdealPattern.txt'); 16 | % H = plot_apm(I); 17 | % 18 | % % Load, and over plot 19 | % M = load_pattern_file('/m_files/test_data/make_ideal_pattern/MeasPattern.txt'); 20 | % LS = line_style_groups; 21 | % H = plot_apm(M,LS,H); 22 | 23 | 24 | % Copyright (C) 2009-2010 Brian M. Emery 25 | % June 2009 26 | % Feb 2015 updates to make it more useful 27 | 28 | 29 | if ~isfield(A,'BEAR'), try A.BEAR = A.TRGB; catch, end, end 30 | 31 | if nargin < 2 32 | LS = line_style_groups; 33 | end 34 | 35 | 36 | hx = makesubplots(2,2,.2,.2); 37 | 38 | % phases 39 | plot(hx(1), A.BEAR,A.A13P,LS(1)), hold on 40 | plot(hx(1), A.BEAR,A.A23P,LS(2)) 41 | 42 | xlabel(hx(1),'Degrees (CWN)') 43 | ylabel(hx(1),'Phases') 44 | 45 | % amplitudes 46 | plot(hx(2), A.BEAR,A.A13M,LS(1)), hold on 47 | plot(hx(2), A.BEAR,A.A23M,LS(2)) 48 | 49 | % tangents 50 | plot(hx(3), A.BEAR,tan(A.A13M/A.A23M),LS(1)) 51 | 52 | % real and imag 53 | plot(hx(4), A.BEAR,A.A13R,LS(1)), hold on 54 | plot(hx(4), A.BEAR,A.A13I,LS(3)) 55 | 56 | plot(hx(4), A.BEAR,A.A23R,LS(2)) 57 | plot(hx(4), A.BEAR,A.A23I,LS(4)) 58 | 59 | 60 | % labels? 61 | 62 | % handle managment 63 | 64 | H = []; 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | return 73 | 74 | 75 | 76 | % FIRST PLOT POLAR 77 | 78 | if nargin == 3 79 | figure(HH(1).fig) 80 | else 81 | H(1).fig = figure; 82 | end 83 | 84 | H(1).h{1} = polar(APM.BEAR*pi/180,APM.A13M,LS(1)); hold on 85 | H(1).h{2} = polar(APM.BEAR*pi/180,APM.A23M,LS(2)); 86 | 87 | try 88 | H(1).loop1 = polar([APM.loop1Brg APM.loop1Brg]*pi/180,[0 max([APM.A23M(:)' APM.A13M(:)'])],'y'); 89 | catch 90 | end 91 | view(90,-90) 92 | 93 | H(1).leg = legend_append([H(1).h{:}],{'A13M','A23M'}); 94 | 95 | xlabel('Degrees CWN') 96 | 97 | 98 | 99 | % SECOND PLOT OF PHASES 100 | 101 | if nargin == 3 102 | figure(HH(2).fig) 103 | else 104 | H(2).fig = figure; 105 | end 106 | 107 | 108 | H(2).h{1} = plot(APM.BEAR,APM.A13P,LS(1)); hold on 109 | H(2).h{2} = plot(APM.BEAR,APM.A23P,LS(2)); 110 | xlabel('Bearing CWN') 111 | ylabel('Phase (deg)') 112 | 113 | H(2).leg = legend_append([H(2).h{:}],{'A13M','A23M'}); 114 | 115 | 116 | 117 | 118 | end 119 | 120 | 121 | function LS = line_style_groups 122 | % LINE STYLE GROUPS - get favorite line style groups 123 | 124 | % LINE STYLE SETTINGS 125 | 126 | 127 | LS(1).Color = 'r'; 128 | LS(1).Marker = 'o'; 129 | LS(1).MarkerFaceColor = 'r'; 130 | LS(1).MarkerEdgeColor = 'r'; 131 | LS(1).LineStyle = '-'; 132 | LS(1).MarkerSize = 8; 133 | 134 | % defaults 135 | LS(2:4) = LS(1); 136 | 137 | 138 | LS(2).Color = 'b'; 139 | LS(2).MarkerFaceColor = 'b'; 140 | LS(2).MarkerEdgeColor = 'b'; 141 | 142 | LS(3).Color = 'm'; 143 | LS(3).MarkerFaceColor = 'm'; 144 | LS(3).MarkerEdgeColor = 'm'; 145 | 146 | LS(4).Color = 'g'; 147 | LS(4).MarkerFaceColor = 'g'; 148 | LS(4).MarkerEdgeColor = 'g'; 149 | 150 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/plot_apm_polar.m: -------------------------------------------------------------------------------- 1 | function H = plot_apm_polar(APM,LS,HH) 2 | % PLOT APM POLAR - polar antenna patter plot 3 | % h = plot_apm_polar(APM,LSH) 4 | % Make Plots like Cross Loop Patterner 5 | % 6 | % INPUT 7 | % Standard APM structure (minimum required fields are BEAR A13M A23M, see 8 | % apm_struct.m) 9 | % 10 | % Optionally include Handle Struct (from previous run of this function) to 11 | % enable adding second APM to plot 12 | % 13 | % EXAMPLE 14 | % % Load and plot 15 | % I = load_pattern_file('/m_files/test_data/make_ideal_pattern/IdealPattern.txt'); 16 | % H = plot_apm_polar(I); 17 | % 18 | % % Load, and over plot 19 | % M = load_pattern_file('/m_files/test_data/make_ideal_pattern/MeasPattern.txt'); 20 | % LS = line_style_groups; 21 | % H = plot_apm_polar(M,LS,H); 22 | 23 | 24 | % Copyright (C) 2009-2010 Brian M. Emery 25 | % June 2009 26 | % Feb 2015 updates to make it more useful 27 | 28 | 29 | if ~isfield(APM,'BEAR'), try APM.BEAR = APM.TRGB; catch, end, end 30 | 31 | if nargin < 2 32 | LS = line_style_groups; 33 | end 34 | 35 | 36 | % FIRST PLOT POLAR 37 | 38 | if nargin == 3 39 | figure(HH(1).fig) 40 | else 41 | H(1).fig = figure; 42 | end 43 | 44 | H(1).h{1} = polar(APM.BEAR*pi/180,APM.A13M,LS(1)); hold on 45 | H(1).h{2} = polar(APM.BEAR*pi/180,APM.A23M,LS(2)); 46 | 47 | try 48 | H(1).loop1 = polar([APM.loop1Brg APM.loop1Brg]*pi/180,[0 max([APM.A23M(:)' APM.A13M(:)'])],'y'); 49 | catch 50 | end 51 | view(90,-90) 52 | 53 | %H(1).leg = legend_append([H(1).h{:}],{'A13M','A23M'}); 54 | H(1).leg = legend([H(1).h{:}],{'A13M','A23M'}); 55 | 56 | xlabel('Degrees CWN') 57 | 58 | 59 | 60 | % SECOND PLOT OF PHASES 61 | 62 | if nargin == 3 63 | figure(HH(2).fig) 64 | else 65 | H(2).fig = figure; 66 | end 67 | 68 | 69 | H(2).h{1} = plot(APM.BEAR,APM.A13P,LS(1)); hold on 70 | H(2).h{2} = plot(APM.BEAR,APM.A23P,LS(2)); 71 | xlabel('Bearing CWN') 72 | ylabel('Phase (deg)') 73 | 74 | H(2).leg = legend([H(2).h{:}],{'A13M','A23M'}); 75 | 76 | 77 | 78 | 79 | end 80 | 81 | 82 | function LS = line_style_groups 83 | % LINE STYLE GROUPS - get favorite line style groups 84 | 85 | % LINE STYLE SETTINGS 86 | 87 | 88 | LS(1).Color = 'r'; 89 | LS(1).Marker = 'o'; 90 | LS(1).MarkerFaceColor = 'r'; 91 | LS(1).MarkerEdgeColor = 'r'; 92 | LS(1).LineStyle = '-'; 93 | LS(1).MarkerSize = 8; 94 | 95 | % defaults 96 | LS(2) = LS(1); 97 | 98 | 99 | LS(2).Color = 'b'; 100 | LS(2).MarkerFaceColor = 'b'; 101 | LS(2).MarkerEdgeColor = 'b'; 102 | % 103 | % LS(3).Color = 'm'; 104 | % LS(3).MarkerFaceColor = 'm'; 105 | % LS(3).MarkerEdgeColor = 'm'; 106 | % 107 | % LS(4).Color = 'g'; 108 | % LS(4).MarkerFaceColor = 'g'; 109 | % LS(4).MarkerEdgeColor = 'g'; 110 | % 111 | 112 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/realImag2MagPhase.m: -------------------------------------------------------------------------------- 1 | function APM = realImag2MagPhase(APM) 2 | % REAL IMAG 2 MAG PHASE - APM mag phase from real and imag components 3 | % 4 | % APM = realImag2MagPhase(APM) 5 | % APM must contain the fields 'A13R','A23R','A13I','A23I'. Outputs phases 6 | % in degrees (Magnitude in ? Volts I think ) 7 | % 8 | % See also magPhase2RealImag, abs, angle, volts2dbm 9 | 10 | % Copyright (C) 2010 Brian M. Emery 11 | % verified method with mag_phase_calc_experiments.m 12 | 13 | 14 | field_check(APM,{'A13R','A23R','A13I','A23I'}) 15 | 16 | % COMPUTE Magnitudes 17 | APM.A13M = sqrt( (APM.A13R.^2) + (APM.A13I.^2) ); 18 | APM.A23M = sqrt( (APM.A23R.^2) + (APM.A23I.^2) ); 19 | 20 | % COMPUTE Phases 21 | APM.A13P = atan2(APM.A13I,APM.A13R).*180/pi; 22 | APM.A23P = atan2(APM.A23I,APM.A23R).*180/pi; 23 | 24 | end -------------------------------------------------------------------------------- /tools/codar/antenna_pattern/volts2dbm.m: -------------------------------------------------------------------------------- 1 | function [dBm,phs] = volts2dbm(v2) 2 | % VOLTS SQUARED TO DBM - convert seasonde signal to dBm 3 | % [dBm,deg] = volts2dbm(v2) 4 | % 5 | % Also outputs phase in radians if given two output arguments (and inputs 6 | % are complex) 7 | % 8 | % See File_CrossSpectra.pdf from the COS documentation 9 | % 10 | % See also cs_volts2dbm.m for converting units on a 11 | % whole cross spectra file. 12 | % 13 | % NOTE on units 14 | % File_CrossSpectra.pdf suggests volts^2, which is correct even though 15 | % SpectraPlotterMap says volts. 'dBm' is a measure of power referenced to 16 | % 1mW, suggesting that the CS files (which are conjugate products of the 17 | % FFT's of the voltage time-series) contain power. Hence volts^2 18 | % 19 | % See also mag2db, and db2mag for non HFR related applications (they use 20 | % 20*log10), magPhase2RealImag, abs, angle. 21 | 22 | 23 | % Copyright (C) 2011 Brian M. Emery 24 | % 14 Oct 2010 - Verified vs SpectraPlotterMap 25 | % 6 May 2011 - rechecked and renamed, added test case and 26 | % output of phase angle 27 | 28 | % if strcmp('--t',v2), test_case, return, end %<-- comment out for speed 29 | 30 | % From File_CrossSpectra.pdf: 31 | % Note to convert Antenna1,2,3 to dBm use: 32 | % 10*log10(abs(voltagesquared)) + (40.0 ? 5.8) 33 | % The 40.0 is an adjustment to conversion loss in the receiver. 34 | % The 5.8 is an adjustment to processing gain in SeaSondeAcquisition. 35 | % 36 | % It seems the above is in error, this checks out with 37 | % SpectraPlotterMap (see test below): 38 | dBm = 10.*log10(abs(v2)) - 40 + 5.8; 39 | 40 | % skip atand for speed if nargout is one 41 | if nargout > 1, 42 | 43 | % Output phase in radians 44 | % phs = atan(imag(v2)./real(v2)); 45 | % ... on the interval (-pi to pi) ... required to reproduce complex #s 46 | phs = atan2(imag(v2),real(v2)); 47 | end 48 | 49 | end 50 | 51 | % -------------------------------------------------------- 52 | function test_case 53 | % TEST CASE 54 | 55 | % FROM SPECTRA PLOTTER 56 | % Some numbers from CSQ_cop1_08_12_06_202548.cs, range 14, doppler 269 57 | % A1, A2, A2 (shows volts??), 58 | 59 | v2 = [7.6137e-9 9.8172e-9 7.8471e-8]; 60 | dB = [-115.4 -114.3 -105.3]; 61 | 62 | run_check(dB,round(volts2dbm(v2).*10)./10) 63 | 64 | % A13, A23, A12 (complex numbers) 65 | v2 = [4.216e-9 - 2.408e-8i; 2.769e-8 + 1.846e-9i; 9.214e-10 - 8.596e-9i ]; 66 | dB = [-110.3; -109.8; -114.8 ]; 67 | ph = [-80.1; 3.8; -83.9]*pi/180; 68 | 69 | keyboard 70 | 71 | [dBm,phs] = volts2dbm(v2); 72 | 73 | % This tests functionality, ... see dbm2volts for reversibility and sig 74 | % digits 75 | run_check(dB,round(dBm.*1e3)./1e3) 76 | run_check(round(ph.*1e2)./1e2,round(phs.*1e2)./1e2) 77 | 78 | 79 | % Here's a second check from SpectraPlotterMap (v11.1.2) 80 | % (also shows volts instead of v^2) 81 | v2 = [1.1906e-3 3.1938e-4 5.2024e-4]; 82 | dB = [-63.4 -69.2 -67.0]; 83 | 84 | run_check(dB,round(volts2dbm(v2).*10)./10) 85 | 86 | keyboard 87 | end 88 | 89 | % -------------------------------------------------------- 90 | function run_check(db,v2) 91 | 92 | if isequal(db,v2) 93 | disp('test passed') 94 | else 95 | disp('test not passed'), keyboard 96 | end 97 | 98 | 99 | end -------------------------------------------------------------------------------- /tools/codar/codar_sites.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brianemery/hfr_cs_processing/db44fe3453e7fd7e0f1954e0b854796170fa0887/tools/codar/codar_sites.m -------------------------------------------------------------------------------- /tools/codar/cs_dbm2volts.m: -------------------------------------------------------------------------------- 1 | function CS = cs_dbm2volts(CS) 2 | % CS DBM TO VOLTS SQUARED- convert CS data to volts^2 3 | % CS = cs_dbm2volts(CS) 4 | % 5 | % Converts the components of a Cross Spectra file from units of dbm to 6 | % volts.^2 to dbm using dbm2volts.m 7 | % 8 | % Note that the default (no Units field), typically means the data is in 9 | % volts^2. 10 | 11 | % Copyright (C) 2017 Brian Emery 12 | % 26 May 2017 13 | 14 | % TODO 15 | % remove phase field? 16 | 17 | 18 | % Test case 19 | if strcmp(CS,'--t'), test_case, return, end 20 | 21 | 22 | % RECURSE IF MULTI-ELEMENT 23 | if numel(CS) > 1, 24 | 25 | for i = 1:numel(CS) 26 | CS(i) = cs_dbm2volts(CS(i)); 27 | end 28 | 29 | % can do this here, but cant figure out how to do it for the 30 | % singleton case ... 31 | CS = rmfield(CS,'Phases'); 32 | 33 | return 34 | end 35 | 36 | 37 | % Detect if units have been converted to dBm ... these have to be true if 38 | % the units have been converted to dBm 39 | if isfield(CS,'Units') && strcmp('dBm',CS.Units) 40 | 41 | 42 | % CONVERT UNITS 43 | 44 | % Define field names we'll loop over ( generalize a*) 45 | fn = cs_fieldnames(CS); 46 | 47 | 48 | for i = 1:numel(fn) 49 | 50 | if isfield(CS,'Phases') 51 | 52 | % use the phases if they are there 53 | CS.(fn{i}) = dbm2volts( CS.(fn{i}), CS.Phases.(fn{i}) ); 54 | 55 | % empty it out at least 56 | CS.Phases = rmfield(CS.Phases,fn{i}); % disp('using phases ..') 57 | 58 | else 59 | CS.(fn{i}) = dbm2volts( CS.(fn{i}) ); 60 | 61 | end 62 | end 63 | 64 | 65 | % Add meta data 66 | CS.Units = 'volts^2'; 67 | end 68 | 69 | 70 | end 71 | 72 | function test_case 73 | % TEST CASE 74 | 75 | % functionality test ... 76 | 77 | fn = '/m_files/test_data/compute_apm_from_csq/CSQ_cop1_08_12_06_205124.cs'; 78 | 79 | dat1 = cs_read(fn); 80 | 81 | dat(1:3) = dat1; 82 | 83 | dat = cs_volts2dbm(dat); 84 | 85 | 86 | % now run test for this function, and check reversal worked 87 | 88 | dat2 = cs_dbm2volts(dat); 89 | 90 | 91 | 92 | % PLOT RESULT 93 | fn = cs_fieldnames(dat2); 94 | 95 | 96 | % this suggests it's reversible to order 1e-20 97 | for i = 1:numel(fn) 98 | figure(1), hold on 99 | plot(real(dat1.(fn{i}))-real(dat2(1).(fn{i})) ,'.') 100 | figure(2), hold on 101 | plot(imag(dat1.(fn{i}))-imag(dat2(1).(fn{i})) ,'.') 102 | 103 | end 104 | 105 | keyboard 106 | 107 | % if isequal(dat(1),dat(3)) 108 | % disp('cs_volts2dbm: test ... ok') 109 | % else 110 | % disp('cs_volts2dbm: test ... NOT ok') 111 | % end 112 | 113 | 114 | 115 | 116 | end 117 | 118 | -------------------------------------------------------------------------------- /tools/codar/cs_fieldnames.m: -------------------------------------------------------------------------------- 1 | function fn = cs_fieldnames(CS) 2 | % CS FIELDNAMES - read antenna field names from Cross Spectra File 3 | % fn = cs_fieldnames(CS) 4 | % 5 | % fn = {'antenna1Self' 6 | % 'antenna2Self' 7 | % 'antenna3Self' 8 | % 'antenna12CrossSp' 9 | % 'antenna13CrossSp' 10 | % 'antenna23CrossSp' 11 | % }; 12 | % 13 | % Should work for non-seasonde CS also. 14 | % 15 | % SEE ALSO 16 | % ... for generating them use this: cs_make_field_names.m 17 | 18 | 19 | fn = fieldnames(CS); fn = fn(strncmp('a',fn,1)); 20 | 21 | end -------------------------------------------------------------------------------- /tools/codar/cs_make_field_names.m: -------------------------------------------------------------------------------- 1 | function [fn,I,J] = cs_make_field_names(M) 2 | % CS MAKE FIELD NAMES - create names for fields for non-seasonde CS 3 | % [fn,I,J] = cs_make_field_names(M) 4 | % 5 | % Names for auto and cross spectra of the upper triangle 6 | % 7 | % see also, cs_struct.m, cs_from_fft.m, cs_fieldnames.m, doa_column_index.m 8 | 9 | % Copyright (C) 2017 Brian Emery 10 | 11 | 12 | 13 | % just need the upper triangle 14 | [I,J] = find(triu(ones(M))); 15 | 16 | 17 | % Zero pad if M > 9 (num2str(I,'%02.0f')_ 18 | if M > 9 19 | fmt = '%02.0f'; 20 | else 21 | fmt = '%1.0f'; 22 | end 23 | 24 | fn = cell(length(I),1); 25 | 26 | for n = 1:length(I) 27 | 28 | % make the new field name 29 | fn{n} = ['a' num2str(I(n),fmt) num2str(J(n),fmt) ]; 30 | 31 | end 32 | 33 | 34 | 35 | end 36 | -------------------------------------------------------------------------------- /tools/codar/cs_plot_bragg_lines.m: -------------------------------------------------------------------------------- 1 | function hx = cs_plot_bragg_lines(CS,h,a) 2 | % CS PLOT BRAGG LINES - add bragg lines to CS plot 3 | % 4 | % USAGE 5 | % hx = cs_plot_bragg_lines(CS,h) 6 | % 7 | % OPTIONALLY 8 | % add the ylims to specify height of the Bragg ticks 9 | % 10 | % see bragg_frequency_notes.m 11 | 12 | 13 | % Brian Emery 14 | 15 | if nargin < 2, h = gcf; end 16 | 17 | 18 | % constants 19 | g = 9.81; %m/s^2 20 | c = 299792458;% m / s 21 | 22 | % ftx=13.49e6; % transmit freq in hz (1/s) 23 | ftx = CS.Header.freqMHz *1e6; % transmit freq in hz (1/s) 24 | 25 | ktx = 2*pi*ftx/c; % transmitter wave number 26 | 27 | % Using the doppler relation for reflected light: 28 | df = (1/(2*pi))*sqrt(2*g*ktx); 29 | 30 | if nargin < 3 31 | a = axis(h); 32 | 33 | else 34 | a = [NaN NaN a]; 35 | end 36 | 37 | hx = plot(h,[df -df; df -df],[a(3:4)' a(3:4)'],'-k'); 38 | 39 | 40 | 41 | 42 | 43 | end 44 | -------------------------------------------------------------------------------- /tools/codar/cs_struct.m: -------------------------------------------------------------------------------- 1 | function CS = cs_struct(N,M) 2 | % CS STRUCT - create empty CS structure 3 | % 4 | % INPUT 5 | % N - number of elements of CS 6 | % 7 | % NEW 2nd input, allows field names for arbitrary arrays with M elements 8 | % 9 | % DATA SPECIFICATION 10 | % Standard format has the matricies with 11 | % dimensions nfft x # range cells 12 | % 13 | % Note that the file name appears to be the start time of the data in the 14 | % file in SeaSonde Cross Spectra. 15 | 16 | 17 | [CS.Header] = deal([]); 18 | 19 | 20 | if nargin < 2 21 | 22 | [CS.antenna1Self, ... 23 | CS.antenna2Self, ... 24 | CS.antenna3Self, ... 25 | CS.antenna12CrossSp, ... 26 | CS.antenna13CrossSp, ... 27 | CS.antenna23CrossSp, ] = deal([]); 28 | 29 | 30 | else 31 | 32 | % make fields 33 | CS = make_fields(M,CS); 34 | 35 | 36 | end 37 | 38 | 39 | [CS.spectraQualNum, ... 40 | CS.rdCSErr] = deal([]); 41 | 42 | 43 | CS.FileName = ''; 44 | 45 | CS.ProcessingSteps = {''}; 46 | CS.Units = 'volts^2'; 47 | 48 | CS.freqs =[]; 49 | CS.Vrad = []; 50 | 51 | if nargin > 0 52 | 53 | CS(1:N) = deal(CS); 54 | 55 | end 56 | 57 | 58 | end 59 | 60 | function CS = make_fields(M,CS) 61 | 62 | 63 | fn = cs_make_field_names(M); 64 | 65 | 66 | for n = 1:length(fn) 67 | 68 | % now calc auto and cross products 69 | CS.(fn{n}) = []; 70 | 71 | end 72 | 73 | 74 | end 75 | 76 | -------------------------------------------------------------------------------- /tools/codar/cs_volts2dbm.m: -------------------------------------------------------------------------------- 1 | function CS = cs_volts2dbm(CS) 2 | % CS VOLTS SQUARED TO DBM - convert CS data to dBm 3 | % CS = cs_volts2dbm(CS) 4 | % 5 | % Converts the components of a Cross Spectra file from units of volts.^2 to 6 | % dBm using volts2dbm.m 7 | 8 | % Copyright (C) 2011 Brian Emery 9 | % 6 May 2011 10 | 11 | 12 | % Test case 13 | if strcmp(CS,'--t'), test_case, return, end 14 | 15 | 16 | % RECURSE IF MULTI-ELEMENT 17 | if numel(CS) > 1, 18 | 19 | % Add meta container 20 | [CS(1:numel(CS)).Units] = deal(''); 21 | 22 | % Add container for phases 23 | [CS(1:numel(CS)).Phases] = deal(struct([])); 24 | 25 | 26 | for i = 1:numel(CS) 27 | CS(i) = cs_volts2dbm(CS(i)); 28 | end 29 | 30 | return 31 | end 32 | 33 | 34 | 35 | % Detect if units have been converted to dBm 36 | if ( ~isfield(CS,'Units') || ~strcmp('dBm',CS.Units) ) && ~isempty(CS) 37 | 38 | % disp('Converting to dB') 39 | 40 | % CONVERT UNITS 41 | 42 | % Define field names we'll loop over 43 | fn = cs_fieldnames(CS); 44 | 45 | 46 | for i = 1:numel(fn) 47 | 48 | [CS.(fn{i}),CS.Phases(1).(fn{i})] = volts2dbm( CS.(fn{i}) ); 49 | 50 | end 51 | 52 | 53 | % Add meta data 54 | CS.Units = 'dBm'; 55 | end 56 | 57 | 58 | end 59 | 60 | function test_case 61 | % TEST CASE 62 | 63 | % functionality test ... 64 | 65 | fn = '/m_files/test_data/compute_apm_from_csq/CSQ_cop1_08_12_06_205124.cs'; 66 | 67 | dat = cs_read(fn); 68 | 69 | dat(1:3) = dat; 70 | 71 | 72 | 73 | % run test 74 | dat = cs_volts2dbm(dat); 75 | 76 | 77 | keyboard 78 | 79 | if isequal(dat(1),dat(3)) 80 | disp('cs_volts2dbm: test ... ok') 81 | else 82 | disp('cs_volts2dbm: test ... NOT ok') 83 | end 84 | 85 | 86 | end 87 | 88 | -------------------------------------------------------------------------------- /tools/codar/ctf_descriptions.m: -------------------------------------------------------------------------------- 1 | function [desc,units,fmt] = ctf_descriptions(HdrNames,HdrValues) 2 | % CTF_DESCRIPTIONS.M - get or save descriptions for CTF file keys 3 | % [desc,units,fmt] = ctf_descriptions(HdrNames,HdrValues) 4 | % 5 | % This function is typically called by ctfReader.m (to populate the database 6 | % as files are loaded), and ctfWriter.m to use info in the database. 7 | % 8 | % The 'database' is currently ctf_formats.mat, and saved on the function's 9 | % matlab path in /codar/private/. The 'descriptions' are the strings associated 10 | % with the 4 char keys, and their units. 11 | % 12 | % If necessary, this database can be recreated with code in ctf_formats.m, 13 | % and or code in the test for ctfReader.m 14 | 15 | % Copyright(C) 2012 Brian M. Emery 16 | % Version 22 Feb 2012: 17 | % from ctf_formats.m 18 | 19 | if nargin > 0 20 | 21 | % get descriptions from inputs 22 | [desc,units] = read_descriptions(HdrNames,HdrValues); 23 | 24 | % add them to database 25 | save_ctf_formats(desc, 'desc' ) 26 | save_ctf_formats(units,'units') 27 | 28 | else 29 | 30 | % output descriptions and units ... and formats 31 | load('ctf_formats.mat','desc','units','fmt'); 32 | 33 | end 34 | 35 | 36 | end 37 | 38 | function [D,U] = read_descriptions(HdrNames,HdrValues) 39 | % READ DESCRIPTIONS 40 | % 41 | % parse header names and values to assign descriptions to each of the 4 42 | % character keys 43 | % 44 | % second output struct commonly contains unit descriptions 45 | 46 | % get the field names to use from 'TableColumnTypes' 47 | [~,~,val]=getNameValuePair('TableColumnTypes',HdrNames,HdrValues); 48 | fn = cellstr(strparser(val{1})); 49 | 50 | % Get the column names (possibly 2 rows here); after TableStart 51 | ii = find(strcmp('TableStart',HdrNames)); 52 | 53 | 54 | % get, parse and pack colum data 55 | D = pack_descriptions(fn,HdrNames{ii+1}); 56 | 57 | %keyboard 58 | 59 | % GET UNITS 60 | % sometimes this is where the units are located 61 | % try for row 2 if it exists 62 | if numel(HdrNames) > ii+1 63 | 64 | U = pack_descriptions(fn, HdrNames{ii+2}); 65 | 66 | else 67 | 68 | % otherwise create the empty struct 69 | % U = cell2struct(cell(size(fn)),fn,1); 70 | for i = 1:numel(fn) 71 | U.(fn{i}) = {''}; 72 | end 73 | 74 | end 75 | 76 | 77 | end 78 | 79 | function D = pack_descriptions(fn, HdrNames) 80 | 81 | % strip off comment characters 82 | HdrNames = regexprep(HdrNames,'%*',''); 83 | 84 | % get and parse colNames 85 | colNames = cellstr(strparser(HdrNames)); 86 | 87 | % put the data in a struct 88 | for i = 1:numel(fn) 89 | try 90 | D.(fn{i}) = colNames(i); 91 | 92 | catch E 93 | D.(fn{i}) = {''}; 94 | 95 | end 96 | end 97 | 98 | 99 | 100 | end 101 | 102 | -------------------------------------------------------------------------------- /tools/codar/my_hfrp_tools/RADIALstruct.m: -------------------------------------------------------------------------------- 1 | function R = RADIALstruct( N ) 2 | % RADIALSTRUCT Creates an empty default RADIAL structure 3 | % that can be filled with radial current measurements data 4 | % 5 | % Usage: RADIAL = RADIALstruct( N ) 6 | % 7 | % This function should be used *every* time one wants to load in any type of 8 | % radial data so that all such structures have the same fields. 9 | % 10 | % Inputs 11 | % ------ 12 | % 13 | % N: size of vector of radial structures to return. Defaults to 1. 14 | % 15 | % Outputs 16 | % ------- 17 | % 18 | % RADIAL: is the empty structure to use for recording radial data. 19 | % 20 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 21 | % 22 | % $Id: RADIALstruct.m 396 2007-04-02 16:56:29Z mcook $ 23 | % 24 | % Copyright (C) 2007 David M. Kaplan 25 | % Licence: GPL (Gnu Public License) 26 | % 27 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 28 | 29 | % BE Edit: 30 | % added specific fields to the 'OtherMatrixVars' substruct 31 | 32 | R.Type = 'Ideal'; 33 | 34 | R.SiteName = ''; 35 | R.SiteCode = 1; 36 | R.SiteOrigin = [NaN,NaN]; 37 | 38 | R.FileName = cell(1,0); % This is the only way to have a truly empty RADIAL 39 | % structure 40 | R.TimeStamp = zeros(1,0); 41 | R.TimeZone = 'GMT'; 42 | 43 | R.LonLat = zeros(0,2); 44 | R.RangeBearHead = zeros(0,3); 45 | 46 | R.RadComp = []; 47 | R.Error = []; 48 | R.Flag = []; 49 | R.U = []; % These are purely for convenience, not calculations 50 | R.V = []; % These are purely for convenience, not calculations 51 | 52 | R.LonLatUnits = {'Decimal Degrees','Decimal Degrees'}; 53 | R.RangeBearHeadUnits = {'km','Degrees_ccw_from_east','Degrees_ccw_from_east'}; 54 | [R.RadCompUnits,R.ErrorUnits,R.UUnits,R.VUnits] = deal( 'cm/s' ); 55 | 56 | R.CreateTimeStamp = datestr(now); 57 | R.CreateTimeZone = 'GMT'; 58 | 59 | 60 | % Note that all variables in this structure should have the 61 | % same number of dimensions as RadComp (i.e. [SpatialPoints x TimeSteps] ). 62 | [R.OtherMatrixVars.ERSC , ... 63 | R.OtherMatrixVars.ERTC , ... 64 | R.OtherMatrixVars.ESPC , ... 65 | R.OtherMatrixVars.MAXV , ... 66 | R.OtherMatrixVars.MINV , ... 67 | R.OtherMatrixVars.SPRC , ... 68 | R.OtherMatrixVars.VFLG ]= deal([]); 69 | 70 | 71 | R.OtherMetadata = struct([]); 72 | 73 | R.ProcessingSteps = {}; 74 | 75 | R.RADIAL_struct_version = which(mfilename); %'SVN $Rev: 397 $ $Date: 2007-04-02 $'; 76 | 77 | if exist('N','var') 78 | R = repmat( R, [N,1] ); 79 | 80 | % BE note: if you have N sites, this applies a site code 2^N for each 81 | % site. Ive been useing this function such that N may equal the number of 82 | % radial files I'm loading. 83 | % n = num2cell( 2.^(0:N-1) ); 84 | % [R.SiteCode] = deal(n{:}); 85 | end 86 | 87 | -------------------------------------------------------------------------------- /tools/codar/my_hfrp_tools/loadDataFileWithChecks.m: -------------------------------------------------------------------------------- 1 | function [ d, fn, c ] = loadDataFileWithChecks( fn ) 2 | % LOADDATAFILEWITHCHECKS Loads a text data file, but does some basic checking 3 | % to see if the file exists and the data is not empty. 4 | % 5 | % Usage: [ data, filename, code ] = loadDataFileWithChecks( filename ) 6 | % [ data, filename, code ] = loadDataFileWithChecks( data ) 7 | % 8 | % Inputs 9 | % ------ 10 | % filename = a string filename of a text data file (i.e., a tab or comma 11 | % delimited file of the type matlab likes) to be loaded. This 12 | % can also be a data matrix, in which case the same data will be 13 | % passed back (useful if you are not sure if argument is a 14 | % filename or data). In this case, the returned filename will be 15 | % 'MATRIX'. 16 | % 17 | % Outputs 18 | % ------- 19 | % data = the result of load(filename) if a string filename was passed to 20 | % the function. Otherwise the original argument to the function 21 | % is just passed back. 22 | % filename = if the original filename was a valid string filename, then 23 | % this will just be the filename. If the file does not exist, 24 | % then this will be [ 'NOT FOUND: ' filename ]. If the 25 | % original argument to the function was a data matrix, this 26 | % will be 'MATRIX'. Otherwise, it will be 'BAD TYPE'. 27 | % 28 | % code = 0 for good string filename that can be loaded, 1 for data matrix, 29 | % 10 for file that is emtpy, 100 for file that does not exist, 1000 30 | % for file that cannot be loaded, 1e10 otherwise. Might be a sum of 31 | % these. 32 | % 33 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 34 | % 35 | % $Id: loadDataFileWithChecks.m 471 2007-08-21 22:52:08Z dmk $ 36 | % 37 | % Copyright (C) 2007 David M. Kaplan 38 | % Licence: GPL (Gnu Public License) 39 | % 40 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 41 | 42 | % BE Version: 43 | % - add comments ...then removed the comments ... 44 | % 45 | % COMMENTS/THOUGHTS 46 | % - Not sure how this would handle cell input, seems like something that one 47 | % should chekc for 48 | % 49 | % - Need to be able to control the level of output to the screen 50 | % - Need to update the matlab error methods 51 | 52 | 53 | switch class(fn) 54 | 55 | case 'char' 56 | 57 | % Does the file exist? 58 | if ~exist(fn,'file') || exist(fn,'dir') 59 | 60 | % warning( [mfilename ': File ' fn ' not found.' ] ); 61 | d = []; 62 | fn = [ 'NOT FOUND: ' fn ]; 63 | c = 100; 64 | 65 | else 66 | 67 | try 68 | c = 0; 69 | d = load(fn); 70 | 71 | catch 72 | %warning(lasterr); 73 | 74 | warning( [mfilename ': File ' fn ' could not be loaded ' ] ... 75 | ); 76 | 77 | fn = [ 'UNLOADABLE: ' fn ]; 78 | 79 | c = 1e3; 80 | d = []; 81 | 82 | end 83 | 84 | end 85 | 86 | 87 | case 'double' 88 | d = fn; 89 | fn = 'MATRIX'; 90 | c = 1; 91 | 92 | otherwise 93 | warning( [mfilename ': Unknown data type passed to function.' ] ); 94 | d = fn; 95 | fn = 'BAD TYPE'; 96 | c = 1e10; 97 | 98 | end 99 | 100 | if isempty(d) 101 | c = c + 10; 102 | end 103 | 104 | end 105 | -------------------------------------------------------------------------------- /tools/codar/private/save_ctf_formats.m: -------------------------------------------------------------------------------- 1 | function save_ctf_formats(N,structStr) 2 | % SAVE CTF FORMATS - merge new data with existing and save it 3 | % 4 | % Called by ctf_formats.m and ctf_descriptions.m to append field 5 | % data to existing structures. 6 | % 7 | % INPUT is the string field name to append to 8 | % 9 | % Quick and not particularly elegant 10 | 11 | % Copyright (C) 2012 Brian Emery 12 | 13 | 14 | % get ctf_formats.mat path 15 | fname = which('ctf_formats.mat'); 16 | 17 | % load desc struct 18 | S = load(fname,structStr); 19 | 20 | % merge structs 21 | M = [fieldnames(N) struct2cell(N); fieldnames(S.(structStr)) struct2cell(S.(structStr))]; 22 | 23 | % find unique fields, favoring the old over the new. 24 | % Using non-cell M, and unique(..,'rows') would be able to identify cases 25 | % where keys have different descriptions 26 | [~, r] = unique(M(:,1)); 27 | M = M(r,:); 28 | 29 | % set struct to save 30 | eval([structStr ' = cell2struct(M(:,2), M(:,1), 1);']) 31 | 32 | 33 | % write data (maybe just fprintf, as a .m?) 34 | save(fname,structStr,'-append') 35 | 36 | 37 | end 38 | 39 | 40 | function extra_code 41 | % EG ELIMINATE FIELDS 42 | 43 | fieldnames(fmt)' 44 | 45 | fn = {'SBG1' 'SBG2' 'SBG3' 'SIR1' 'SIR2' 'SIR3' 'SLD1' 'SLD2' 'SLD3' }; 46 | 47 | desc = rmfield(desc,fn); 48 | fmt = rmfield(fmt,fn); 49 | units = rmfield(units,fn); 50 | 51 | end -------------------------------------------------------------------------------- /tools/codar/radial/compute_heading.m: -------------------------------------------------------------------------------- 1 | function R = compute_heading(R) 2 | % COMPUTE HEADING - from site origin and data lon lat using dist.m 3 | % 4 | % The dist.m output is degrees cwN, which this converts to ccwE for use 5 | % with HFR Progs 6 | % 7 | % EXAMPLE 8 | % R = compute_heading(R) 9 | 10 | % Should combine this with rangeBear2LonLat.m 11 | 12 | % Brian Emery, 5 Aug 2019 13 | 14 | % check for test 15 | if strcmp('--t',R), test_case, return, end 16 | 17 | 18 | % struct recursion if necessary 19 | if numel(R) > 1 20 | for i = 1:numel(R) 21 | R(i) = compute_heading(R(i)); 22 | end 23 | return 24 | end 25 | 26 | % Run the code 27 | [R.RangeBearHead(:,3),af]= calc_head(R.SiteOrigin,R.LonLat); 28 | 29 | 30 | % convert to ccwE 31 | R.RangeBearHead(:,3) = cwN2ccwE(R.RangeBearHead(:,3)); 32 | 33 | % % set units %THIS DOESNT WORK WITH the recursion code 34 | % if ~isfield(R,'RangeBearHeadUnits') 35 | % R.RangeBearHeadUnits ={'km','?','deg ccwE'}; 36 | % else 37 | % R.RangeBearHeadUnits{3} = 'deg ccwE'; 38 | % end 39 | 40 | 41 | end 42 | 43 | function [Head,af] = calc_head(SiteOrigin,LonLat) 44 | % [Head,ar] = calc_head(SiteOrigin,LonLat) 45 | % 46 | % site to grid direction = bearing_f = Bear 47 | % grid to site direction = bearing_r = Head 48 | 49 | 50 | 51 | [Head,af] = deal(NaN(size(LonLat,1),1)); 52 | 53 | SiteOrigin = SiteOrigin(1,:); 54 | 55 | 56 | % just loop I guess 57 | for i = 1:size(LonLat,1) 58 | 59 | % [RANGE,AF,AR]=dist(LAT,LONG) 60 | % Site origin is Lon Lat 61 | [~,af(i),Head(i)] = dist([SiteOrigin(2) LonLat(i,2)],[SiteOrigin(1) LonLat(i,1)]); 62 | 63 | 64 | end 65 | 66 | 67 | end 68 | 69 | function test_case 70 | % TEST CASE 71 | % 72 | % ... tested during the development of submesoscale_simulation 73 | 74 | 75 | 76 | 77 | end 78 | -------------------------------------------------------------------------------- /tools/general/add_filesep.m: -------------------------------------------------------------------------------- 1 | function wd = add_filesep(wd) 2 | % ADD FILESEP - Detect trailing slash, insert if missing 3 | % wd = add_filesep(wd) 4 | % 5 | % char or cell input allowed 6 | 7 | % TO DO 8 | % rename this filesep_add 9 | % make filesep_rm (see get_file_list) 10 | 11 | % Copyright(C) 2011 Brian Emery 12 | 13 | if strcmp('--t',wd), test_case, return, end 14 | 15 | if ischar(wd) 16 | 17 | if ~strcmp(wd(end),filesep), wd(end+1) = filesep; end 18 | 19 | elseif iscell(wd) 20 | 21 | for i = 1:numel(wd) 22 | 23 | if ~strcmp(wd{i}(end),filesep), wd{i}(end+1) = filesep; end 24 | 25 | end 26 | 27 | end 28 | 29 | end 30 | 31 | function test_case 32 | 33 | disp(['all should end in ' filesep]) 34 | add_filesep('wft') 35 | add_filesep('wft/') 36 | add_filesep({'wft/'}) 37 | add_filesep({'wft'}) 38 | 39 | keyboard 40 | 41 | end -------------------------------------------------------------------------------- /tools/general/conversions/ccwE2cwN.m: -------------------------------------------------------------------------------- 1 | function cwN=ccwE2cwN(ccwE) 2 | 3 | % CCWE2CWN.M 4 | % cwN=ccwE2cwN(ccwE) 5 | % Converts Degress Counter-clockwise from east to 6 | % clockwise from north (ie, from cartesian to true bearing) 7 | 8 | % 15mar99 Brian Emery 9 | 10 | cwN=450-ccwE; 11 | i=find(cwN>=360); 12 | cwN(i)=cwN(i)-360; 13 | 14 | 15 | % NOTE from wavemeas.pdf 16 | % in radians: 17 | % cwn = 3pi/2 - ccwE 18 | 19 | 20 | end 21 | 22 | -------------------------------------------------------------------------------- /tools/general/conversions/cwN2ccwE.m: -------------------------------------------------------------------------------- 1 | function ccwE=cwN2ccwE(cwN) 2 | 3 | % CWN2CCWE.M 4 | % ccwE=cwN2ccwE(cwN) 5 | % Converts Degrees clockwise from North to Degrees 6 | % counter-clockwise from East (CCW E). 7 | 8 | % Brian Emery 1Feb98 9 | 10 | % This is the ugly, brute force method. 11 | ccwE=(abs(cwN-360))+90; 12 | 13 | i=find(ccwE>360); 14 | 15 | ccwE(i)=ccwE(i)-360; 16 | 17 | end -------------------------------------------------------------------------------- /tools/general/conversions/km2lonlat.m: -------------------------------------------------------------------------------- 1 | function [lon, lat] = km2lonlat(lon_orig,lat_orig,east,north) 2 | %KM2LONLAT Convert distances in km referenced to a lon/lat point to lon/lat. 3 | % 4 | % This function will convert distances in kilometers east and west 5 | % of a reference longitude/latitude point to longitude/latitude. The 6 | % equation was obtained from Bowditch's book "The American Practical 7 | % Navigator, 1995 edition, page 552." 8 | % 9 | % Usage: 10 | % [LON,LAT]=KM2LONLAT(LON_ORIG,LAT_ORIG,EAST,NORTH) 11 | % 12 | % Inputs: 13 | % LON_ORIG - reference longitude (decimal degrees), a scalar. 14 | % LAT_ORIG - reference latitude (decimal degrees), a scalar. 15 | % EAST - distance east (km) of reference point (scalar or vector). 16 | % NORTH - distance north (km) of reference point (scalar of vector). 17 | % 18 | % Outputs: 19 | % LON - longitude (decimal degrees) 20 | % LAT - latitude (decimal degrees) 21 | % 22 | % Example: 23 | % [LON,LAT]=KM2LONLAT(-122,35.4,EAST,NORTH) 24 | % will convert the vectors EAST and NORTH, which contain distances 25 | % in km east and north of -122 W, 35.4 N to lon/lat pairs, returned 26 | % in the vectors LON and LAT. 27 | % 28 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 29 | % Copyright (C) 2007 Mike Cook, Naval Postgraduate School 30 | % License: GPL (Gnu Public License) 31 | % 32 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 33 | 34 | % Mike Cook - NPS Oceanography Dept. - FEB 94 35 | % Mike Cook - JUN 94 - added more documentation and error checking. 36 | 37 | 38 | % Check for the correct number of inputs. 39 | if nargin ~= 4 40 | error(' You *MUST* supply 4 input arguments ') 41 | end 42 | 43 | con = radians(lat_orig); 44 | ymetr = 111132.92 - 559.82 .* cos(2 .* con) + 1.175 ... 45 | .* cos(4 .* con) - 0.0023 .* cos(6 .* con); 46 | xmetr = 111412.84 .* cos(con) - 93.50 .* cos(3 .* con) ... 47 | + 0.0118 .* cos(5 .* con); 48 | lon = east .* 1000 ./ xmetr + lon_orig; 49 | lat = north .* 1000 ./ ymetr + lat_orig; 50 | -------------------------------------------------------------------------------- /tools/general/conversions/lonlat2km.m: -------------------------------------------------------------------------------- 1 | function [east, north] = lonlat2km(lon_orig,lat_orig,lon,lat) 2 | %LONLAT2KM Convert lat/lon to distances (km) referenced to a lon/lat point. 3 | % 4 | % This function will convert longitude/latitude pairs to distances in 5 | % kilometers east and west of a reference longitude/latitude point. The 6 | % equation was obtained from Bowditch's book "The American Practical 7 | % Navigator, 1995 edition, page 552." 8 | % 9 | % Usage: 10 | % [EAST,NORTH]=LONLAT2KM(LON_ORIG,LAT_ORIG,LON,LAT) 11 | % 12 | % 13 | % Inputs: lon_orig - reference longitude. 14 | % lat_orig - reference latitude. 15 | % lon - longitude scalar or vector. 16 | % lat - latitude scalar or vector. 17 | % 18 | % Outputs: east - distance east from reference point (km) 19 | % north - distance north from reference point (km) 20 | % 21 | % Example: 22 | % [EAST,NORTH]=LONLAT2KM(-122,35.4,LON,LAT) 23 | % will convert the vectors LON and LAT, which contain lon/lat pairs, 24 | % to distances in km east and north of -122 W, 35.4 N, returned 25 | % in the vectors EAST and NORTH. 26 | % 27 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 28 | % Copyright (C) 2007 Mike Cook, Naval Postgraduate School 29 | % License: GPL (Gnu Public License) 30 | % 31 | % ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 32 | 33 | % Mike Cook - NPS Oceanography Dept. - FEB 94 34 | % Mike Cook - JUN 94 - added more documentation and error checking. 35 | 36 | 37 | if nargin ~= 4 38 | error(' You *MUST* supply 4 input arguments ') 39 | end 40 | 41 | 42 | con = radians(lat_orig); 43 | ymetr = 111132.92 - 559.82 .* cos(2 .* con) + 1.175 ... 44 | .* cos(4 .* con) - 0.0023 .* cos(6 .* con); 45 | xmetr = 111412.84 .* cos(con) - 93.50 .* cos(3 .* con) ... 46 | + 0.0118 .* cos(5 .* con); 47 | east = (lon - lon_orig) .* xmetr ./ 1000; 48 | north = (lat - lat_orig) .* ymetr ./ 1000; 49 | 50 | return; 51 | 52 | 53 | 54 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 55 | function r = radians(d); 56 | r = d .* pi ./ 180; 57 | return; 58 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 59 | -------------------------------------------------------------------------------- /tools/general/conversions/radians.m: -------------------------------------------------------------------------------- 1 | function r = radians(d) 2 | 3 | %RADIANS converts degrees to radians. 4 | % 5 | % r = radians(d) will convert d (which can be 6 | % a scalar or matrix of degrees) to radians. 7 | % 8 | 9 | % MIKE COOK - NPS Oceanography Dept. - v1.0 MAY94 10 | 11 | r = d .* pi ./ 180; 12 | -------------------------------------------------------------------------------- /tools/general/conversions/rangeBear2LonLat.m: -------------------------------------------------------------------------------- 1 | function LonLat = rangeBear2LonLat(RangeBear,SiteOrigin) 2 | % RANGE BEAR TO LON LAT - mash up of other functions for a short cut 3 | % LonLat = rangeBear2LonLat(RangeBear,SiteOrigin) 4 | % 5 | % INPUT 6 | % input bearings are usually ccwE, so assume that is the case 7 | % Range in km 8 | % 9 | % OUPUT 10 | % 11 | % EXAMPLE 12 | % 13 | % 14 | % See also, compute_heading.m ... 15 | 16 | % Copyright (C) 2017 Brian Emery 17 | 18 | % check for test case 19 | if strcmp('--t',RangeBear), test_case, return, end 20 | 21 | % NOTE 22 | % Regarding empty radial data cases for the RNG/CS processing. It looks 23 | % like m_fdist.m will output all empty, if given all emtpy. But the use of 24 | % the site lonlat here will cause an error. So, put in this trival check 25 | if isempty(RangeBear) 26 | LonLat = RangeBear; return 27 | end 28 | 29 | 30 | % Note that m_fdist calls for azimuth input, azimuth is compass bearing, 31 | % eg degrees cwN, meters! too 32 | [LonLat(:,1),LonLat(:,2),~] = m_fdist(SiteOrigin(1),SiteOrigin(2),ccwE2cwN(RangeBear(:,2)),RangeBear(:,1)*1000); 33 | 34 | % Lon's are messed up too 35 | LonLat(:,1) = LonLat(:,1) - 360; 36 | 37 | return 38 | 39 | % OLD WAY 40 | 41 | % [eastkm,northkm]=rngbear2km(site_loc,central_loc,range,bearing) 42 | % converts the SeaSonde radial data, given as range and bearing 43 | % to km East and North relative to the origin. The site location and 44 | % central location are input as a 1x2 dim array, [longitude latitude]. 45 | % Range is in km and bearing is CCW from east. 46 | 47 | [eastkm,northkm] = rngbear2km(SiteOrigin,SiteOrigin,RangeBear(:,1),RangeBear(:,2)); 48 | 49 | 50 | % KM2LONLAT.M - Convert km to lon lat from origin using Vincenty's 51 | % [lon, lat] = km2lonlat_new(lon_origin,lat_origin,east,north) 52 | % 53 | % INPUT 54 | % decimal lon, lat of origin (scalar) 55 | % km east and north of origin (vectors) 56 | % 57 | % OUTPUT 58 | % decimal lon, lat (vectors) 59 | 60 | [LonLat(:,1), LonLat(:,2)] = km2lonlat_new(SiteOrigin(1,1),SiteOrigin(1,2),eastkm,northkm); 61 | 62 | 63 | 64 | end 65 | 66 | function test_case 67 | % TEST CASE 68 | 69 | SiteOrigin = [-119.8787 34.4076]; 70 | 71 | % bearings ccwE 72 | RangeBear(:,2) = 160:360; 73 | 74 | RangeBear(:,1) = 30; 75 | 76 | LonLat = rangeBear2LonLat(RangeBear,SiteOrigin); 77 | 78 | 79 | % % % now go back 80 | % % [east, north] = lonlat2km(SiteOrigin(1),SiteOrigin(2),LonLat(:,1),LonLat(:,2)); 81 | % % 82 | % %... jfc, what a hassle 83 | % for i = 1:size(LonLat,1) 84 | % [rng(i),af(i),ar(i)] = dist([SiteOrigin(2) LonLat(i,2)],[SiteOrigin(1) LonLat(i,1)]); 85 | % 86 | % end 87 | % 88 | % % pretty close ... 89 | % keyboard 90 | % 91 | % % 92 | % % bearing_f is compass bearing from 1 to 2, ie from site to grid (cwN) 93 | % [M.Range,M.bearing_f,M.bearing_r] = m_idist(SiteOrigin(1),SiteOrigin(2),LonLat(:,1),LonLat(:,2)); 94 | % M.Bear = cwN2ccwE(M.bearing_f); 95 | 96 | 97 | % This is the right way (Note that azimuth is compass bearing, eg 98 | % degrees cwN) ... less than 1e-7 difference (deg) and 1e-6 km 99 | % [lon,lat,~] = m_fdist(SiteOrigin(1),SiteOrigin(2),ccwE2cwN(RangeBear(:,2)),RangeBear(:,1)); 100 | % 101 | [I.Range,I.bearing_f,I.bearing_r] = m_idist(SiteOrigin(1),SiteOrigin(2),LonLat(:,1),LonLat(:,2)); 102 | I.Bear = cwN2ccwE(I.bearing_f); 103 | I.Range = I.Range./1000; 104 | 105 | % these should be true: 106 | isequal( round(I.Bear*1000)./1000, round(RangeBear(:,2).*1000)./1000 ) 107 | isequal( round(I.Range*100000)./100000, round(RangeBear(:,1).*100000)./100000 ) 108 | 109 | keyboard 110 | 111 | 112 | % Make a map test too 113 | 114 | mvco_map, title('click three locations') 115 | [lon,lat] = ginput(3); 116 | 117 | 118 | [I.Range,I.bearing_f,I.bearing_r] = m_idist(lon(1),lat(1),lon,lat); 119 | I.Bear = cwN2ccwE(I.bearing_f); 120 | I.Range = I.Range./1000; 121 | 122 | % now get it back 123 | LonLat = rangeBear2LonLat([I.Range I.Bear],[lon(1) lat(1)]); 124 | 125 | hold on 126 | h1 = plot(lon,lat,'o'); 127 | 128 | h2 = plot(LonLat(:,1),LonLat(:,2),'r*'); 129 | 130 | legend([h1(1) h2(1)],'original','recomputed') 131 | 132 | keyboard 133 | 134 | end -------------------------------------------------------------------------------- /tools/general/conversions/rngbear2km.m: -------------------------------------------------------------------------------- 1 | function [eastkm,northkm]=rngbear2km(site_loc,central_loc,range,bearing) 2 | % RNGBEAR2KM.M 3 | % [eastkm,northkm]=rngbear2km(site_loc,central_loc,range,bearing) 4 | % converts the SeaSonde radial data, given as range and bearing 5 | % to km East and North relative to the origin. The site location and 6 | % central location are input as a 1x2 dim array, [longitude latitude]. 7 | % Range is in km and bearing is CCW from east. 8 | % 9 | % This function calls Rich Pawlowicz's dist.m which computes distances on 10 | % the earth using the wgs84 spheroid (using Vincenty's), not to be confused 11 | % with the HFRProgs function of the same name. 12 | 13 | % 22Dec97 Brian Emery 14 | 15 | % NEED TO MAKE SURE 16 | % do a forward and reverse test to make sure range and bearing to km calc 17 | % is ok - ie I need the reverse of dist.m (given range and bearing compute 18 | % lon lat between points) 19 | % 20 | % see: 21 | % http://www.mathworks.com/matlabcentral/fileexchange/loadFile.do?objectId= 22 | % 15285&objectType=FILE 23 | 24 | % reduce the confusion 25 | site_lon=site_loc(1); 26 | site_lat=site_loc(2); 27 | lat_o=central_loc(2); 28 | lon_o=central_loc(1); 29 | 30 | % compute km east and north relative to site location 31 | kmN_site=range.* sin(bearing.*pi./180); 32 | kmE_site=range.* cos(bearing.*pi./180); 33 | 34 | % compute the distance between site and origin (in two compontents) 35 | % first the distance between the two longitudes at this lat. Note that 36 | % the output of dist.m is always positive! 37 | % [RANGE,AF,AR]=DIST(LAT,LONG) 38 | [delta_E,AF,AR]=dist([lat_o lat_o],[site_lon lon_o]); 39 | 40 | % now the distance between the two latitudes at this lon 41 | [delta_N,AF,AR]=dist([site_lat lat_o],[lon_o lon_o]); 42 | 43 | % compute km east and north relative to the origin 44 | if site_lon > lon_o 45 | eastkm=kmE_site+(delta_E/1000); 46 | elseif site_lon <= lon_o 47 | eastkm=kmE_site-(delta_E/1000); 48 | end 49 | 50 | if site_lat > lat_o 51 | northkm=kmN_site+(delta_N/1000); 52 | elseif site_lat <= lat_o 53 | northkm=kmN_site-(delta_N/1000); 54 | end 55 | 56 | % % check that the outputs are column vectors 57 | % if ~isempty(eastkm) 58 | % eastkm=eastkm(:); 59 | % end 60 | % 61 | % if ~isempty(northkm) 62 | % northkm=northkm(:); 63 | % end 64 | 65 | return 66 | 67 | % test numbers 68 | 69 | ptc_loc = [-120.4637 34.4543]; 70 | cop_loc = [-119.8767 34.4100]; 71 | central_loc = [(ptc_loc(1)+cop_loc(1))/2 (ptc_loc(2)+cop_loc(2))/2]; 72 | 73 | angle=181:5:361; 74 | range=1.5:1.5:45; 75 | vel=50; %this is velocity in cm/s 76 | current=vel*cos((angle-90)*pi/180); 77 | 78 | % make columns 79 | angle=angle(:); 80 | range=range(:); 81 | current=current(:); 82 | fudge=5*ones(size(angle)); 83 | 84 | %use a loop to build the file: the full span of angles for each 85 | %range. 86 | data=[]; 87 | for i=1:length(range) 88 | data=[data; range(i).*ones(size(angle)), angle, current, fudge]; 89 | end 90 | 91 | 92 | [eastkm,northkm]=rngbar2km(cop_loc,central_loc,data(:,1),data(:,2)); 93 | plot(eastkm,northkm,'r.'), hold on 94 | [eastkm,northkm]=rngbar2km(ptc_loc,central_loc,data(:,1),data(:,2)); 95 | plot(eastkm,northkm,'b.') 96 | title('ptc data in blue, cop data in red') -------------------------------------------------------------------------------- /tools/general/creation_info.m: -------------------------------------------------------------------------------- 1 | function created = creation_info 2 | % CREATION INFO - make structure with mfilename, path, and date meta data 3 | % created = creation_info 4 | % 5 | % Simplifies the documentation of structures and *.mat files 6 | 7 | % Copyright (C) 2011 Brian Emery 8 | % March 29 2011 9 | 10 | [st,ix]=dbstack('-completenames'); 11 | [pth,nm,ext] = fileparts(st(end).file); 12 | 13 | 14 | created.by = 'Brian Emery'; 15 | created.date = datestr(now,0); 16 | created.with = [nm ext]; % calling mfile and directory 17 | created.in = pth; 18 | 19 | 20 | end 21 | -------------------------------------------------------------------------------- /tools/general/datestrq.m: -------------------------------------------------------------------------------- 1 | function S = datestrq(D) 2 | % convert a date number to a string with format yyyy_mm_dd_HHMMSS 3 | % datestrq(734474.62) 4 | % ans = 2010_12_02_145248 5 | % 6 | 7 | 8 | % Copyright: zhang@zhiqiang.org, 2010 9 | % Customized Nov 2010 Brian Emery ('yyyy_mm_dd_HHMM') 10 | % renamed datestrq.m for better recall 11 | 12 | % TO DO 13 | % take advantage of sprintf vectorization by converting cell to char? 14 | % allow typical datestr inputs, then parse to create sprintf string 15 | 16 | if iscell(D) 17 | S = cell(size(D)); 18 | for i = 1:numel(D) 19 | S{i} = mdatestr(D{i}); 20 | end 21 | return; 22 | end 23 | 24 | if ~ischar(D) 25 | if min(D) > 1000 && max(D) < 693960 26 | D = D + 693960; 27 | end 28 | 29 | D = datevecmx(D); 30 | % yyyy_mm_dd_HHMMSS 31 | % S = sprintf('%04d_%02d_%02d_%02d%02d%', D(1), D(2), D(3), D(4), D(5)); 32 | S = sprintf('%4.0f_%02.0f_%02.0f_%02.0f%02.0f%02.0f', D(1), D(2), D(3), D(4), D(5), D(6)); 33 | 34 | elseif numel(D) == 10 && D(8) == '-' 35 | S = D; 36 | else 37 | S = formatdate(D); 38 | end 39 | 40 | end -------------------------------------------------------------------------------- /tools/general/diff_centered.m: -------------------------------------------------------------------------------- 1 | function du = diff_centered(u,x) 2 | % DIFF CENTERED - Centered difference 3 | % du = diff_centered(u,x) 4 | % 5 | % Computes the centered difference (slope) of a vector using the finite 6 | % difference approximation. Second order accurate (c.f. Laveque 2007 7 | % "Finite Difference Methods for Ordinary and Partial Differential 8 | % Equations"). Edge derivatives are computed using the foward and backward 9 | % one-sided approximations (with first order accuracy). 10 | % 11 | % The method assumes equal spacing of grid x, but this implementation of it 12 | % does not require equal spacing. The centered difference is order (deltax^2) 13 | % accurate, thus accuracy goes as the square of the spacing. An easy way to 14 | % increase accuracy (in most practical applications) is to use finer grid. 15 | % 16 | % INPUTS 17 | % u - the function of x. Can be a matrix of independent rows, columns 18 | % associated with x (NOTE DIFFERENCE WITH DIFF.M, which is the matrix 19 | % of row diffs) 20 | % x - the grid (usually equal spacing) 21 | % 22 | % OUTPUTS 23 | % du/dx - same size as inputs 24 | % 25 | % SEE ALSO 26 | % outputs should be more or less identical to gradient.m - damnit! 27 | % 28 | % EXAMPLE 29 | % % Need to be careful using this with degrees vs radians: 30 | % x = 1:180; % degrees 31 | % % Must convert all inputs to the same grid 32 | % du = diff_centered(sind(x),x*pi/180); 33 | % plot(x,cosd(x),'-bo'), hold on 34 | % plot(x,du,'r*') 35 | 36 | 37 | % 26Jun00 Brian Emery 38 | % Total rewrite Nov 2016 39 | 40 | % TO DO 41 | % matrix inputs? 42 | % add gradient.m to test 43 | 44 | % Note: Might look into CFD notes for alternative methods if more accuracy 45 | % is needed. 46 | 47 | 48 | % check for test case 49 | if strcmp('--t',u), test_case, return, end 50 | 51 | % Preallocate 52 | du = NaN(size(u)); 53 | x = repmat(x(:).',size(du,1),1); 54 | 55 | % Get first point 56 | du(:,1) = (u(:,2) - u(:,1)) ./ ( x(:,2)-x(:,1) ); 57 | 58 | % Centered Approximation, Eqn 1.3 59 | du(:,2:end-1) = ( u(:,3:end) - u(:,1:end-2) )./ ( x(:,3:end)-x(:,1:end-2) ); 60 | 61 | % Get last point 62 | du(:,end) = ( u(:,end) - u(:,end-1) )./( x(:,end) - x(:,end-1) ); 63 | 64 | 65 | 66 | 67 | end 68 | 69 | 70 | function test_case 71 | % FROM MATHWORKS: 72 | % Use the diff function to approximate partial derivatives with the syntax 73 | % Y = diff(f)/h, where f is a vector of function values evaluated over 74 | % some domain, X, and h is an appropriate step size. 75 | % 76 | % For example, the first derivative of sin(x) with respect to x is cos(x), 77 | % and the second derivative with respect to x is -sin(x). You can use diff 78 | % to approximate these derivatives. 79 | 80 | % Mathworks test, modified for matrix inputs 81 | % NOTE: diff(X), for a matrix X, is the matrix of row differences, 82 | % [X(2:n,:) - X(1:n-1,:)]. 83 | 84 | h = 0.001; % step size 85 | X = -pi:h:pi; % domain 86 | f = sin(X); % range 87 | f = [f; f; f;]; 88 | 89 | % Take colum diffs 90 | Y = diff(f,1,2)/h; % first derivative 91 | 92 | figure, hold on 93 | h1 = plot(X(:,1:size(Y,2)),Y,'ro'); 94 | h2 = plot(X,f,'b'); 95 | 96 | % this function 97 | df = diff_centered(f,X); 98 | 99 | % looks good? 100 | h3 = plot(X,df,'-g.'); 101 | 102 | legend([h2(1) h1(1) h3(1)],'u(x)', 'du/dx','FEM version') 103 | 104 | 105 | % % COMPARE ERRORS? 106 | % figure 107 | % plot(df(1,:) - cos(X)), hold on 108 | % plot(Y(1,:) - cos(X(1:size(Y,2))),'-r.') 109 | 110 | 111 | 112 | 113 | 114 | % % TEST X NOTE 115 | % % sind converts x into radians, so the inputs need to be consistent? 116 | % 117 | % x = 1:0.01:180; 118 | % du = diff_centered(sind(x),x*pi/180); 119 | % plot(x,cosd(x),'-bo'), hold on 120 | % plot(x,du,'r*') 121 | % 122 | % keyboard 123 | 124 | % TEST 2 125 | % Laveque 2007, pg 4 126 | % Example 1.1. Let u(x) = sin(x) and x = 1; 127 | % thus we are trying to approximate u'(x 0:5403023. 128 | x = 1; 129 | u = sin(x); 130 | 131 | h = [1e-1, 5e-2, 1e-2, 5e-3, 1e-3]; 132 | 133 | disp('h D3') 134 | 135 | for i = 1:numel(h) 136 | 137 | t = [-2 -1 0 1 2]*h(i); 138 | 139 | du = diff_centered(sin(x + t), t); 140 | 141 | err(i) = 0.5403023 - du(3); 142 | 143 | % disp([num2str(h(i)) ' ' num2str(err)]) 144 | end 145 | 146 | % Compare with figure 1.2 147 | h1 = loglog(h,err,'-bo'); hold on 148 | 149 | h0 = loglog(h, [9.0005e-4 2.251e-4 9.005e-6 2.2513e-6 9.005e-8],'r*'); 150 | 151 | axis([1e-4 1 1e-10 1e-2]) 152 | 153 | legend('diff_centered.m','Laveque Fig 1.2') 154 | 155 | keyboard 156 | 157 | 158 | end -------------------------------------------------------------------------------- /tools/general/diff_centered2.m: -------------------------------------------------------------------------------- 1 | function du2 = diff_centered2(u,x) 2 | % DIFF CENTERED - Centered difference for computing 2nd derivatives 3 | % du2 = diff_centered2(u,x) 4 | % 5 | % Computes the 2nd derivative of a vector using the finite 6 | % difference approximation. Second order accurate (c.f. Laveque 2007 7 | % "Finite Difference Methods for Ordinary and Partial Differential 8 | % Equations"). Edge derivatives are computed using the left and right sided 9 | % approximations with second order accuracy. 10 | % 11 | % The method assumes equal spacing of grid x, but this implementation of it 12 | % does not require equal spacing. The centered difference is order (deltax^2) 13 | % accurate, thus accuracy goes as the square of the spacing. An easy way to 14 | % increase accuracy (in most practical applications) is to use finer grid. 15 | % 16 | % INPUTS 17 | % u - the function of x. Can be a matrix of independent rows, columns 18 | % associated with x (NOTE DIFFERENCE WITH DIFF.M, which is the matrix 19 | % of row diffs). 20 | % x - the grid (usually equal spacing) 21 | % 22 | % OUTPUTS 23 | % du2/dx2 - same size as inputs 24 | % 25 | % EXAMPLE 26 | % % Need to be careful using this with degrees vs radians: 27 | % x = 1:180; % degrees 28 | % % Must convert all inputs to the same grid 29 | % d2u = diff_centered2(sind(x),x*pi/180); 30 | % plot(x,cosd(x),'-bo'), hold on 31 | % plot(x,du,'r*') 32 | % 33 | % SEE ALSO 34 | % del2.m 35 | 36 | 37 | % 10 Feb 2017 38 | 39 | % Note: Might look into CFD notes for alternative methods if more accuracy 40 | % is needed, cf compact_finite_diff.m which uses Lele 92 method but needs 41 | % to be generalized 42 | 43 | 44 | % check for test case 45 | if strcmp('--t',u), test_case, return, end 46 | 47 | % Preallocate 48 | du2 = NaN(size(u)); 49 | x = repmat(x(:).',size(du2,1),1); 50 | 51 | % Get first point from formula found on internet (fd.pdf) 52 | % http://shahroodut.ac.ir/fa/download.php?id=1111113740 53 | % Right sided second order scheme 54 | du2(:,1) = ( 2*u(:,1) - 5*u(:,2) + 4*u(:,3) - u(:,4) ) ./ ((x(:,2)-x(:,1)).^2) ; 55 | 56 | % Centered Approximation, Eqn 1.13 57 | i = 2:(size(u,2)-1); 58 | du2(:,i) = ( u(:,i+1) - 2*u(:,i) + u(:,i-1) )./ (( x(:,i)-x(:,i-1)).^2) ; 59 | 60 | % Get last point 61 | % Left sided second order scheme 62 | i = size(u,2); 63 | du2(:,i) = ( 2*u(:,i) - 5*u(:,i-1) + 4*u(:,i-2) - u(:,i-3) ) ./ ((x(:,i)-x(:,i-1)).^2) ; 64 | 65 | 66 | 67 | end 68 | 69 | 70 | function test_case 71 | % FROM MATHWORKS: 72 | % Use the diff function to approximate partial derivatives with the syntax 73 | % Y = diff(f)/h, where f is a vector of function values evaluated over 74 | % some domain, X, and h is an appropriate step size. 75 | % 76 | % For example, the first derivative of sin(x) with respect to x is cos(x), 77 | % and the second derivative with respect to x is -sin(x). You can use diff 78 | % to approximate these derivatives. 79 | 80 | % Mathworks test, modified for matrix inputs 81 | % NOTE: diff(X), for a matrix X, is the matrix of row differences, 82 | % [X(2:n,:) - X(1:n-1,:)]. 83 | 84 | h = 0.001; % step size 85 | X = -pi:h:pi; % domain 86 | f = sin(X); % range 87 | f = [f; f; f;]; 88 | 89 | 90 | x = 1:180; % degrees 91 | 92 | % Must convert all inputs to the same grid 93 | d2u = diff_centered2(sin(X),X); 94 | plot(X,-sin(X),'r*'), hold on 95 | plot(X,d2u,'-b.') 96 | 97 | % error is order 10e-8 98 | figure 99 | plot(X,abs(d2u+sin(X))) 100 | 101 | 102 | 103 | keyboard 104 | 105 | % this function 106 | d2f = diff_centered2(f,X); 107 | 108 | % looks good? 109 | h3 = plot(X,d2f,'-g.'); 110 | 111 | keyboard 112 | 113 | legend([h2(1) h1(1) h3(1)],'u(x)', 'du/dx','FEM version') 114 | 115 | 116 | % % COMPARE ERRORS? 117 | % figure 118 | % plot(df(1,:) - cos(X)), hold on 119 | % plot(Y(1,:) - cos(X(1:size(Y,2))),'-r.') 120 | 121 | 122 | 123 | 124 | 125 | % % TEST X NOTE 126 | % % sind converts x into radians, so the inputs need to be consistent? 127 | % 128 | % x = 1:0.01:180; 129 | % du = diff_centered(sind(x),x*pi/180); 130 | % plot(x,cosd(x),'-bo'), hold on 131 | % plot(x,du,'r*') 132 | % 133 | % keyboard 134 | 135 | % TEST 2 136 | % Laveque 2007, pg 4 137 | % Example 1.1. Let u(x) = sin(x) and x = 1; 138 | % thus we are trying to approximate u'(x 0:5403023. 139 | x = 1; 140 | u = sin(x); 141 | 142 | h = [1e-1, 5e-2, 1e-2, 5e-3, 1e-3]; 143 | 144 | disp('h D3') 145 | 146 | for i = 1:numel(h) 147 | 148 | t = [-2 -1 0 1 2]*h(i); 149 | 150 | du = diff_centered(sin(x + t), t); 151 | 152 | err(i) = 0.5403023 - du(3); 153 | 154 | % disp([num2str(h(i)) ' ' num2str(err)]) 155 | end 156 | 157 | % Compare with figure 1.2 158 | h1 = loglog(h,err,'-bo'); hold on 159 | 160 | h0 = loglog(h, [9.0005e-4 2.251e-4 9.005e-6 2.2513e-6 9.005e-8],'r*'); 161 | 162 | axis([1e-4 1 1e-10 1e-2]) 163 | 164 | legend('diff_centered.m','Laveque Fig 1.2') 165 | 166 | keyboard 167 | 168 | 169 | end -------------------------------------------------------------------------------- /tools/general/fileparts_name.m: -------------------------------------------------------------------------------- 1 | function fname = fileparts_name(fullcsq) 2 | % FILEPARTS NAME - get names only from list of full-path file names 3 | % inputs are generally a cell with full path to csq names 4 | % 5 | % see also fileparts_cell.m 6 | 7 | % TO DO 8 | % use cellfun! 9 | 10 | % check ins, 11 | if ischar(fullcsq) 12 | fullcsq = cellstr(fullcsq); 13 | end 14 | 15 | 16 | fname = cell(numel(fullcsq),1); 17 | 18 | for i = 1:numel(fullcsq) 19 | 20 | [~,fname{i},~] = fileparts(fullcsq{i}); 21 | 22 | end 23 | 24 | % this shouldn't do uniques 25 | % fname = unique(fname); 26 | 27 | end 28 | -------------------------------------------------------------------------------- /tools/general/fnames_to_times.m: -------------------------------------------------------------------------------- 1 | function t = fnames_to_times(flist,nmstr,dstr) 2 | % FILE NAMES TO TIMES - more generic version of fname2time 3 | % stime = fnames_to_times(flist,nmstr,dstr) 4 | % 5 | % INPUT 6 | % flist - cell list of file names, eg output of get_file_list.m 7 | % nmstr - part of file name to scrub off 8 | % dstr - date string format used in the name 9 | % 10 | % OUTPUT 11 | % stime - matlab serial time 12 | % 13 | % EXAMPLE 14 | % 15 | % flist = { '/Users/codar/Desktop/tot_2015_05_19.mat' 16 | % '/Users/codar/Desktop/tot_2015_05_25.mat'}; 17 | % 18 | % stime = fnames_to_times(flist,'tot_','yyyy_mm_dd') 19 | % 20 | % ANOTHER EXAMPLE 21 | % 22 | % % Custom code to match RDL_i*AGL1 for example (ie dont worry about RA) 23 | % nmstr = [RDLstr '.*' site '_'] 24 | % 25 | % % two sites in the list: 26 | % retimes = fnames_to_times(reflist,{'RDLe_ssd1_','RDLe_cop1_'},'yyyy_mm_dd_HHMM') 27 | 28 | 29 | 30 | % TO DO 31 | % make this a replacement for fname2time or a function that it calls 32 | % char input support 33 | % 34 | % Custom code to match RDL_i*AGL1 for example (ie dont worry about RA) 35 | % nmstr = [RDLstr '.*' site '_'] 36 | 37 | t = datenum(regexprep(fileparts_name(flist),nmstr,''),dstr); 38 | 39 | 40 | end -------------------------------------------------------------------------------- /tools/general/max_2d.m: -------------------------------------------------------------------------------- 1 | function [mx,r,c] = max_2d(x) 2 | % MAX 2D - find global max of a matrix 3 | % [mx,r,c] = max_2d(x) 4 | 5 | 6 | [cx,j] = max(x); 7 | 8 | [mx,c] = max(cx); 9 | 10 | r = j(c); 11 | 12 | end -------------------------------------------------------------------------------- /tools/general/short_cuts/w.m: -------------------------------------------------------------------------------- 1 | % W.M 2 | % w 3 | % short for whos.m (no relation to the current president) 4 | 5 | % a minor stroke of genius 6 | % Brian Emery 20jun06 7 | whos -------------------------------------------------------------------------------- /tools/general/strjust2.m: -------------------------------------------------------------------------------- 1 | function t = strjust(s,justify) 2 | %STRJUST Justify character array. 3 | % T = STRJUST(S) or T = STRJUST(S,'right') returns a right justified 4 | % version of the character array S. 5 | % 6 | % T = STRJUST(S,'left') returns a left justified version of S. 7 | % 8 | % T = STRJUST(S,'center') returns a center justified version of S. 9 | 10 | % Copyright (c) 1984-98 by The MathWorks, Inc. 11 | % $Revision: 1.5 $ $Date: 1997/11/21 23:47:38 $ 12 | 13 | if nargin<2, justify = 'right'; end 14 | 15 | if isempty(s), t = s; return, end 16 | 17 | % Find non-pad characters 18 | ch = (s ~= ' ' & s ~= 0); 19 | [r,c] = find(ch); 20 | [m,n] = size(s); 21 | 22 | % Determine offset 23 | switch justify 24 | case 'right' 25 | spa = sparse(c,r,c); 26 | offset = full(max(spa))'; 27 | offset = n-offset; 28 | case 'left' 29 | [dum,offset] = max(ch,[],2); 30 | offset = 1 - offset; 31 | case 'center' 32 | spa = sparse(c,r,c); 33 | offset1 = full(max(spa))'; 34 | [dum,offset2] = max(ch,[],2); 35 | offset = floor((n - offset1 - offset2 + 1)/2); 36 | end 37 | 38 | % Apply offset to justify character array 39 | newc = c + offset(r); 40 | t = repmat(' ',m,n); 41 | t(r + (newc-1)*m) = s(r + (c-1)*m); 42 | -------------------------------------------------------------------------------- /tools/general/strparser.m: -------------------------------------------------------------------------------- 1 | function fields = strparser(input_line,delimiter) 2 | % STRPARSER Break a string into tokens. 3 | % 4 | % Usage: 5 | % TOKENS = STRPARSER(STRING) 6 | % Create a char array TOKENS that contains the strings in STRING delimited 7 | % by a space. 8 | % 9 | % TOKENS = STRPARSER(STRING,DELIMITER) 10 | % TOKENS are the strings in STRING delimited by DELIMITER. 11 | % 12 | % EXAMPLE: 13 | % fields = strparser('now,or, later. Which is,it?',',') 14 | % 15 | % will produce: 16 | % fields = 17 | % 18 | % now 19 | % or 20 | % later. Which is 21 | % it? 22 | 23 | % Mike Cook, NPS Oceanography Dept., 21AUG98. 24 | % Modified from code on p.11-12 of USING MATLAB Version 5 manual. 25 | % Added strjust 'left' so that all blanks are on right of array. 26 | 27 | if nargin < 2 28 | delimiter = ' '; 29 | end 30 | 31 | remainder = input_line; 32 | fields = ''; 33 | 34 | while (any(remainder)) 35 | [chopped,remainder] = strtok(remainder,delimiter); 36 | fields = strvcat(fields,chopped); 37 | end 38 | 39 | fields = strjust2(fields,'left'); 40 | 41 | return 42 | -------------------------------------------------------------------------------- /tools/general/struct/field_check.m: -------------------------------------------------------------------------------- 1 | function field_check(D,flds) 2 | % FIELD CHECK - check for presence of needed fields in input structures 3 | % field_check(D,flds) 4 | % 5 | % Stops mfile execution and returns an error if needed fields are not 6 | % found. Designed to be called by functions with structure inputs. 7 | 8 | % Copyright (C) 2010 Brian Emery 9 | % 2 Mar 10 10 | 11 | % [st,i] = dbstack 12 | 13 | % Check for critical fields 14 | if any(~isfield(D,flds)) 15 | error('Critical Structure Fields not found') 16 | end 17 | 18 | end 19 | -------------------------------------------------------------------------------- /tools/general/struct/struct_pack.m: -------------------------------------------------------------------------------- 1 | function M = struct_pack(fn,M) 2 | % STRUCT PACK - move varibles into structure 3 | % S = struct_pack(varibles, S) 4 | % 5 | % INPUT 6 | % cell array with names of variables, and 7 | % (optionally) the struct to append to 8 | % 9 | % EXAMPLE 10 | % B = who; 11 | % B = struct_pack(setdiff({B.name},'S')); 12 | % 13 | % - or - 14 | % B = struct_pack(who); 15 | % 16 | % see also: struct_unpack, substruct_unpack 17 | 18 | % Copyright (C) 2010 Brian M. Emery 19 | 20 | if nargin < 2, M = []; 21 | 22 | else 23 | fn = setdiff(fn,inputname(2)); 24 | end 25 | 26 | for i = 1:numel(fn) 27 | try 28 | M.(fn{i}) = evalin('caller',fn{i}); 29 | catch 30 | disp([mfilename ': ' fn{i} ' not packed: not found?']) 31 | end 32 | end 33 | 34 | 35 | end -------------------------------------------------------------------------------- /tools/general/struct/struct_unpack.m: -------------------------------------------------------------------------------- 1 | function struct_unpack(varargin) 2 | % STRUCT UNPACK - move structure contents to workspace as variables 3 | % struct_unpack(R) 4 | % Allow for multiple structure inputs, eg struct_unpack(S,R,MET), etc. 5 | % 6 | % see also: struct_pack, substruct_unpack 7 | 8 | % Copyright (C) 2010 Brian M. Emery 9 | 10 | % NOTE 11 | % ASSIGNIN Assign variable in workspace. 12 | % ASSIGNIN(WS,'name',V) assigns the variable 'name' in the 13 | % workspace WS the value V. WS can be one of 'caller' or 'base'. 14 | 15 | for j = 1:numel(varargin) 16 | 17 | % get the structure 18 | R = varargin{j}; 19 | 20 | % get the field names 21 | try 22 | fn = fieldnames(R); 23 | 24 | if ~isempty(fn) 25 | for i = 1:numel(fn) 26 | assignin('caller',fn{i},R.(fn{i})) 27 | end 28 | end 29 | 30 | catch 31 | end 32 | end 33 | end -------------------------------------------------------------------------------- /tools/general/struct/subsref_struct.m: -------------------------------------------------------------------------------- 1 | function S = subsref_struct(S,idx,n,rc,fn) 2 | % SUBSREF STRUCT - apply indexing to fields in a structure 3 | % S = subsref_struct(S,i,n,rc,fn) 4 | % 5 | % Applies the indexing given in i, of the fields in S that have the 6 | % matching number of columns (n). Given a 4th input will apply the 7 | % indexing to the rows (1). Defaults to columns (rc = 2). Cell arrays 8 | % are now included, and input index array can be logical. 5th input can 9 | % be a cell list of fields to skip over. 10 | % 11 | % Recurses into substructures looking for fields of the same size to apply 12 | % the indexing to as well. 13 | % 14 | % Example: 15 | % % Create a structure with mixed fields, array and structure 16 | % d.lon = ones(5,1)*[1:10]; 17 | % d.lat = ones(5,1)*[1:10]; 18 | % d.time = 1:10; 19 | % d.strct = d; 20 | % 21 | % % Change the column indexing 22 | % d = subsref_struct(d,2:5,size(d,2),2) 23 | % 24 | % % Change the row indexing 25 | % d = subsref_struct(d,1:2,size(d,1),1) 26 | % 27 | % SEE ALSO 28 | % work_fields.m 29 | 30 | % Copyright (C) 2010 Brian M. Emery 31 | % Brian Emery 12 Jan 2010 32 | % from subsrefTUV.m 33 | 34 | % TO DO 35 | % - maybe a special case when indexing applies to whole matrix ...? 36 | % - should apply to cells also 37 | % - recursion? 38 | % - allow 3 inputs, last input is a size(X) and apply indexing to everyting 39 | % size(X) 40 | % - use structfun? might be a lot faster 41 | 42 | if strcmp(S,'--t'), test_case, return, end 43 | 44 | % don't skip any by default 45 | if nargin < 5 46 | fn = ''; 47 | end 48 | 49 | % Apply to columns by default 50 | if nargin < 4 51 | rc = 2; 52 | end 53 | 54 | % Sort out indexing for each case 55 | if rc == 2; 56 | rows = ':'; cols = idx; 57 | elseif rc == 1; 58 | rows = idx; cols =':'; 59 | end 60 | 61 | % % Recurse if multi-element 62 | % if numel(S)>1, S = struct_recursion(@subsref_struct,S,idx,n,rc); return, end 63 | 64 | 65 | % % < --- possible future case with absolute indexing 66 | % elseif rc == 0 67 | % [i,k] = ind2sub(size(),i); % <---- 68 | 69 | 70 | % Get field names to loop over 71 | nm = fieldnames(S); 72 | 73 | % % experiment to make this faster, get only the field names we want to 74 | % % operate on ... actualy makes it slower. The anon function seems to be the 75 | % % problem 76 | % sz = structfun(@(x) ( size(x,rc) ),S); 77 | % 78 | % nm = nm(sz == n); 79 | 80 | % detect char and struct arrays and skip them 81 | s1 = structfun(@ischar,S); 82 | s2 = structfun(@isstruct,S); 83 | 84 | nm = nm(~s1 & ~s2); 85 | 86 | % skip any named fields 87 | nm = setdiff(nm,fn); 88 | 89 | 90 | for j = 1:numel(nm) 91 | 92 | % keyboard 93 | % 94 | % Apply indexing to numeric or cell fields matching the correct number 95 | % of elements (rows or columns) 96 | if size(S.(nm{j}),rc) == n % && ( isnumeric(S.(nm{j})) || iscell(S.(nm{j})) || islogical(S.(nm{j})) ) 97 | 98 | S.(nm{j}) = S.(nm{j})(rows,cols); 99 | 100 | 101 | % % Recurse into sub-structures if they are numel == 1 102 | % elseif isstruct(S.(nm{j})) && numel(S.(nm{j})) == 1 103 | % 104 | % S.(nm{j}) = subsref_struct(S.(nm{j}),idx,n,rc); 105 | % 106 | end 107 | end 108 | 109 | % experitment: recurse here 110 | if any(s2) 111 | nm = fieldnames(S); % list was shortened above 112 | nm = nm(s2); 113 | 114 | for i = 1:numel(nm) 115 | if numel(S.(nm{i})) == 1 116 | S.(nm{i}) = subsref_struct(S.(nm{i}),idx,n,rc,fn); 117 | end 118 | end 119 | 120 | end 121 | 122 | 123 | 124 | % % Optionally add documentation 125 | % if isfield(S,'ProcessingSteps') 126 | % S.ProcessingSteps{end+1} = mfilename; 127 | % end 128 | 129 | 130 | end 131 | % ------------------------ 132 | function test_case 133 | % Other tests needed? pass fail test ...? 134 | % 135 | 136 | % % RECURSION TEST 137 | % load /Data/testData/subsref_struct.mat 138 | % 139 | % [~,t,j]=intersect(RDL.TimeStamp,round(DRFT.TimeStamp.*24)./24); clear j 140 | % 141 | % R = subsref_struct(RDL,t,size(RDL.TimeStamp,2),2); 142 | % keyboard 143 | 144 | 145 | % ROBUST TEST 146 | % Example FOR MATHWORKS : 147 | % Create a structure with mixed fields, array and structure 148 | d.lon = ones(7,1)*(1:10); 149 | d.lat = ones(7,1)*(1:10); 150 | d.time = 1:10; 151 | d.strct = d; 152 | d.ProcessingSteps = {'blahblah'}; 153 | d.cellTst = cellstr(num2str([1:7]')) 154 | 155 | disp(' Change the column indexing') 156 | f = subsref_struct(d,2:5,10,2) 157 | 158 | disp(' Change the column indexing') 159 | f = subsref_struct(d,2:5,10) 160 | 161 | disp(' Change the row indexing') 162 | f = subsref_struct(d,[5 7],7,1) 163 | 164 | keyboard 165 | 166 | end 167 | 168 | % ---------------------------------------------------------- 169 | % Additionally ... 170 | function B = subsref_local(B,r,c,flds) 171 | % SUBSREF LOCAL - local version of subscript reference 172 | % Add this as a subfunction to clean up all the loops over fields. This 173 | % applies the indexing in r, c to all fields listed in flds cell. 174 | % 175 | % at 181: 176 | % % RDL = subsref_local(RDL,cat(2,sflds,flds),r,c); 177 | % 178 | % Note r or c can be ':' for all rows or columns. 179 | 180 | if nargin < 4 181 | flds = fieldnames(B); 182 | end 183 | 184 | for i = 1:numel(flds) 185 | B.(flds{i}) = B.(flds{i})(r,c); 186 | end 187 | 188 | end 189 | 190 | -------------------------------------------------------------------------------- /tools/maps/bathymetry/c_line.m: -------------------------------------------------------------------------------- 1 | function Cline=c_line(lon,lat,data,level) 2 | 3 | % C_LINE.M 4 | % [Cline]=c_line(x,y,z,level) 5 | % Outputs 'Cline', the x and y positions 6 | % of a given contour line given in 'level' so that the data 7 | % can be used with 'plot' to plot the contour. The x,y 8 | % inputs must be vectors describing the positions of the 9 | % data given in the matrix z, as in the 'contour' function. 10 | % 11 | % example: 12 | % load c:\data\bathymetry\sbcsmb.mat 13 | % [d200]=c_line(lon,lat,depth,200); 14 | % plot(d200(:,1),d200(:,2)) 15 | % 16 | % See code at the end of sbgrid2.m for creating contourable 17 | % matricies on the HF grid. 18 | 19 | % try [d700]=c_line(lon',lat,depth,700); with sbcsmb_lo.mat 20 | 21 | % Brian Emery 16Apr99 22 | 23 | % compute the contour matrix 24 | C = contourc(lon,lat,data,[level level]); 25 | 26 | % define m, the index of the contour level in C(see help contourc) 27 | m=find(C(1,:)==level); 28 | 29 | Cline=C; 30 | Cline(:,m)=NaN; 31 | Cline=Cline'; 32 | 33 | return 34 | 35 | % this quickly makes a bathy data set 36 | %for i=[700:100:1000 1200:200:3600]; 37 | for i=[325:50:500]; 38 | x=num2str(i); 39 | eval(['[d' x ']=c_line(lon,lat,depth'',' x ');']) 40 | eval(['plot(d' x '(:,1),d' x '(:,2),''b'')']), hold on 41 | 42 | end -------------------------------------------------------------------------------- /tools/maps/mercat.m: -------------------------------------------------------------------------------- 1 | function [Axis_factor, Scale_factor] = mercat(lons,lats) 2 | 3 | %MERCAT mercator scaling factors for axes 'AspectRatio' parameter. 4 | % This function will calculate scale factors to be used in the axes 5 | % command option 'AspectRatio' to produce mercator projection plots. 6 | % The latitude used to scale the longitudinal distance is simply 7 | % the midpoint of the 2 input latitudes. 8 | % 9 | % The format is as follows: 10 | % [Axis_factor, Scale_factor] = mercat(lons,lats) 11 | % 12 | % input: 13 | % lons is a 2 element vector - [minimum lon, maximum lon] 14 | % lats is a 2 element vector - [minimum lat, maximum lat] 15 | % 16 | % output: 17 | % Axis_factor - scalar 18 | % Scale_factor - scalar 19 | % 20 | % usage example: 21 | % axes(... ,'AspectRatio',[Axis_factor,Scale_factor], ...) 22 | % 23 | % See the "axes" command discussion in the MATLAB Reference Guide 24 | % for more information on AspectRatio. 25 | % 26 | 27 | % Mike Cook - NPS Oceanography Dept. - Oct 93 28 | % Added error statements Mar 94 29 | 30 | if nargin ~= 2 31 | error(' Must supply 2 element longitude and latitude vectors ... type help mercat') 32 | end 33 | if length(lons) ~= 2 | length(lats) ~= 2 34 | error(' Must supply 2 element longitude and latitude vectors ... type help mercat') 35 | end 36 | 37 | lat_mid = (lats(2) + lats(1)) / 2; 38 | Scale_factor = cos((lat_mid*pi)/180); 39 | 40 | Axis_factor = ( (lons(2) - lons(1)) / (lats(2) - lats(1)) ) * Scale_factor; 41 | 42 | -------------------------------------------------------------------------------- /tools/plotting/colorbar_label.m: -------------------------------------------------------------------------------- 1 | function colorbar_label(str,h) 2 | % COLORBAR LABEL.M 3 | % colorbar_label(str,h) 4 | % 5 | % INPUTS 6 | % str - string to use as label 7 | % h - optional colobar handle 8 | 9 | % Copyright (C) 2019 Brian Emery 10 | 11 | % Notes about changeing colorbar labels: 12 | % 13 | % h=colorbar; 14 | % set(get(h,'Ylabel'),'String','^oC','Rotation',0) 15 | 16 | if nargin < 2 17 | h = findobj('Tag','Colorbar'); 18 | end 19 | 20 | if ~isempty(h) 21 | % old way 22 | % set(get(y,'Ylabel'),'String','WindU Variance (cm^2s^-^2)') 23 | h(1).Label.String = str; 24 | 25 | end 26 | 27 | end -------------------------------------------------------------------------------- /tools/plotting/colorbar_my.m: -------------------------------------------------------------------------------- 1 | function cbar = colorbar_my(ax) 2 | % COLORBAR MY - add colorbar, keep axes in same place 3 | % h = colobar_my 4 | % 5 | % label it too: set(get(h,'Ylabel'),'string','Log_1_0(K_z)') 6 | 7 | 8 | 9 | if nargin < 1, ax = gca; end 10 | pos = get(ax,'position'); 11 | cbar = colorbar('peer',ax); 12 | set(ax,'position',pos) 13 | axes(ax) 14 | 15 | % move colorbar to just outside of right axis 16 | cb_pos = get(cbar,'position'); 17 | set(cbar,'position',[pos(1)+pos(3) cb_pos(2:end)]) 18 | 19 | end -------------------------------------------------------------------------------- /tools/plotting/errorbarx.m: -------------------------------------------------------------------------------- 1 | function h = errorbarx(x, y, l,u,symbol) 2 | % ERRORBARX.M 3 | % Same as Errorbar.m except the bar is drawn in x instead of y, 4 | % and the errorbars only overplot onto an existing plot. 5 | % 6 | % Help for regular errorbar: 7 | % 8 | % ERRORBAR(X,Y,L,U) plots the graph of vector X vs. vector Y with 9 | % error bars specified by the vectors L and U. L and U contain the 10 | % lower and upper error ranges for each point in Y. Each error bar 11 | % is L(i) + U(i) long and is drawn a distance of U(i) above and L(i) 12 | % below the points in (X,Y). The vectors X,Y,L and U must all be 13 | % the same length. If X,Y,L and U are matrices then each column 14 | % produces a separate line. 15 | % 16 | % ERRORBAR(X,Y,E) or ERRORBAR(Y,E) plots Y with error bars [Y-E Y+E]. 17 | % ERRORBAR(...,'LineSpec') uses the color and linestyle specified by 18 | % the string 'LineSpec'. The color is applied to the data line and 19 | % error bars while the linestyle and marker are applied to the data 20 | % line only. See PLOT for possibilities. 21 | % 22 | % ERRORBAR(AX,...) plots into AX instead of GCA. 23 | % 24 | % H = ERRORBAR(...) returns a vector of errorbarseries handles in H. 25 | % 26 | % For example, 27 | % x = 1:10; 28 | % y = sin(x); 29 | % e = std(y)*ones(size(x)); 30 | % errorbar(x,y,e) 31 | % draws symmetric error bars of unit standard deviation. 32 | % 33 | % Reference page in Help browser 34 | % doc errorbar 35 | % 36 | % NOTE 37 | % typically the errorbar's full span shows 2 SD, encompasing ~66% of the 38 | % data, so data +/- sigma 39 | 40 | % Changes made 6jun96 - Brian Emery 41 | 42 | if min(size(x))==1, 43 | npt = length(x); 44 | x = x(:); 45 | y = y(:); 46 | if nargin == 3, 47 | l = l(:); 48 | elseif nargin == 4 | nargin == 5 49 | l = l(:); 50 | u = u(:); 51 | end 52 | else 53 | [npt,n] = size(x); 54 | end 55 | 56 | if nargin == 3, 57 | u = l; 58 | end 59 | 60 | if nargin ~= 5 61 | symbol = '-'; 62 | end 63 | 64 | if nargin == 2 65 | l = y; 66 | u = y; 67 | y = x; 68 | [m,n] = size(y); 69 | x(:) = [1:npt]'*ones(1,n);; 70 | end 71 | if isstr(x) | isstr(y) | isstr(l) | isstr(u) 72 | error('Arguments must be numeric.') 73 | end 74 | 75 | if any(size(x)~=size(y)) | any(size(x)~=size(l)) | any(size(x)~=size(u)), 76 | error('The sizes of X, Y, L and U must be the same.'); 77 | end 78 | 79 | % % This is how matlab did it, which is fine usually 80 | % tee = (max(y(:))-min(y(:)))/100; % make tee .02 y-distance for error bars 81 | % ... but for layering you get different size tee's. So base it on the axis 82 | % instead 83 | a = axis; tee = 1.5 .* (a(4)-a(3))/100; % was 3.5 84 | 85 | yl = y - tee; 86 | yr = y + tee; 87 | n = size(x,2); 88 | 89 | % Plot graph and bars 90 | cay = newplot; 91 | next = lower(get(cay,'NextPlot')); 92 | % build up nan-separated vector for bars 93 | xb = []; 94 | yb = []; 95 | nnan = nan*ones(1,n); 96 | for i = 1:npt 97 | xtop = x(i,:) + l(i,:); 98 | xbot = x(i,:) - u(i,:); 99 | yb = [yb; y(i,:); y(i,:) ; nnan; yl(i,:);yr(i,:);nnan ;yl(i,:);yr(i,:);nnan]; 100 | xb = [xb; xtop;xbot;nnan;xtop;xtop;nnan;xbot;xbot;nnan]; 101 | end 102 | 103 | h = plot(xb,yb,symbol); 104 | 105 | 106 | end 107 | -------------------------------------------------------------------------------- /tools/plotting/legend_append.m: -------------------------------------------------------------------------------- 1 | function legh = legend_append(h,cel,opt) 2 | % LEGEND APPEND - append to existing legend 3 | % legh = legend_append(h,cel,opt) 4 | % 5 | % h = new plot object handles 6 | % cel = cell array of assoc labels 7 | % opt = 1 to add to top of legend (defaults to 0) 8 | % 9 | % based on addTextLikeLegend 10 | 11 | % Copyright (C) 2010 Brian Emery 12 | % 4Feb2010 13 | 14 | if nargin<3, opt=0; end 15 | 16 | if ischar(cel), cel = cellstr(cel); end 17 | 18 | 19 | % get info if there is a pre-existing legend: (outm is cell) 20 | [legh,objh,outh,outm] = legend; 21 | 22 | % if no legend, make outm a cell 23 | if isempty(outm), outm ={}; end 24 | 25 | % create legend inputs 26 | if opt 27 | hh=[h(:); outh]; 28 | inArray={cel{:} outm{:}}; 29 | else 30 | hh=[outh; h(:)]; 31 | inArray={outm{:} cel{:}}; 32 | end 33 | 34 | legh=legend(hh,inArray); 35 | 36 | 37 | end -------------------------------------------------------------------------------- /tools/plotting/line_colors.m: -------------------------------------------------------------------------------- 1 | function c = line_colors 2 | % LINE COLORS - get default line colors 3 | % c = line_colors .... or just use line.m from TMW 4 | % 5 | % c = [ 0 0.4470 0.7410 6 | % 0.8500 0.3250 0.0980 7 | % 0.9290 0.6940 0.1250 8 | % 0.4940 0.1840 0.5560 9 | % 0.4660 0.6740 0.1880 10 | % 0.3010 0.7450 0.9330 11 | % 0.6350 0.0780 0.1840] 12 | % 13 | % blue, orange, yellow, purple, green, light blue, maroon 14 | % 15 | % SEE ALSO 16 | % parula, eg: 17 | % clr = colormap_parula(10); 18 | % figure, for i=1:10, plot([0 1],[i i],'-','Color',clr(i,:),'LineWidth',8), hold on, end 19 | 20 | 21 | c = [ 0 0.4470 0.7410 22 | 0.8500 0.3250 0.0980 23 | 0.9290 0.6940 0.1250 24 | 0.4940 0.1840 0.5560 25 | 0.4660 0.6740 0.1880 26 | 0.3010 0.7450 0.9330 27 | 0.6350 0.0780 0.1840]; 28 | 29 | 30 | end -------------------------------------------------------------------------------- /tools/plotting/makesubplots.m: -------------------------------------------------------------------------------- 1 | function [haxes]=makesubplots(nrows,ncols,sh,sv,varargin) 2 | % MAKE SUBPLOTS - closely spaced subplots 3 | % 4 | % [HAXES] = makesubplots(NROWS,NCOLS,sh,sv,extras) 5 | % 6 | % Sets up an NROWS by NCOLS array of closely-spaced subplots in the 7 | % current window. Returns a length NCOLS*NROWS vector HAXES of handles 8 | % to the axes in column-wise order. SH and SV are the normalized 9 | % spacing between subplots. 10 | % NOTE: sh=sv=0.01 for axes without labels 11 | % sh=sv=0.1 for axes with labels 12 | % 13 | % EXAMPLE: 14 | % Make 7 plots on one figure (arranged in 7 rows and 1 column wide): 15 | % 16 | % % Create the subplot axes 17 | % % and add whatever you want to plot to it: 18 | % hx = makesubplots(7,1,.05,.05); 19 | % h = plot(hx(1), doy, WS, ln); 20 | % 21 | % % Add letter (see subplot_add_letters.m! run it outside the loop) 22 | % subplot_add_letters(hx) 23 | % 24 | % % Instead of axes.m, use: 25 | % set(gcf,'CurrentAxes',hx(2)) 26 | % 27 | % 28 | % SUPPORTS FRACTIONAL SUBPLOT SIZES 29 | % EXAMPLE: 30 | % % Fractions total to 1 31 | % hx = makesubplots(9,2,.04,.03, [1/9*ones(1,6) .5/9 1/9 1.5/9]); 32 | 33 | 34 | 35 | 36 | % Bill Shaw's code 37 | % Modified 8 Feb 2010 by Brian Emery 38 | % - added fraction plot options 39 | 40 | % TO DO: 41 | % varargin bw compatible, expand to width subplots (?), check inputs ... 42 | % spacing between plots should be same in fractional case (right now its 43 | % a function of the plot height which changes ..) 44 | % 45 | % Need to be able to set fractional width also 46 | % 47 | % automate adding letters to the plots, use this: 48 | % char(97:97+25) 49 | 50 | extras = {}; 51 | 52 | % define borders 53 | bh = 0.075; %0.125; %0.075; 54 | bv=0.075; 55 | 56 | % if length(varargin) 57 | % if ~isempty(varargin{1}) 58 | % bh = varargin{1}; 59 | % end 60 | % end 61 | % if length(varargin)>2 62 | % if ~isempty(varargin{1}) 63 | % bv = varargin{2}; 64 | % end 65 | % end 66 | % if length(varargin)>2 67 | % extras = varargin(3:end); 68 | % end 69 | 70 | 71 | 72 | % define borders and cells and spacing 73 | wcell=(1-2*bh)/ncols; 74 | 75 | if ~isempty(varargin) 76 | hfrac = varargin{1}; % height fraction totaling 1 77 | hcell = (1-2*bv)*hfrac; 78 | else 79 | hcell=(1-2*bv)./(nrows*ones(1,nrows)); 80 | end 81 | 82 | % create matrix of handles 83 | haxes = zeros(nrows,ncols); 84 | 85 | % % hack to allow variable horiz spacing 86 | % if length(sh) == 1, sh = sh*ones(1,ncols); end 87 | 88 | for j=1:ncols; 89 | 90 | 91 | for i=1:nrows 92 | 93 | % compute address 94 | k = (j-1)*nrows+i; 95 | 96 | % define the axes position (left bottom width height) 97 | % and Add in spacing between plots 98 | lbwh = [ (j-1)*wcell + bh + sh*wcell, ... 99 | (1-bv)-(sum(hcell(1:i))) + sv*hcell(i), ... 100 | wcell - 2*sh*wcell, ... 101 | hcell(i) - 2*sv*hcell(i)]; 102 | 103 | haxes(i,j)=axes('Units','Normalized','Position',lbwh); 104 | 105 | % % add letter to plot 106 | %text(.015,0.92,[char(96+k) ')'],'units','normalized') 107 | end 108 | end 109 | 110 | set(haxes,'Box','On','NextPLot','Add',extras{:}) 111 | 112 | end -------------------------------------------------------------------------------- /tools/plotting/plot_struct.m: -------------------------------------------------------------------------------- 1 | function [hx,h] = plot_struct(S,xstr,fn,LS,hx) 2 | % PLOT STRUCT - plotting template for structures 3 | % [hx,hdl] = plot_struct(S,xstr,fn,LS) 4 | % 5 | % Makes line plots of data in structure, such as timeseries, etc. 6 | % 7 | % INPUTS 8 | % S - data structure 9 | % xstr - x axis field name string 10 | % fn - cell of field names to plot on y axis (multi element for subplots) 11 | % LS - line style structure(s), see line_style_groups.m 12 | % hx - optional axes handles to previous use of plot_struct 13 | % 14 | % If units and a LABS fields are found, these are used to label the axes 15 | % ** need to specify these and standardize 16 | % 17 | % EXAMPLE 18 | % md = '/projects/drifter_experiment_ssd/data/seasonde_day6/' 19 | % apm_file = [md 'RadialConfigs/MeasPattern.txt']; 20 | % APM = load_pattern_file(apm_file); 21 | % M = interp_apm(APM,min(APM.BEAR):0.1:max(APM.BEAR)); 22 | % 23 | % LS = get_linestyles(8); 24 | % [hx,hdl] = plot_struct(APM,'BEAR',{'A13I','A13R','A23I','A23R'},LS(1)); 25 | % hold on 26 | % LS(2).Marker = '.' 27 | % LS(2).LineStyle = 'none'; 28 | % [hx,hdl] = plot_struct(M,'BEAR',{'A13I','A13R','A23I','A23R'},LS(2),hx); 29 | % 30 | % figure 31 | % [hx,hdl] = plot_struct(APM,'BEAR',{'A13M','A13P','A23M','A23P'},LS(1)); 32 | % hold on 33 | % [hx,hdl] = plot_struct(M,'BEAR',{'A13M','A13P','A23M','A23P'},LS(2),hx); 34 | % 35 | % 36 | % see also: saveFig.m 37 | 38 | % Copyright (C) 2011 Brian M. Emery 39 | % 10 Nov 2011 40 | 41 | % TO DO 42 | % add legends? 43 | % modify figure name 44 | % test cases 45 | % generate the code to make the plot 'by hand' 46 | 47 | % check inputs, 48 | if ischar(fn) 49 | fn = cellstr(fn); 50 | end 51 | 52 | 53 | % get line styles if not given 54 | if nargin <4, 55 | LS = get_linestyles(numel(fn)); 56 | end 57 | 58 | if numel(fn) > numel(LS) 59 | [LS(1:numel(fn))] = deal(LS); 60 | end 61 | 62 | 63 | % MAIN PLOTTING 64 | 65 | if nargin < 5 66 | 67 | figure 68 | hx = makesubplots(numel(fn),1,.05,.05); 69 | 70 | % add letter 71 | subplot_add_letters(hx) %,0.035,0.85) 72 | 73 | end 74 | 75 | for i = 1:numel(fn) 76 | 77 | % plot data 78 | h{i} = plot(hx(i), S.(xstr), S.(fn{i}), LS(i)); hold on 79 | 80 | % label using field name (try units also) 81 | set_ylabel(hx(i),S,fn{i}) 82 | 83 | % axes labels on bottom only 84 | if i < numel(fn) 85 | set(hx(i),'XTickLabel','') 86 | end 87 | 88 | end 89 | 90 | 91 | % set y limits automatically 92 | set_ylims_auto(hx) 93 | 94 | % set plot size and fonts, etc 95 | publicationStandards 96 | 97 | 98 | 99 | 100 | end 101 | 102 | function set_ylabel(hx,S,fn) 103 | % SET YLABEL 104 | % try to use Units field, or LABS 105 | 106 | % set default first 107 | lab = fn; 108 | 109 | % try several ways of storing units info (this is getting messy) 110 | if isfield(S,'Units') && ~isfield(S,'LABS') 111 | try lab = [fn ' ' S.Units.(fn)]; catch E, end 112 | 113 | elseif isfield(S,'LABS') 114 | 115 | % label storage standard 116 | try lab = [fn ' ' S.LABS.(fn)]; catch E, end 117 | 118 | % label storage used in Sally project code 119 | try lab = [fn ' ' S.LABS.(fn).u]; catch E, end 120 | 121 | % label storage used by ctfReader.m and related 122 | try lab = [S.LABS.(fn){:} '' S.Units.(fn){:} ]; catch E, end 123 | 124 | 125 | end 126 | 127 | ylabel(hx,lab) 128 | 129 | end 130 | 131 | function LS = get_linestyles(n) 132 | % GET LINESTYLES 133 | % 134 | % This might be the best way to do this, use the field name as the string 135 | % THIS IS HOW WE DO IT 136 | % takes advantage of structure inputs to plot!!! 137 | 138 | % LINE STYLE SETTINGS 139 | 140 | % % defaults 141 | % LS(1).Color = 'k'; 142 | % LS(1).Marker = '.'; 143 | % % LS(1).MarkerFaceColor = 'w'; 144 | % % LS(1).MarkerEdgeColor = 'k'; 145 | % LS(1).LineStyle = '-'; 146 | % % LS(1).MarkerSize = 6; 147 | % 148 | % LS(1).Color = 'k'; 149 | % LS(1).Marker = 'o'; 150 | % LS(1).MarkerFaceColor = [.8 .8 .8]; %'w'; 151 | % LS(1).MarkerEdgeColor = 'k'; 152 | % LS(1).LineStyle = 'none'; 153 | % LS(1).MarkerSize = 4; 154 | % 155 | % [LS(1:n)] = deal(LS(1)); 156 | % 157 | % LS(2).Color = 'r'; 158 | % LS(2).Marker = '.'; 159 | % LS(2).MarkerFaceColor = 'r'; 160 | % LS(2).MarkerEdgeColor = 'r'; 161 | 162 | c = line_colors; 163 | ls = {'*','s','o','^','d','+','x'}; 164 | 165 | 166 | for i = 1:min([n numel(ls)]) 167 | 168 | LS(i).Color = c(i,:); 169 | LS(i).Marker = ls{i}; 170 | LS(i).MarkerSize = 6; 171 | LS(i).MarkerFaceColor = c(i,:); 172 | LS(i).MarkerEdgeColor = c(i,:); 173 | LS(i).LineStyle = '-'; 174 | LS(1).LineWidth = 0.5000; 175 | 176 | end 177 | 178 | 179 | 180 | end 181 | 182 | function LABS = get_y_info 183 | % EXAMPLE 184 | 185 | % FIGURE 2 186 | 187 | LABS.LE_0900.y = 'LE ';%_0_9_0_0'; 188 | LABS.LE_0900.u = '(W m^-^2)'; 189 | LABS.LE_0900.y_lim = [-350 0]; 190 | 191 | LABS.SE_0900.y = 'SE ';%_0_9_0_0'; 192 | LABS.SE_0900.u = '(W m^-^2)'; 193 | LABS.SE_0900.y_lim = [-40 10]; 194 | 195 | LABS.LWNet_0900.y = 'LWNet ';%_0_9_0_0'; 196 | LABS.LWNet_0900.u = '(W m^-^2)'; 197 | LABS.LWNet_0900.y_lim = [-100 -10]; 198 | 199 | 200 | end 201 | 202 | -------------------------------------------------------------------------------- /tools/plotting/set_ylims_auto.m: -------------------------------------------------------------------------------- 1 | function set_ylims_auto(hx) 2 | % SET YLIMS AUTO - set figure y limits based on data 3 | % set_ylims_auto(hx) 4 | % 5 | % Given axes handle(s) sets the y limits of the plot based on the data 6 | % contained on the figure. 7 | 8 | % Copyright(C) 2011 Brian Emery 9 | % 11 Nov 2010 10 | % 11 Nov 2011 - refactored, generalized 11 | 12 | % TO DO 13 | % - build test case, with multiple lines on the plot 14 | % - option for subplots to have same (max) ylims 15 | % see vic_climate_fluxes_noaa_summary_figure for a later modification 16 | 17 | for i = 1:numel(hx) 18 | 19 | try 20 | 21 | % % get all x and y data that went into the plot 22 | % S = get(get(hx(i),'Children')); 23 | % 24 | % % concatenate it 25 | % x = [S.XData]; 26 | % y = [S.YData]; 27 | 28 | % get all x and y data that went into the plot 29 | [x,y] = get_data(hx(i)); 30 | 31 | 32 | % get current xlimits 33 | xlims = get(hx(i),'xlim'); 34 | 35 | % find y values of data between x limits (visible data) 36 | ix = find( x > xlims(1) & x < xlims(2) ); 37 | 38 | % limit y data 39 | y = y(ix); 40 | 41 | % add 10% to final plot y limits 42 | dy = 0.05*diff([min(y) max(y)]); 43 | 44 | % try to set the limits 45 | ylims = [min(y)-dy max(y)+dy]; 46 | 47 | if all(~isnan(ylims)) 48 | set(hx(i),'ylim',ylims) 49 | end 50 | 51 | catch err 52 | 53 | 54 | % display cause of any errors 55 | %keyboard 56 | disp([mfilename,':', err.message]) 57 | 58 | end 59 | 60 | 61 | end 62 | 63 | % OLD WAY - pretty cool 64 | % 65 | % set_ylims(hx(1), {D.temp}) 66 | % 67 | % function set_ylims(hx,y) 68 | % % SET YLIMS - dynamically set ylimits 69 | % % 70 | % % 71 | % % get ymax (either 21 or max of stuff in D, +1) 72 | % % This is just a fancy way to concat D.temp outputs 73 | % 74 | % % S = get(get(hx,'Children')); 75 | % % S(1) 76 | % 77 | % try 78 | % ymax = max(cellfun(@max,y))+0.75; 79 | % ymin = min(cellfun(@min,y))-0.75; 80 | % 81 | % catch % R2007 format 82 | % disp('ylim setting error') 83 | % ymax = 20; ymin = 10; 84 | % end 85 | % 86 | % set(hx,'ylim',[ymin ymax]) 87 | % 88 | % end 89 | % 90 | % 91 | 92 | 93 | end 94 | 95 | function [x,y] = get_data(hx) 96 | % get all x and y data that went into the plot 97 | 98 | % STUCK 99 | % hard to separate the legend objects from the data objects ... needs more 100 | % work 101 | 102 | % get handles of all figure objects 103 | hdls = get(hx,'Children'); 104 | 105 | % get just the data handles 106 | str = get(hdls,'Type'); 107 | 108 | % get the struct containing object data 109 | S = get(hdls(strcmp('line',str))); 110 | 111 | 112 | % concatenate it 113 | x = [S.XData]; 114 | y = [S.YData]; 115 | 116 | end 117 | 118 | -------------------------------------------------------------------------------- /tools/plotting/subplot_add_letters.m: -------------------------------------------------------------------------------- 1 | function subplot_add_letters(ax,x,y) 2 | % SUBPLOT ADD LETTERS - add letters to subplots 3 | % subplot_add_letters(ax, x, y) 4 | % 5 | % INPUT 6 | % ax - array of axes handles 7 | % 8 | % OPTIONAL INPUTS 9 | % % Set position relative to axes (these are default) 10 | % x = 0.05; 11 | % y = 0.9 ; 12 | % 13 | % EXAMPLE CUSTOMIZATION 14 | % % reposition the letter 'C' 15 | % h = findobj('String','C'); 16 | % pos = get(h,'Position'); 17 | % set(h,'Position',pos + [0 -25 0]) 18 | 19 | 20 | % Copyright(C) 2011 Brian Emery 21 | 22 | % TO DO 23 | % figure out how to pin this to the axes so that when they change the 24 | % letters float with the axes (see annotations) 25 | 26 | % abort if only one axis 27 | if length(ax) == 1, return, end 28 | 29 | % gca for use later 30 | h1 = gca; 31 | 32 | % get alphabet letters (lowercase) 33 | letter = char(97:97+25); 34 | 35 | if nargin < 2 36 | % Set position relative to axes 37 | x = 0.05; 38 | y = 0.9 ; 39 | 40 | end 41 | 42 | % get axes if not input 43 | if nargin < 1 44 | ax = find_axes; 45 | end 46 | 47 | 48 | for i = 1:numel(ax) 49 | 50 | % Set current axes 51 | set(gcf,'CurrentAxes',ax(i)) 52 | 53 | % Convert to data units 54 | a = axis(ax(i)); 55 | 56 | xd = a(1) + (( a(2)-a(1) )*x); 57 | yd = a(3) + (( a(4)-a(3) )*y); 58 | 59 | 60 | % add text 61 | ht = text(xd,yd,upper(letter(i))); % ')']) %,'units','normalized') 62 | 63 | set(ht,'FontName','Times New Roman') %,'FontSize',12) % <-- custom line for CF 64 | 65 | end 66 | 67 | set(gcf,'CurrentAxes',h1) 68 | 69 | end 70 | 71 | function ax = find_axes 72 | % FIND AXES 73 | 74 | % Get all axes handles 75 | ax = findobj(get(gcf,'Children'),'type','axes'); 76 | 77 | % get rid of colorbars and legends 78 | ax = ax(~strcmp('Colorbar',(get(ax,'Tag')))); 79 | ax = ax(~strcmp('legend',(get(ax,'Tag')))); 80 | 81 | ax = sort(ax); 82 | 83 | end --------------------------------------------------------------------------------