This guide provides a comprehensive overview of the core functionalities and best practices for the CCMA library.
The CCMA library is designed in an object-oriented style. To begin, initialize the CCMA object:
from ccma import CCMA
ccma = CCMA()During initialization, the CCMA object prepares kernels and sets filtering width parameters. You can customize the filtering for moving average over points (w_ma) and moving average for curvature correction (w_cc) during initialization:
ccma = CCMA(w_ma=3, w_cc=2)Once the CCMA object is initialized, you can smooth a sequence of N points, provided as a NumPy array with dimensions Nx2 or Nx3:
smoothed_points = ccma.filter(noisy_points)The CCMA utilizes kernels to determine weights for convolution operations. Several predefined kernels are available:
- Uniform (Rectangular) [
uniform]—Assigns equal weights to all points. - Pascal's Triangle (Default) [
pascal]—A discrete Gaussian distribution, balancing accuracy and smoothness. - Hanning (Raised Cosine) [
hanning]—Ideal for signal processing, particularly effective for smoothing. - Truncated Gaussian [
normal]—Versatile kernel with adjustable cutoff areas (rho_maandrho_cc).
Specify a kernel during initialization:
ccma = CCMA(distrib="pascal")For the truncated Gaussian kernel, you can set the cutoff area:
ccma = CCMA(distrib="normal", rho_ma=0.95, rho_cc=0.9)If the provided kernels don't meet your requirements, define your own kernel function:
ccma = CCMA(distrib=get_triangle_kernel)Here's an example of a custom triangle kernel:
import numpy as np
def get_triangle_kernel(width):
ramp = np.array(range(1, width + 1))
half_width = width // 2 + 1
ramp[-half_width:] = ramp[:half_width][::-1]
triangle_kernel = ramp / np.sum(ramp)
return triangle_kernelNote
Kernel width is always an odd value (e.g., 1, 3, 5, ...).
Tip
Start with pascal or hanning for general use. Avoid uniform unless you have specific requirements.
If you wish to employ distinct kernels for smoothing and curvature correction,
you have the flexibility to do so by specifying distrib_ma and distrib_cc.
In scenarios where both distrib_ma and distrib are set,
the former takes precedence. The same rule applies to distrib_cc.
ccma = CCMA(w_ma=5, w_cc=2, distrib_ma="hanning")In this example, the hanning kernel is designated for smoothing,
while the pascal kernel is automatically assigned for curvature correction since no specific distrib_cc is set.
Consequently, the default distrib specification, which is set to pascal,
is utilized for curvature correction.
Tip
Using hanningfor smoothing and pascal for curvature correction can be a strategic approach.
Leveraging the beneficial characteristics of the hanning kernel for smoothing
and then the accuracy of the pascal kernel for curvature reconstruction.
Similar to convolution, boundaries require additional handling. Different strategies are available:
- None [
none]—No boundary strategy is applied. - Padding
padding]—Replicate the last points on each end forw_ccmatimes. - Wrapping [
wrapping]—Treat the sequence as closed/periodic, adding the first and lastw_ccmapoints to the opposite end. - Decreasing Filtering Width [
fill_boundary]—Filter the ends with decreasing width, trying to maintain equality betweenw_maandw_cc. Furthermore, the objective isw_ma>=w_cc
Example:
ccma = CCMA(mode="fill_boundary", w_ma=1, w_cc=2)This would result in the following decreasing filtering parameters at the boundaries:
>>> ccma._get_descending_width()
[{'w_ma': 1, 'w_cc': 1}, {'w_ma': 1, 'w_cc': 0}, {'w_ma': 0, 'w_cc': 0}]To apply only the moving average without curvature correction, set cc_mode to False:
ccma = CCMA()
# Apply the moving average without curvature correction
ccma.filter(noisy_points, cc_mode=False)If you have additional insights or suggestions to enhance the overall quality and utility of the code, please feel free to share them. Your input is highly valued, and any ideas for improvement that contribute to the code's clarity, efficiency, or user-friendliness will be greatly appreciated.
Thank you in advance for your constructive feedback!