As already mentioned, for the trend analysis, a number of ports were selected based on their size and traffic. There were also a couple of known ports included in this dataset to easier interpret the results. The ports used in the analysis were:
• NLRTM— Rotterdam, Netherlands
• NOOSL— Oslo, Norway
• CNSHG— Shanghai, China
• NLMSV— Maasvlakte, Netherlands
• SGSIN— Singapore, Singapore
• USHPY— Baytown, USA
• BEANR— Antwerpen, Belgium
• TWKHH— Kaohsiung, Taiwan
• JPYOK— Yokohama, Japan
The same process as for the single-case analysis was conducted, but on a higher level as the main purpose of this study was to establish a trend in terms of a impact factor of vessel segmentation on port frequencies. Figure A.6 shows a similar version of the table used for the single port analysis (Figure A.2) but also shows the number of transitions that differed from the most frequent next port when considering segments (i.e. the estimated improvement factor).
It is apparent that there are variances in improvement factors for
dif-Chapter A: Feasibility study - Summary 108
Figure A.6:Port frequencies and transition distribution as they relate to the most frequent next port for the selected ports
Figure A.7:Distribution of improvement factors for each origin port considering segments
Chapter A: Feasibility study - Summary 109
ferent ports ranging from as low as1.25% to as high as91.40%. In the case of NLRTM, which is mostly a dry bulk port, there were no considerable improvements as almost all vessels are of the same segment. For the port NLMSV, the opposite was the case as there were a plethora of different types of vessels that frequented the port. Figure A.7 shows the distribution of the improvement factor considering segments for each origin port as well as the overall average impact factor for these 9 ports which was36.88%.
Furthermore, when looking at the impact of sub-segments, as Figure A.8 shows, it seems that the improvement factor has increased overall. For example, in the case ofNLRTM, the improvement factor has increased from1.25%to19.66%, and although this varied for the different ports, the overall average improvement factor increased from36.88%to50.28%.
Figure A.8:Distribution of improvement factors for each origin port considering sub-segments
A prediction method considering the frequencies of ports for vessel des-tination predictions would choose the most frequent next port for the predicted next destination. In this scenario, ignoring the vessel’s type (segmentation) would give the wrong prediction for a lot of vessels from different segments in a lot of ports. The results from the feasibility study clearly indicates that applying the as-pect of vessel segmentation to such models would definitively have an impact on prediction accuracy and, therefore, is worth investigating further.
Appendix B
Trajectory sampler Golang package
Code listing B.1:Trajectory sampler package
1 // Package sampler can be used to sample 2D trajectories based on distance as well as 3D trajectories based on time
2 package sampler 3
4 import (
5 "errors"
6 "sort"
7 "time"
8
9 "github.com/paulmach/orb"
10 "github.com/paulmach/orb/encoding/wkt"
11 "github.com/paulmach/orb/geo"
12 "github.com/paulmach/orb/resample"
13 "github.com/twpayne/go-geom"
14 "github.com/twpayne/go-geom/encoding/ewkbhex"
15 geomwkt "github.com/twpayne/go-geom/encoding/wkt"
16 ) 17
18 // Metric either time or distance used for sampling 19 type Metric string
20
21 const (
22 // Time sampling uses hours as SamplRate unit 23 Time Metric = "time"
24 // Distance sampling uses meters as SamplRate unit 25 Distance Metric = "distance"
26 ) 27
28 // Instance of sampler 29 type Instance struct {
30 // Trajectory in (E)WKT format, e.g. (LINESTRING Z (x, y, timestamp)) 31 WKTTrajectory string
32 // Trajectory in (E)WBT format, e.g. (01020000800801058A1A4CC312424025B5548F949B5454240000) 33 WKBHexTrajectory string
34 Metric Metric
35 // SampleRate unit is hours for time and meters for distance 36 SampleRate int
110
Chapter B: Trajectory sampler Golang package 111
37 } 38
39 // Parsers 40
41 // parse2DTrajectory parses a trajectory not containing Z coordinates
42 // we want orb.Geometry for the resampling method which doesn’t support 3D geometry, 43 // so we use parse3DTrajectory and flatten the coords
44 func (s *Instance) parse2DTrajectory() (orb.LineString, error) { 45 geoLine, err := s.parse3DTrajectory()
46 if err != nil {
53 lineString = append(lineString, orb.Point{c[0], c[1]})
54 }
55
56 return lineString, nil 57 }
58
59 // parse3DTrajectory parses a 3D trajectory where the Z coordinate contains time 60 func (s *Instance) parse3DTrajectory() (*geom.LineString, error) {
61 var (
62 geometry geom.T
63 err error
64 )
65
66 if s.WKBHexTrajectory == "" && s.WKTTrajectory == "" {
67 return nil, errors.New("specify either WKTTrajectory, or WKBHexTrajectory")
68 }
69
70 if s.WKBHexTrajectory != "" {
71 geometry, err = ewkbhex.Decode(s.WKBHexTrajectory)
72 if err != nil {
73 return nil, err
74 }
75 }
76
77 if s.WKTTrajectory != "" {
78 geometry, err = geomwkt.Unmarshal(s.WKTTrajectory)
79 if err != nil {
80 return nil, err
81 }
82 }
83
84 line, ok := geometry.(*geom.LineString)
85 if !ok {
86 return nil, errors.New("geometry was not a valid linestring")
87 }
88
89 return line, nil 90 }
91
92 // Resample runs resampling based on given config 93 func (s *Instance) Resample() (string, error) { 94 switch s.Metric {
95 case Distance:
96 return s.resampleDistance()
Chapter B: Trajectory sampler Golang package 112
97 case Time:
98 return s.resampleTime()
99 default:
100 return "", errors.New("metric was not specified to a valid metric")
101 }
102 } 103
104 func (s *Instance) resampleDistance() (string, error) { 105 parsed, err := s.parse2DTrajectory()
106 if err != nil { 107 return "", err
108 }
109
110 sampled := resample.ToInterval(parsed, geo.DistanceHaversine, float64(s.SampleRate)) 111 return wkt.MarshalString(sampled), nil
112 } 113
114 // resampleTime resamples trajectory based on s.SampleRate given in hours.
115 // Extracts the first position within intervals based on sample rate 116 func (s *Instance) resampleTime() (string, error) {
117 var err error 118
119 trajectory, err := s.parse3DTrajectory() 120 if err != nil {
129 // within each interval add the first coord to reducedCoords 130 for _, interval := range intervals {
131 var first *geom.Coord
132
133 // find coord first within interval
134 for i := range coords {
135 coordInterval := s.roundTime(int64(coords[i][2]))
136 if coordInterval == interval {
137 first = &coords[i]
143 reducedCoords = append(reducedCoords, *first)
144 }
145 }
146
147 // if the last coord wasn’t in the reduced coords, add it 148 lastReduced := reducedCoords[len(reducedCoords)-1]
149 if !lastReduced.Equal(geom.XYZ, coords[len(coords)-1]) {
150 reducedCoords = append(reducedCoords, coords[len(coords)-1])
151 }
152
153 if len(reducedCoords) <= 1 {
154 return "", errors.New("too few points in sampled trajectory")
155 }
156
Chapter B: Trajectory sampler Golang package 113
157 reduced, err := geom.NewLineString(geom.XYZ).SetCoords(reducedCoords) 158 if err != nil {
159 return "", err
160 }
161
162 return geomwkt.Marshal(reduced) 163 }
164
165 // time sampling helpers 166
167 func (s *Instance) roundTime(ts int64) time.Time {
168 return time.Unix(ts, 0).UTC().Round(time.Duration(s.SampleRate) * time.Hour) 169 }
170
171 func (s *Instance) getTimeIntervals(trajectory *geom.LineString) []time.Time { 172 times := make(map[string]time.Time)
173 for _, coord := range trajectory.Coords() { 174 rounded := s.roundTime(int64(coord[2]))
175 times[rounded.Format("2006.01.02:15:04")] = rounded
176 }
177
178 ret := make([]time.Time, 0, len(times)) 179 for _, value := range times {
180 ret = append(ret, value)
181 }
182
183 sort.Slice(ret, func(i, j int) bool { 184 return ret[i].Before(ret[j])
185 })
186
187 return ret
NTNU Norwegian University of Science and Technology Faculty of Information Technology and Electrical Engineering Department of Computer Science
Morten Omholt-JensenVessel destination forecasting based on historical AIS data
Morten Omholt-Jensen
Vessel destination forecasting based on historical AIS data
Master’s thesis in Applied Computer Science Supervisor: Christopher Frantz
June 2021