diff --git a/.gitignore b/.gitignore
index 397680eecc360e1cda8d18d964d0f90b47430f9a..b139f3e8d20a35b89f3b7ebe50a95cf38649dc15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
 .idea/*
 build/
 skais.egg-info/
-*.coverage
\ No newline at end of file
+*.coverage
+*__pycache__*
diff --git a/requirements.txt b/requirements.txt
index 7d1581b18d12e886eca1b169a2639465adb91d63..0634b7c3db2603b5ca2ba0a5b6484f863be17d00 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,4 +3,5 @@ setuptools~=57.0.0
 numpy~=1.19.5
 numba~=0.53.1
 scipy~=1.5.4
-POT~=0.7.0
\ No newline at end of file
+hmmlearn~=0.2.6
+scikit-learn~=1.0.1
\ No newline at end of file
diff --git a/skais/ais/ais_trajectory.py b/skais/ais/ais_trajectory.py
index c3a339c895e80366c42c35560f4a09819cce0af8..41853864212c75a5cf89c0549ae6632927637872 100644
--- a/skais/ais/ais_trajectory.py
+++ b/skais/ais/ais_trajectory.py
@@ -5,6 +5,7 @@ import numpy as np
 from numba import jit
 from scipy.interpolate import interp1d
 
+from skais.stats.angluar import angular_dispersion
 from skais.utils.geography import great_circle
 from skais.utils.stats import calc_std_dev
 
@@ -155,7 +156,7 @@ def l1_angle(dat, radius):
 
     dat = np.concatenate([np.full(radius, dat[0]), dat, np.full(radius, dat[-1])])
     for i in range(radius, dat.shape[0] - radius):
-        data = dat[i - radius:i + radius+1]
+        data = dat[i - radius:i + radius + 1]
         l1[i - radius] = np.linalg.norm(data, ord=1)
 
     return l1
@@ -166,11 +167,20 @@ def l2_angle(dat, radius):
 
     dat = np.concatenate([np.full(radius, dat[0]), dat, np.full(radius, dat[-1])])
     for i in range(radius, dat.shape[0] - radius):
-        data = dat[i - radius:i + radius+1]
+        data = dat[i - radius:i + radius + 1]
         l2[i - radius] = np.linalg.norm(data, ord=2)
     return l2
 
 
+def angle_dispersion(dat, radius):
+    l2 = np.zeros(dat.shape)
+
+    dat = np.concatenate([np.full(radius, dat[0]), dat, np.full(radius, dat[-1])])
+    for i in range(radius, dat.shape[0] - radius):
+        data = dat[i - radius:i + radius + 1]
+        l2[i - radius] = angular_dispersion(np.radians(data))
+
+
 class AISTrajectory:
     def __init__(self, df, interpolation_time=None):
         df = df.drop_duplicates(subset=['ts_sec'])
@@ -181,7 +191,7 @@ class AISTrajectory:
             discrete_columns = ['navstatus', 'label']
             new_df = pd.DataFrame()
             t_raw = df['ts_sec'].to_numpy()
-            t_interp1d = np.arange(start=t_raw[0], stop=t_raw[-1]+1,
+            t_interp1d = np.arange(start=t_raw[0], stop=t_raw[-1] + 1,
                                    step=interpolation_time * 60)
 
             new_df['ts_sec'] = t_interp1d
@@ -267,6 +277,16 @@ class AISTrajectory:
             stds[:radius] = np.nan
             self.df[f"{field}_std"] = stds
 
+    def compute_all_dispersions(self, radius):
+        fields = ['cog', 'heading', 'angles_diff']
+        for field in fields:
+            if field in self.df.columns:
+                dat = self.df[field].to_numpy()
+                disp = angle_dispersion(dat, radius)
+                disp[-radius:] = np.nan
+                disp[:radius] = np.nan
+                self.df[f"{field}_disp"] = disp
+
     def compute_position_features(self, radius):
         dat = np.stack([self.df.longitude.to_numpy(), self.df.latitude.to_numpy()], axis=1)
         std = compute_position_angle_std(dat, radius)
diff --git a/skais/learn/hmm_gmm_classifier.py b/skais/learn/hmm_gmm_classifier.py
index 34507ddf98c80a7452ca45894d077a11b9ca1a61..953041d1d5c890b2244ae95233e27680b8c49f55 100644
--- a/skais/learn/hmm_gmm_classifier.py
+++ b/skais/learn/hmm_gmm_classifier.py
@@ -1,7 +1,6 @@
 import random
 
 from hmmlearn.hmm import GMMHMM, GaussianHMM
-from matplotlib import pyplot as plt
 from numba import jit
 from scipy import linalg
 from sklearn.datasets import make_spd_matrix