Haar Wavelets Implementation in C#

You searched for 'wavelet c#'

Here are some results for the search term on this website

  1. Haar Wavelets Implementation in C#
  2. Latest Activities

三月23

Haar Wavelets Implementation in C#

[HaarWavelets.rar]

As I mentioned in a recent post, I’ve recently started studying the subject of wavelets, a mathematical transform with many interesting applications than range from image compression to audio de-noising. I won’t go into detail of what wavelets are and how they work, though I intend to do so in a later blog post once I feel more comfortable with the subject, but in the meantime I decided to implement the Haar Wavelets, which are the simplest kind, in C#. The implementation itself is nothing fancy and rather straightforward, but I find the operations themselves and how they work to be very appealing.

The interface for the class is very conservative, offering methods to acquire the trend and fluctuation sub-signals from an input as well as methods to reconstruct a signal from its trend and fluctuations. I also included methods to perform transforms and inverse transforms which take the number of levels of the desired (Each level represents one application of the transform). Since I’m using doubles as the numeric type, there are a few numeric stability issues which I decided not to get into at the time. They could be reduced by simply using the decimal type instead or considering them when working with the class.

Here’s the full source code, which you can also download from the link above. The class could be made much shorter and a bit more efficient by offering only methods to perform the transform and the inverse transform, instead of breaking the functionality into pieces and allowing clients to obtain only the trend or fluctuation sub-signals. Particuarly, performing a full one-level transform would require traversing the input only once whereas in the current implementation it’s done twice since the trend and fluctuations are calculated separately. In spite of this, I prefer the current implementation because it offers a clear and explicit way to work with the transforms rather than having to use one array that holds all the required sub-signals similar to what the Transform method returns.

   1:  using System;
   2:  using System.Linq;
   3:   
   4:  namespace RaineTech.Math.Wavelets
   5:  {
   6:      /// <summary>
   7:      /// Represents the Haar Wavelets.
   8:      /// </summary>
   9:      public class HaarWavelets
  10:      {
  11:          /// <summary>
  12:          /// Calculates the trend sub-signal for the specified input.
  13:          /// </summary>
  14:          /// <param name="input">The input from which to calculate the trend. Its length must be divisible by 2.</param>
  15:          /// <returns>An array of half the length of the input containing the trend sub-signal.</returns>
  16:          public double[] GetTrendSignal(double[] input)
  17:          {
  18:              return GetTrendSignal(input, 0, input.Length);
  19:          }
  20:   
  21:          /// <summary>
  22:          /// Calculates the trend sub-signal for the specified input.
  23:          /// </summary>
  24:          /// <param name="input">The input from which to calculate the trend.</param>
  25:          /// <param name="offset">The offset into the input array.</param>
  26:          /// <param name="count">The number of elements to take from the input array. This must be a multiple of 2.</param>
  27:          /// <returns>An array of half the length of the input containing the trend sub-signal.</returns>
  28:          public double[] GetTrendSignal(double[] input, int offset, int count)
  29:          {
  30:              if (count % 2 != 0)
  31:              {
  32:                  throw new ArgumentException("Input must have an even number of elements.");
  33:              }
  34:              int trendLength = count / 2;
  35:              double[] trend = new double[trendLength];
  36:              for (int i = 0; i < trendLength; ++i)
  37:              {
  38:                  trend[i] = (input[offset + 2 * i] + input[offset + 2 * i + 1]) / System.Math.Sqrt(2.0);
  39:              }
  40:              return trend;
  41:          }
  42:   
  43:          /// <summary>
  44:          /// Calculates the fluctuation sub-signal for the specified input.
  45:          /// </summary>
  46:          /// <param name="input">The input from which to calculate the fluctuations. Its length must be divisible by 2.</param>
  47:          /// <returns>An array of half the length of the input containing the fluctuation sub-signal.</returns>
  48:          public double[] GetFluctuationSignal(double[] input)
  49:          {
  50:              return GetFluctuationSignal(input, 0, input.Length);
  51:          }
  52:   
  53:          /// <summary>
  54:          /// Calculates the fluctuation sub-signal for the specified input.
  55:          /// </summary>
  56:          /// <param name="input">The input from which to calculate the fluctuations.</param>
  57:          /// <param name="offset">The offset into the input array.</param>
  58:          /// <param name="count">The number of elements to take from the input array. This number must be a multiple of 2.</param>
  59:          /// <returns>An array of half the length of the input containing the fluctuation sub-signal.</returns>
  60:          public double[] GetFluctuationSignal(double[] input, int offset, int count)
  61:          {
  62:              if (count % 2 != 0)
  63:              {
  64:                  throw new ArgumentException("Input must have an even number of elements.");
  65:              }
  66:              int fluctuationsLength = count / 2;
  67:              double[] fluctuations = new double[fluctuationsLength];
  68:              for (int i = 0; i < fluctuationsLength; ++i)
  69:              {
  70:                  fluctuations[i] = (input[offset + 2 * i] - input[offset + 2 * i + 1]) / System.Math.Sqrt(2.0);
  71:              }
  72:              return fluctuations;
  73:          }
  74:   
  75:          /// <summary>
  76:          /// Reconstructs a signal from its equal-length trend and fluctuation sub-signals. This is equivalent to a 
  77:          /// one-level inverse transform.
  78:          /// </summary>
  79:          /// <param name="trendSignal">The trend sub-signal.</param>
  80:          /// <param name="fluctuationSignal">The fluctuation sub-signal.</param>
  81:          /// <returns>The reconstructed signal.</returns>
  82:          public double[] Reconstruct(double[] trendSignal, double[] fluctuationSignal)
  83:          {
  84:              double[] result = new double[trendSignal.Length + fluctuationSignal.Length];
  85:              for (int i = 0; i < trendSignal.Length; ++i)
  86:              {
  87:                  result[2 * i] = (trendSignal[i] + fluctuationSignal[i]) / System.Math.Sqrt(2.0);
  88:                  result[2 * i + 1] = (trendSignal[i] - fluctuationSignal[i]) / System.Math.Sqrt(2.0);
  89:              }
  90:              return result;
  91:          }
  92:   
  93:          /// <summary>
  94:          /// Performs an n-leveled transform on the specified input. 
  95:          /// </summary>
  96:          /// <param name="input">The input to transform. The length of this array must be divisilbe by 2 ^ level.</param>
  97:          /// <param name="level">The levels of the desired transform.</param>
  98:          /// <returns>
  99:          /// An array containing the results of the transform starting by the highest leveled thrend sub-signal followed
 100:          /// by the fluctuation sub-signals in descending order.
 101:          /// </returns>
 102:          public double[] Transform(double[] input, int level)
 103:          {
 104:              if (input.Length % System.Math.Pow(2, level) != 0)
 105:              {
 106:                  throw new ArgumentException("The number of levels specified can't be applied on the input.");
 107:              }
 108:              double[] result = new double[input.Length];
 109:              double[] trend, fluctuation;
 110:              {
 111:                  for (int i = 0; i < level; ++i)
 112:                  {
 113:                      trend = GetTrendSignal(input);
 114:                      fluctuation = GetFluctuationSignal(input);
 115:                      input = trend;
 116:                      for (int j = 0; j < input.Length; ++j)
 117:                      {
 118:                          result[j] = trend[j];
 119:                          result[j + trend.Length] = fluctuation[j];
 120:                      }
 121:                  }
 122:              }
 123:              return result;
 124:          }
 125:   
 126:          /// <summary>
 127:          /// Performs an n-leveled inverse transform on the input array containing the trend and fluctuation sub-signals.
 128:          /// </summary>
 129:          /// <param name="input">
 130:          /// An array that starts with the highest leveled trend sub-signal followed by the fluctuation
 131:          /// sub-signals in descending order. The length of this array must be divisible by 2 ^ level.
 132:          /// </param>
 133:          /// <param name="level">The desired level of the inverse transform.</param>
 134:          /// <returns>An array containing the result of the inverse transform.</returns>
 135:          public double[] InverseTransform(double[] input, int level)
 136:          {
 137:              if (input.Length % System.Math.Pow(2, level) != 0)
 138:              {
 139:                  throw new ArgumentException("The number of levels specified can't be applied on the input.");
 140:              } 
 141:              double[] trend = input, fluctuation = new double[0];
 142:              for (int i = level; i > 0; --i)
 143:              {
 144:                  int subsignalLength = input.Length / (int)System.Math.Pow(2, i);
 145:                  trend = trend.Take(subsignalLength).ToArray();
 146:                  fluctuation = input.Skip(subsignalLength).Take(subsignalLength).ToArray();
 147:                  trend = Reconstruct(trend, fluctuation);
 148:              }
 149:              return trend;
 150:          }
 151:      }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值