├── LICENSE ├── README.md ├── SIMPL_reader_batch_20190517.m ├── plotter_20190517.m └── time2distance.m /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Gang Hai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # photon-counting-lidar-data-processing-and-analysis 2 | This is an preliminary processing and analysis for photon-counting lidar data. 3 | 4 | # data 5 | 6 | A sample data of SIMPL could be downloaded as below. Cope it and paste it on the browser. 7 | 8 | https://icesat-2.gsfc.nasa.gov/legacy-data/simpl/data/maypop3/R5/grans/017_20150813/1404/simpl_l2a_20150813t142217_005_1.h5 9 | 10 | If this way failed, please instead go to this webpage: 11 | 12 | https://icesat-2.gsfc.nasa.gov/legacy-data/simpl/data/maypop3/R5/browse/017_20150813/1404/index.html 13 | 14 | and select the data file start from 2015-08-13 14:22:17 and end at 2015-08-13 14:27:27, click 【get】 and the downloading begins. 15 | 16 | Anyway, one of both two ways should work. 17 | 18 | # reader 19 | main script used to read in batch: SIMPL_reader_batch_20190517.m 20 | 21 | auxiliary function: time2distance.m 22 | 23 | plot script: plotter_20190517.m 24 | 25 | # usage 26 | Put the readers and the sample data in the same directory, then run the SIMPL_reader_batch_20190517.m, and plot the output data using plotter_20190517.m. 27 | -------------------------------------------------------------------------------- /SIMPL_reader_batch_20190517.m: -------------------------------------------------------------------------------- 1 | % ################ modified and appended on 2018-12-13 ################## % 2 | % 3 | clear; 4 | close; 5 | tic; 6 | 7 | % % definition of anonymous function 8 | % global dist2d; 9 | % dist2d = @(x1, y1, x2, y2)sqrt((x1 - x2) .^ 2 + (y1 - y2) .^ 2); % 2D Euclidean distance 10 | 11 | % start to read HDF file 12 | simplfiles = dir('simpl*.h5'); 13 | 14 | grp = 9; 15 | % chl = 4; % 532 nm 16 | chl = 2; % 1064 nm 17 | indStart = 1; 18 | %} 19 | 20 | for f = 1:length(simplfiles) - 1 21 | %% 22 | h5filename = ([simplfiles(f,1).name]); % identify the MABEL HDF5 file to pass through each function 23 | data = h5info(h5filename); % generates the structure profile for each HDF5 file being analyzed from which time and elevation data will be called 24 | 25 | % read variables from HDF file 26 | % channel 2: 1064 nm, parallel direction 27 | % Elapsed seconds since first data point in granuleGPS time = delta_time + gps_sec_offset (in /ancillary_data) 28 | elev_initial = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/elev'])); % initial range elevations of returned photons 29 | lat_initial = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/latitude'])); % corresponding latitudes for initial range elevations 30 | lon_initial = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/longitude'])); % corresponding longitudes for initial range elevations 31 | time_initial = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/delta_time'])); % timestamp of photons 32 | 33 | x_waVelocity = hdf5read(h5filename,([data.Groups((8),1).Groups(3,1).Name,'/x_waVelocity'])); % meters/second 34 | y_waVelocity = hdf5read(h5filename,([data.Groups((8),1).Groups(3,1).Name,'/y_waVelocity'])); % meters/second 35 | time_gps = hdf5read(h5filename,('ins/delta_time')); % timestamp of gps, source = Derived (gps_seconds-metadata.gps_sec_offset) 36 | 37 | lat_gps = hdf5read(h5filename,([data.Groups((8),1).Groups(2,1).Name,'/latitude'])); 38 | lon_gps = hdf5read(h5filename,([data.Groups((8),1).Groups(2,1).Name,'/longitude'])); 39 | 40 | % gps_sec_offset = hdf5read(h5filename,('/ancillary_data/gps_sec_offset')); % to be used 41 | 42 | photon_id = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/photon_id'])); % to be used 43 | shot_num = hdf5read(h5filename,([data.Groups((grp),1).Groups(chl,1).Name,'/shot_num'])); % to be used 44 | 45 | %% 46 | % calculate resultant velocity 47 | velocity_total = sqrt((x_waVelocity).^2.+(y_waVelocity).^2); % meters/second 48 | 49 | % convert time of each photon to distance based on velocity 50 | [ distances ] = time2distance( velocity_total, time_initial, time_gps ); % unit: meter 51 | %} 52 | 53 | % organize vectors of time, lon, lat and elevation into matrix 54 | lon_initial_west = lon_initial - 360; % west longitude is expressed as negative, from -180 to 0 degree counterclockwise. 55 | tlle_initial = [time_initial, lat_initial, lon_initial_west, elev_initial]; % [time, lat, lon, ele] 56 | 57 | %% readed data 58 | % truncate and obtain the photons within the first segment of 1000 m starting from the designated point 59 | indkm = find(distances >= distances(indStart) & distances - distances(indStart) <= 1000); 60 | ATD_km = distances(indkm) - distances(indkm(1)); % along track distance of this segment, unit: meter 61 | ele_km = tlle_initial(indkm, 4); % elevation of this segment, unit: meter 62 | ATD_ele_km = [ATD_km, ele_km]; % [ATD, elevation], % 2018-12-05, by Gang 63 | tlle_km = tlle_initial(indkm, :); % [time, lat, lon, ele] of this segment 64 | 65 | % % record the indices of photons for final use 66 | % indPho = (1:1:size(tlle_initial,1))'; % indices of photons, 2018-12-05, by Gang 67 | % indPho = indPho(indkm); % indices of photons filtered within 1km, 2018-12-05, by Gang 68 | 69 | end 70 | 71 | toc; -------------------------------------------------------------------------------- /plotter_20190517.m: -------------------------------------------------------------------------------- 1 | close all; 2 | % 3 | % Figure 2(a) 4 | figure(1); 5 | 6 | % hold on, plot(lle_initial_1km(:,2), lle_initial_1km(:,3),'.k', 'MarkerSize', 0.5); 7 | hold on, a1 = plot(ATD_km, ele_km, '.k', 'MarkerSize', 4.5); 8 | set(gca,'FontSize',18); 9 | 10 | xlim([0 1000]); 11 | ylim([-200 1400]); 12 | 13 | xlabel('Distance Along Track (m)','FontSize', 18); 14 | ylabel('Elevation (m)','FontSize', 18); 15 | title('Raw Data','FontSize', 20); 16 | box on; 17 | % position_2a = get(gcf,'position'); % 2018-12-21 18 | % set(gcf, 'position', position_2a); % 2018-12-21 19 | %} 20 | 21 | -------------------------------------------------------------------------------- /time2distance.m: -------------------------------------------------------------------------------- 1 | function [ distances, avgVelocity ] = time2distance( velocity, time_initial, time_gps ) 2 | 3 | % tic; 4 | 5 | % distances = zeros(numel(time_initial), 1); 6 | timeFirst = time_initial(1); 7 | timeEnd = time_initial(end); 8 | 9 | 10 | indStarts = find(time_gps <= timeFirst); 11 | indStart = indStarts(end); 12 | 13 | indEnds = find(time_gps >= timeEnd); 14 | indEnd = indEnds(1); 15 | 16 | indFlight = (indStart:1:indEnd)'; 17 | avgVelocity = mean(velocity(indFlight)); % meters/second 18 | 19 | %{ 20 | count = 1; 21 | for i = 1:1:numel(indFlight) - 1 22 | i 23 | iAvgVelocity = mean(velocity(i:i + 1)); % average velocity, unit: meters/second 24 | 25 | iPhotonTime = time_initial(time_initial >= time_gps(indFlight(i)) & time_initial < time_gps(indFlight(i) + 1)); 26 | iPhotonNumber = numel(iPhotonTime); 27 | 28 | dT = iPhotonTime - timeFirst; % time increment, unit: second 29 | distances(count:count + iPhotonNumber - 1,1) = iAvgVelocity .* dT; 30 | 31 | count = count + iPhotonNumber; 32 | end 33 | %} 34 | 35 | % 36 | dT = time_initial - timeFirst; % time increment, unit: second 37 | distances = avgVelocity .* dT; % unit: meter 38 | %} 39 | 40 | % toc; 41 | end 42 | 43 | 44 | --------------------------------------------------------------------------------