diff --git a/Esiur.Analysis/Esiur.Analysis.csproj b/Esiur.Analysis/Esiur.Analysis.csproj
new file mode 100644
index 0000000..625bd34
--- /dev/null
+++ b/Esiur.Analysis/Esiur.Analysis.csproj
@@ -0,0 +1,13 @@
+
+
+  
+    netstandard2.1
+    enable
+  
+
+  
+    
+    
+  
+
+
diff --git a/Esiur.Analysis/Signals/Capacity.cs b/Esiur.Analysis/Signals/Capacity.cs
new file mode 100644
index 0000000..9958a04
--- /dev/null
+++ b/Esiur.Analysis/Signals/Capacity.cs
@@ -0,0 +1,69 @@
+using Esiur.Analysis.Statistics;
+using Esiur.Analysis.Units;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Security.Cryptography.X509Certificates;
+using System.Text;
+
+namespace Esiur.Analysis.Signals
+{
+    public static class Capacity
+    {
+        public struct CSI
+        {
+            public double SNR;
+            public Probability Probability;
+
+            public CSI(double snr, double probability)
+            {
+                SNR = snr;
+                Probability = probability;
+            }
+        }
+
+        public struct OutageCapacity
+        {
+            public BitRate Capacity;
+            public double MinSNR;
+            public Probability Outage;
+            public double Bandwidth;
+
+            public OutageCapacity(Probability outage, double minSNR, double bandwidth)
+            {
+                MinSNR = minSNR;
+                Outage = outage;
+                Bandwidth = bandwidth;
+                Capacity = (1 - Outage) * bandwidth * Math.Log(1 + minSNR, 2);
+            }
+
+            public override string ToString() => $" {MinSNR.ToString("F")} <{Outage}> => {Capacity}";
+        }
+
+        public static double Compute(double bandwidth, double snr)
+        => bandwidth * Math.Log(1 + snr, 2);
+
+
+        public static double ComputeErgodic(double bandwidth, CSI[] receiverCSI)
+        {
+            return bandwidth * receiverCSI.Sum(x => Math.Log(1 + x.SNR, 2) * x.Probability);
+        }
+
+        public static OutageCapacity[] ComputeOutage(double bandwidth, CSI[] receiverCSI)
+        {
+            var sorted = receiverCSI.OrderBy(x => x.SNR);
+            var rt = sorted.Select(x => {
+                var pOut = receiverCSI.Where(csi => csi.SNR < x.SNR).Sum(x => x.Probability);
+                return new OutageCapacity()
+                {
+                    Outage = pOut,
+                    MinSNR = x.SNR,
+                    Capacity = (1 - pOut) * bandwidth * Math.Log(1 + x.SNR, 2)
+                };
+            });
+
+            return rt.ToArray();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Esiur.Analysis/Signals/DSP.cs b/Esiur.Analysis/Signals/DSP.cs
new file mode 100644
index 0000000..ee6fa6a
--- /dev/null
+++ b/Esiur.Analysis/Signals/DSP.cs
@@ -0,0 +1,55 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Esiur.Analysis.Signals
+{
+    public static class DSP
+    {
+        public static double[] ConvolveMany(params double[][] signals)
+        {
+            var rt = signals[0];
+
+            for (var i = 1; i < signals.Length; i++)
+                rt = rt.Convolve(signals[i]);
+
+            return rt;
+        }
+
+        public static double[] Convolve(this double[] signal, double[] filter)
+        {
+            var length = signal.Length + filter.Length - 1;
+            var rt = new double[length];
+
+            //for (var i = 0; i < signal.Length; i++)
+            //    for (var j = 0; j < filter.Length; j++)
+            //        rt[i + j] += signal[i] * filter[j];
+
+            for (var i = 0; i < length; i++)
+            {
+                for (var j = 0; j < signal.Length && i - j >= 0 && i - j < filter.Length; j++)
+                {
+                    rt[i] = signal[j] * filter[i - j];
+                }
+            }
+
+            return rt;
+        }
+
+        public static double[] CrossCorrelate(this double[] signal, double[] filter)
+        {
+            var length = signal.Length + filter.Length - 1;
+            var rt = new double[length];
+            for (var i = 0; i < length; i++)
+            {
+                for (var j = 0; j < signal.Length && j + i < filter.Length; j++)
+                {
+                    rt[i] = signal[j] * filter[i + j];
+                }
+            }
+
+            return rt;
+        }
+
+    }
+}
diff --git a/Esiur.Analysis/Signals/Propagation.cs b/Esiur.Analysis/Signals/Propagation.cs
new file mode 100644
index 0000000..1ac2487
--- /dev/null
+++ b/Esiur.Analysis/Signals/Propagation.cs
@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Esiur.Analysis.Signals
+{
+    public static class Propagation
+    {
+        public static readonly  double LightSpeed = 2.99792458e8;
+        public static double FindReceivedPower(double transmittedPower, double distance, 
+            double transmitterGain, double receiverGain, double pathLoss)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}
diff --git a/Esiur.Analysis/Statistics/Probability.cs b/Esiur.Analysis/Statistics/Probability.cs
new file mode 100644
index 0000000..c2ec0c7
--- /dev/null
+++ b/Esiur.Analysis/Statistics/Probability.cs
@@ -0,0 +1,31 @@
+using Esiur.Analysis.Units;
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Esiur.Analysis.Statistics
+{
+    public struct Probability
+    {
+        public double Value;
+
+        public static implicit operator Probability(double v) => new Probability(v);
+        public static implicit operator double(Probability v) => v.Value;
+
+        public Probability(double value)
+        {
+            if (value > 1 || value < 0)
+                throw new Exception("0 >= Probability <= 1");
+
+            Value = value;
+        }
+
+        public double ToPercentage() => Value * 100;
+        public Probability FromPercentage(double value) => new Probability(value / 100);
+
+        public override string ToString()
+        {
+            return (Math.Round(Value * 10000) / 100) + "%";
+        }
+    }
+}
diff --git a/Esiur.Analysis/Statistics/StatisticalFunctions.cs b/Esiur.Analysis/Statistics/StatisticalFunctions.cs
new file mode 100644
index 0000000..f0c5cf8
--- /dev/null
+++ b/Esiur.Analysis/Statistics/StatisticalFunctions.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Esiur.Analysis.Statistics
+{
+    public static class Statistics
+    {
+        public static double Mean(this double[] values) => values.Sum() / values.Length;
+
+        public static double Variance(this double[] x)
+        {
+            var mean = x.Mean();
+            return x.Sum(x => Math.Pow(x - mean, 2)) / x.Length;
+        }
+
+
+        public static double StdDiv(this double[] x) => Math.Sqrt(x.Variance());
+
+        public static double Covariance(this double[] x, double[] y)
+        {
+            var n = x.Length < y.Length ? x.Length : y.Length;
+            var X = x.Mean();
+            var Y = y.Mean();
+
+            double rt = 0;
+
+            for (var i = 0; i < n; i++)
+                rt += (x[i] - X) * (y[i] - Y);
+
+            return rt / n;
+        }
+
+
+        public static double RMS(this double[] x) => Math.Sqrt(x.Sum(x => x * x) / x.Length);
+
+
+        public static double Correlation(this double[] x, double[] y)
+        {
+            return x.Covariance(y) / (x.StdDiv() * y.StdDiv());
+        }
+    }
+}
diff --git a/Esiur.Analysis/Units/BitRate.cs b/Esiur.Analysis/Units/BitRate.cs
new file mode 100644
index 0000000..49de13f
--- /dev/null
+++ b/Esiur.Analysis/Units/BitRate.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Esiur.Analysis.Units
+{
+    public enum BitRateKind
+    {
+        Bits,
+        Octets,
+        Bytes
+    }
+
+    public struct BitRate : IComparable
+    {
+        public double Value;
+
+
+        public BitRate(double value, BitRateKind kind = BitRateKind.Bits)
+        {
+            if (kind == BitRateKind.Bytes)
+                Value = value * 8;
+            else if (kind == BitRateKind.Octets)
+                Value = value * 7;
+            else
+                Value = value;
+        }
+
+        public static implicit operator BitRate(double d) => new BitRate(d);
+        public static implicit operator double(BitRate d) => d.Value;
+
+        //public static explicit operator PowerUnit(double d) => new PowerUnit(d, PowerUnitKind.Watt);
+        //public static explicit operator double(PowerUnit d) => d.Value;
+
+        //public static PowerUnit operator +(PowerUnit a) => a;
+        //public static PowerUnit operator -(PowerUnit a) => new PowerUnit(-a.num, a.den);
+
+        public static BitRate operator +(BitRate a, BitRate b)
+            => new BitRate(a.Value + b.Value);
+
+        public static BitRate operator -(BitRate a, BitRate b)
+            => new BitRate(a.Value - b.Value);
+
+        public static BitRate operator *(BitRate a, BitRate b)
+            => new BitRate(a.Value * b.Value);
+
+        public static BitRate operator /(BitRate a, BitRate b)
+        {
+            if (b.Value == 0)
+            {
+                throw new DivideByZeroException();
+            }
+            return new BitRate(a.Value / b.Value);
+        }
+
+
+        public override string ToString()
+        {
+            if (Value >= 1e12)
+                return (Value / 1e12).ToString("F") + " tbps";
+            else if (Value >= 1e9)
+                return (Value / 1e9).ToString("F") + " gbps";
+            else if (Value >= 1e6)
+                return (Value / 1e6).ToString("F") + " mbps";
+            else if (Value >= 1e3)
+                return (Value * 1e3).ToString("F") + " kbps";
+            else
+                return Value.ToString("F") + " bps";
+        }
+
+
+        public int CompareTo(object obj)
+        {
+            if (obj is BitRate p)
+                return Value.CompareTo(p.Value);
+            else
+                return Value.CompareTo(obj);
+        }
+    }
+}
diff --git a/Esiur.Analysis/Units/PowerUnit.cs b/Esiur.Analysis/Units/PowerUnit.cs
new file mode 100644
index 0000000..eba59d7
--- /dev/null
+++ b/Esiur.Analysis/Units/PowerUnit.cs
@@ -0,0 +1,81 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Esiur.Analysis.Units
+{
+    public enum PowerUnitKind
+    {
+        Watt,
+        Decibel
+    }
+
+    public struct PowerUnit : IComparable
+    {
+        public double Value;
+
+
+        public PowerUnit(double value, PowerUnitKind kind = PowerUnitKind.Watt)
+        {
+            if (kind == PowerUnitKind.Watt)
+                Value = value;
+            else if (kind == PowerUnitKind.Decibel)
+                Value = FromDb(value);
+            else
+                Value = 0;
+        }
+
+        public static implicit operator PowerUnit(double d) => new PowerUnit(d, PowerUnitKind.Watt);
+        public static implicit operator double(PowerUnit d) => d.Value;
+
+        //public static explicit operator PowerUnit(double d) => new PowerUnit(d, PowerUnitKind.Watt);
+        //public static explicit operator double(PowerUnit d) => d.Value;
+
+        //public static PowerUnit operator +(PowerUnit a) => a;
+        //public static PowerUnit operator -(PowerUnit a) => new PowerUnit(-a.num, a.den);
+
+        public static PowerUnit operator +(PowerUnit a, PowerUnit b)
+            => new PowerUnit(a.Value + b.Value);
+
+        public static PowerUnit operator -(PowerUnit a, PowerUnit b)
+            => new PowerUnit(a.Value - b.Value);
+
+        public static PowerUnit operator *(PowerUnit a, PowerUnit b)
+            => new PowerUnit(a.Value * b.Value);
+
+        public static PowerUnit operator /(PowerUnit a, PowerUnit b)
+        {
+            if (b.Value == 0)
+            {
+                throw new DivideByZeroException();
+            }
+            return new PowerUnit(a.Value / b.Value);
+        }
+
+      
+        public override string ToString()
+        {
+            if (Value < 1e-6)
+                return (Value * 1e9).ToString("F") + "nW";
+            else if (Value < 1e-3)
+                return (Value * 1e6).ToString("F") + "µW";
+            else if (Value < 1)
+                return (Value * 1e3).ToString("F") + "mW";
+            else
+                return Value.ToString("F") + "W";
+        }
+
+        public double ToDb() => 10 * Math.Log(10, Value);
+        public static double FromDb(double value) => Math.Pow(10, value / 10);
+
+        public int CompareTo(object obj)
+        {
+
+            if (obj is PowerUnit p)
+                return Value.CompareTo(p.Value);
+            else
+                return Value.CompareTo(obj);
+        }
+    }
+}
diff --git a/Esiur.sln b/Esiur.sln
index 104e119..b7e0ef6 100644
--- a/Esiur.sln
+++ b/Esiur.sln
@@ -10,6 +10,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Esiur.Stores.EntityCore", "
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{331F82B6-6B90-4533-9718-F7C8090D8F19}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Esiur.Analysis", "Esiur.Analysis\Esiur.Analysis.csproj", "{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -32,6 +34,10 @@ Global
 		{331F82B6-6B90-4533-9718-F7C8090D8F19}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{331F82B6-6B90-4533-9718-F7C8090D8F19}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{331F82B6-6B90-4533-9718-F7C8090D8F19}.Release|Any CPU.Build.0 = Release|Any CPU
+		{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{8D52DEEA-B7E8-4C93-9B6C-EDB9C2D25211}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/Esiur/Data/IUserType.cs b/Esiur/Data/IUserType.cs
index 6485b33..7122b40 100644
--- a/Esiur/Data/IUserType.cs
+++ b/Esiur/Data/IUserType.cs
@@ -7,5 +7,7 @@ public interface IUserType
 {
     object Get();
     void Set(object value);
+
+    object SetAndGet(object value);
 }
 
diff --git a/Esiur/Data/VarList.cs b/Esiur/Data/VarList.cs
new file mode 100644
index 0000000..7d6eba0
--- /dev/null
+++ b/Esiur/Data/VarList.cs
@@ -0,0 +1,103 @@
+using Esiur.Core;
+using Esiur.Resource;
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace Esiur.Data
+{
+    public class VarList : IEnumerable, ICollection, ICollection
+    {
+        string propertyName;
+        IResource resource;
+
+        List list = new List();
+
+        public VarList(IResource resource, [CallerMemberName] string propertyName = "")
+        {
+            this.resource = resource;
+            this.propertyName = propertyName;
+        }
+
+        public int Count => list.Count;
+
+        public bool IsReadOnly => false;
+
+        public bool IsSynchronized => true;
+
+
+        public object SyncRoot { get; } = new object();
+
+        public void Add(T item)
+        {
+            list.Add(item);
+
+            resource?.Instance?.Modified(propertyName);
+        }
+
+        public void Clear()
+        {
+            list.Clear();
+            resource?.Instance?.Modified(propertyName);
+        }
+
+        public bool Contains(T item)
+        {
+            return list.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            lock (SyncRoot)
+                list.CopyTo(array, arrayIndex);
+        }
+
+        public void CopyTo(Array array, int index)
+        {
+            lock (SyncRoot)
+                (list as ICollection).CopyTo(array, index);
+        }
+
+        public IEnumerator GetEnumerator()
+        {
+            return list.GetEnumerator();
+        }
+
+        public bool Remove(T item)
+        {
+            if ( list.Remove(item))
+            {
+                resource?.Instance?.Modified(propertyName);
+                return true;
+            }
+
+            return false;
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return list.GetEnumerator();
+        }
+
+
+        public T this[int index]
+        {
+            get
+            {
+                return list[index];
+            }
+            set
+            {
+                //var oldValue = list[index];
+
+                lock (SyncRoot)
+                    list[index] = value;
+
+                resource?.Instance?.Modified(propertyName);
+
+            }
+        }
+    }
+}
diff --git a/Esiur/Esiur.csproj b/Esiur/Esiur.csproj
index 9203a94..4b63b3f 100644
--- a/Esiur/Esiur.csproj
+++ b/Esiur/Esiur.csproj
@@ -6,7 +6,7 @@
     Ahmed Kh. Zamil
      http://www.esiur.com
     true
-    2.3.6
+    2.3.7
     https://github.com/esiur/esiur-dotnet
     Ahmed Kh. Zamil
     
diff --git a/Test/Program.cs b/Test/Program.cs
index 5d5ac93..38489bb 100644
--- a/Test/Program.cs
+++ b/Test/Program.cs
@@ -45,6 +45,8 @@ using System.Collections.Generic;
 using System.Reflection;
 using System.Security.Cryptography;
 using System.Text;
+using Esiur.Analysis.Signals;
+using Esiur.Analysis.Units;
 
 namespace Test
 {
@@ -54,6 +56,17 @@ namespace Test
         static async Task Main(string[] args)
         {
 
+
+            var outage = Capacity.ComputeOutage(20000000, new Capacity.CSI[]
+            {
+                new Capacity.CSI(PowerUnit.FromDb(20), 0.1),
+                new Capacity.CSI(PowerUnit.FromDb(15), 0.15),
+                new Capacity.CSI(PowerUnit.FromDb(10), 0.25),
+                new Capacity.CSI(PowerUnit.FromDb(5), 0.25),
+                new Capacity.CSI(PowerUnit.FromDb(0), 0.15),
+                new Capacity.CSI(PowerUnit.FromDb(-5), 0.1),
+            });
+
             // Create stores to keep objects.
             var system = await Warehouse.Put("sys", new MemoryStore());
             var server = await Warehouse.Put("sys/server", new DistributedServer());
diff --git a/Test/Test.csproj b/Test/Test.csproj
index 00950c4..d54d448 100644
--- a/Test/Test.csproj
+++ b/Test/Test.csproj
@@ -6,6 +6,7 @@
   
 
   
+