Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

Calculating cross-correlation

by Anonymous Monk
on Nov 25, 2010 at 08:19 UTC ( [id://873599]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Hi monks, I'm looking for something to calculate cross-correlation for two series. Are there any modules around? Or a snippet of code? I tried looking around CPAN but found no results. Any thoughts? Thanks!

Replies are listed 'Best First'.
Re: Calculating cross-correlation
by tospo (Hermit) on Nov 25, 2010 at 08:35 UTC
    There are a few statistics modules around, e.g. PDL::Stats::Basic can calculate a Pearson correlation coefficient if that's what you need. If you have a lot of statistical analyses to do you might want to use R instead.
Re: Calculating cross-correlation
by mykl (Monk) on Nov 25, 2010 at 12:32 UTC

    If you can't find a module that does cross-correlation, you can always use one of the many FFT implementations - in pseudo-code:

    # input arrays are @f and @g, this calculates @cc which is the cross-c +orrelation of these. @Ff = fft(@f); @Fg = fft(@g); @Fcc = complex_conjugate(@Ff) * @Fg; @cc = inverse_fft(@Fcc);

    This makes use of the fourth of the properties listed here. If your input arrays are purely real, I think it may be possible to optimise this further by performing their FFTs in a single FFT calculation, with a bit of clever maths.

    I did calculation of a cross-correlation using this method some years ago, but it wasn't in Perl, unfortunately.

    --

    "Any sufficiently analyzed magic is indistinguishable from science" - Agatha Heterodyne

      Found one!

      In Math::FFT the author has provided an easy way to use FFTs to calculate cross-correlation:

      $fft1 = new Math::FFT($data1); $fft2 = new Math::FFT($data2); $corr = $fft1->correl($fft2);

      Look under Applications - Correlation in the documention of Math::FFT.

      --

      "Any sufficiently analyzed magic is indistinguishable from science" - Agatha Heterodyne

Re: Calculating cross-correlation
by anonymized user 468275 (Curate) on Nov 25, 2010 at 14:10 UTC
    Cross-correlation is defined for a single series -- the second series for ordinary correlation purposes being the first series dispaced by a phase and tending to have meaning when the first series repeats cyclically -- is this what you really mean? The fact that you talk of two series makes me think you want ordinary correlation as per Statistics::Basic::Correlation

    One world, one people

      I disagree, and so do Wikipedia and Wolfram...

      --

      "Any sufficiently analyzed magic is indistinguishable from science" - Agatha Heterodyne

        I checked your references and they agree with me: Both clearly state that the second series (and third for wolfram) is derived from the first; the wolfram version has a total of three series but in which the two complex functions f and g are both derived from the same starting series. In both cases there is only one driving variable, everything else is derived. If you start with two series, you want ordinary correlation, not cross-correlation.

        One world, one people

Re: Calculating cross-correlation
by anonymized user 468275 (Curate) on Nov 25, 2010 at 17:11 UTC
    suppose you have two sets @x and @y, then to employ correlation to check for cross-correlation between them, you have to simulate the phasing yourself as far as I know; something like this is what is on my mind:
    use Statistics::Basic::Correlation; sub xcorr { # given two sets and a phase increment, return # at which phase the best correlation is found # and what that value is my ($xref, $yref, $incdeg ) = @_; my $maxcorr = -1; $incdeg ||= 1; default 1 degree of phase. die "sets of unequal size" if ( $#$xref != $#$yref ); my $indexinc = $incdeg * ( 1 + $#$xref ); my $iters = 360 / $incdeg; { use integer; $indexinc /= 360; $iters++; } $indexinc ||=1; my @copy = @$yref; my $where = 0; my $match = 0; for (my $i = 0; $i < $iters; $i++) { unshift @copy, ( pop @copy ) for ( 1 .. $indexinc ); my $res = correlate( $xref, \@copy ); if ( $res > $maxcorr ) { $maxcorr = $res; $match = $where; } $where += $incdeg; } return ( $match, $maxcorr ); }
    (updated the code)

    More update:

    - the arrays are passed by reference i.e. \@x and \@y

    - the approach does not take into account potential change of amplitude of one of the signals relative to the other, which is not taken into account by correlation alone. To compensate if necessary, find s(x)/s(y) where s() is standard deviation found using Statistics::Basic::StdDev and multiply all @copy by that before iterating through the phase shifts.

    One world, one people

Re: Calculating cross-correlation
by jabowery (Beadle) on Nov 06, 2013 at 21:45 UTC
    This thread is probably the most confusing thread I've ever run across in PerlMonks. I mean, with such stark disagreement you'd expect there to at least be some ratings applied.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://873599]
Approved by moritz
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (5)
As of 2024-03-28 11:06 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found