File: SavitzkyGolay.pm

package info (click to toggle)
libdemeter-perl 0.9.27%2Bds6-9
  • links: PTS, VCS
  • area: contrib
  • in suites: forky, sid, trixie
  • size: 74,028 kB
  • sloc: perl: 73,233; python: 2,196; makefile: 1,999; ansic: 1,368; lisp: 454; sh: 74
file content (46 lines) | stat: -rw-r--r-- 1,366 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package Demeter::Data::SavitzkyGolay;
use Moose::Role;

use PDL::Lite;

sub _sgolay {
  my ($self, $p, $n, $m, $ts) = @_;
  die "sgolay needs an odd filter length n" if ($n%2 != 1);
  die "sgolay needs filter length n larger than polynomial order p" if ($p >- $n);
  $m ||= 0;
  $ts ||= 1;

  my $filter = PDL->zeros($p, $n);
  my $f = PDL->zeros($n, $n);
  my $k = int($n/2);
  foreach my $row (0 .. $k) {
    ## Construct a matrix of weights Cij = xi ^ j.  The points xi are
    ## equally spaced on the unit grid, with past points using negative
    ## values and future points using positive values.
    #    C = ( [(1:n)-row]'*ones(1,p+1) ) .^ ( ones(n,1)*[0:p] );
    my $seq = PDL->sequence($n)+1-$row;
    my $prod = $seq->transpose x ones($p+1);
    my $exp = PDL->ones(1, $n) * sequence($p+1);
    my $c = $prod ** $exp;

    ## A = pseudo-inverse (C), so C*A = I; this is constructed from the SVD
    # A = pinv(C);
    my ($u, $s, $v, $info) = $c->svd;
    my $a = $v x stretcher(1/$s) x $u->transpose;

    ## Take the row of the matrix corresponding to the derivative
    ## you want to compute.
    # F(row,:) = A(1+m,:);
    $filter(:,$row) .= $a->slice(":,$m")
  };
  ## The filters shifted to the right are symmetric with those to the left.
  #F(k+2:n,:) = (-1)^m*F(k:-1:1,n:-1:1);
  #$filter(:,$k+2)
  return $filter;
};

sub sgolayfilt {

};

1;