'@desc;Function to smooth data via kernels by converting every point to the corresponding kernel and summing the result.
'@param;sy;Range;The y coordinates
'@param;sx;Range;The x coordinates
'@param;kernel type;Variant;The kernel to apply. Should be one of Gaussian, Uniform, Triangular, Epanechnikov, Quartic, Cubic, Logistic or Cosine. Defaults to Gaussian.
'@param;scale;Variant;The size of the kernel
'@return;Variant;The smoothed points
Dim outputRows As Long
Dim outputCols As Long
Dim output() As Double
Dim vert As Boolean
Dim vertOutput As Boolean
Dim i As Integer
Dim j As Integer
Dim k As Integer
Dim x() As Double
Dim y() As Double
Dim kernel As String
Dim tot_ker1 As Double
Dim tot_ker2 As Double
Dim b() As Double
Dim temp_ker As Double
'Test whether data is arranged vertically or horizontally
vert = False
k = sy.Columns.Count
If sy.Rows.Count > sy.Columns.Count Then
vert = True
k = sy.Rows.Count
End If
With Application.Caller
outputRows = .Rows.Count
outputCols = .Columns.Count
End With
ReDim output(1 To outputRows, 1 To outputCols)
'Test whether output is arranged vertically or horizontally
vertOutput = False
If outputRows > outputCols Then
vertOutput = True
End If
'Check that output range is the same size as input range
If outputRows <> sy.Rows.Count And outputCols <> sy.Columns.Count Then Exit Function
'Populate output with zeroes
For i = 1 To outputRows
For j = 1 To outputCols
output(i, j) = 0
Next
Next
'Redimension variables
ReDim x(1 To k)
ReDim y(1 To k)
ReDim b(1 To k)
'Define kernels
If IsMissing(kerneltype) Then
kernel = "k_G"
ElseIf kerneltype = "Gaussian" Or kerneltype = "G" Then
kernel = "k_G"
ElseIf kerneltype = "Uniform" Or kerneltype = "U" Then
kernel = "k_U"
ElseIf kerneltype = "Triangular" Or kerneltype = "T" Then
kernel = "k_T"
ElseIf kerneltype = "Epanechnikov" Or kerneltype = "E" Then
kernel = "k_E"
ElseIf kerneltype = "Quartic" Or kerneltype = "Q" Then
kernel = "k_Q"
ElseIf kerneltype = "Cubic" Or kerneltype = "C" Then
kernel = "k_C"
ElseIf kerneltype = "Logistic" Or kerneltype = "L" Then
kernel = "k_L"
ElseIf kerneltype = "Cosine" Or kerneltype = "Co" Then
kernel = "k_Co"
Else
kernel = "k_G"
End If
'Define scale
If IsMissing(scaleP) Then
For i = 1 To k
b(i) = 1
Next
Else
If TypeName(scaleP) = "Range" Then
If scaleP.Rows.Count = 1 And scaleP.Columns.Count = 1 Then
For i = 1 To k
b(i) = scaleP
Next
ElseIf scaleP.Rows.Count <> sy.Rows.Count And scaleP.Columns.Count <> sy.Columns.Count Then
Exit Function
ElseIf scaleP.Rows.Count > scaleP.Columns.Count Then
For i = 1 To k
b(i) = scaleP(i, 1).Value
Next
Else
For i = 1 To k
b(i) = scaleP(1, i).Value
Next
End If
Else
For i = 1 To k
b(i) = scaleP
Next
End If
End If
'Populate temporary variables
For i = 1 To k
If sx Is Nothing Then
x(i) = i
Else
If vert = True Then
x(i) = sx(i, 1).Value
y(i) = sy(i, 1).Value
Else
x(i) = sx(1, i).Value
y(i) = sy(1, i).Value
End If
End If
Next
For i = 1 To k
tot_ker1 = 0
tot_ker2 = 0
For j = 1 To k
If kernel = "k_U" Then
temp_ker = k_U(x(i), x(j), b(j))
ElseIf kernel = "k_T" Then
temp_ker = k_T(x(i), x(j), b(j))
ElseIf kernel = "k_E" Then
temp_ker = k_E(x(i), x(j), b(j))
ElseIf kernel = "k_Q" Then
temp_ker = k_Q(x(i), x(j), b(j))
ElseIf kernel = "k_C" Then
temp_ker = k_C(x(i), x(j), b(j))
ElseIf kernel = "k_L" Then
temp_ker = k_L(x(i), x(j), b(j))
ElseIf kernel = "k_Co" Then
temp_ker = k_Co(x(i), x(j), b(j))
Else
temp_ker = k_G(x(i), x(j), b(j))
End If
tot_ker1 = tot_ker1 + temp_ker * y(j)
tot_ker2 = tot_ker2 + temp_ker
Next
If vertOutput = True Then
output(i, 1) = tot_ker1 / tot_ker2
Else
output(1, i) = tot_ker1 / tot_ker2
End If
Next
SmoothKernel = output
End Function