File Coverage

blib/lib/Feed/PhaseCheck.pm
Criterion Covered Total %
statement 46 52 88.4
branch 13 22 59.0
condition 9 20 45.0
subroutine 6 6 100.0
pod 1 1 100.0
total 75 101 74.2


line stmt bran cond sub pod time code
1             package Feed::PhaseCheck;
2              
3 1     1   20736 use 5.006;
  1         2  
4 1     1   3 use strict;
  1         2  
  1         15  
5 1     1   3 use warnings;
  1         1  
  1         23  
6              
7 1     1   3 use Exporter qw(import);
  1         0  
  1         426  
8              
9             our @EXPORT_OK = qw(compare_feeds);
10              
11             # ABSTRACT: Finds the relative time delay between two feed segments.
12              
13             =head1 NAME
14              
15             Feed::PhaseCheck
16              
17             Finds the relative time delay between two feed segments.
18              
19             Accomplished by shifting one feed relative to the other and then computing the error (absolute difference).
20              
21             The shift that yields the lowest error corresponds to the relative delay between he two input feeds.
22              
23             The output consists of the delay found, and the error in delayed point.
24              
25             =cut
26              
27             our $VERSION = '0.06';
28              
29             =head1 SYNOPSIS
30              
31             use Feed::PhaseCheck qw(compare_feeds);
32             my $sample = {
33             "1451276654" => "1.097655",
34             "1451276655" => "1.09765",
35             #...
36             "1451276763" => "1.0976",
37             "1451276764" => "1.097595"
38             };
39             my $compare_to = {
40             "1451276629" => "1.09765",
41             "1451276630" => "1.09764916666667",
42             #...
43             "1451276791" => "1.097595",
44             "1451276792" => "1.097595"
45             };
46             my $max_delay_check = 30; # seconds
47             my ($errors,$delay_with_min_err) = compare_feeds($sample,$compare_to,$max_delay_check);
48              
49             =cut
50              
51             =head1 METHODS
52              
53             =head2 compare_feeds
54              
55             =cut
56              
57             sub compare_feeds {
58 1     1 1 160 my $sample = shift;
59 1         2 my $main = shift;
60 1   50     2 my $max_delay_check = shift || 0;
61              
62 1 50       14 if ($max_delay_check !~ /^\d+$/) {
63 0         0 return;
64             }
65              
66 1 50 33     14 if (ref $sample ne 'HASH' || scalar keys %$sample < 2) {
67 0         0 return;
68             }
69              
70 1 50 33     7 if (ref $main ne 'HASH' || scalar keys %$main < 2) {
71 0         0 return;
72             }
73              
74 1         58 my @main_epoches = sort keys %$main;
75 1         7 foreach (@main_epoches) {
76 164 50 33     490 if (int($_) != $_ || abs($main->{$_}) != $main->{$_}) {
77 0         0 return;
78             }
79             }
80              
81 1         9 my @sample_epoches = sort keys %$sample;
82 1         3 foreach (@sample_epoches) {
83 26 50 33     82 if (int($_) != $_ || abs($sample->{$_}) != $sample->{$_}) {
84 0         0 return;
85             }
86             }
87              
88 1 50 33     6 if ($sample_epoches[0] < $main_epoches[0] || $sample_epoches[-1] > $main_epoches[-1]) {
89 0         0 return;
90             }
91              
92 1         44 my %main = %$main;
93 1         6 my %error = ();
94 1         1 my ($min_error, $delay_for_min_error);
95 1 50       25 my $delay1 = $sample_epoches[0] - $main_epoches[0] < $max_delay_check ? $sample_epoches[0] - $main_epoches[0] : $max_delay_check;
96 1 50       3 my $delay2 = $main_epoches[-1] - $sample_epoches[-1] < $max_delay_check ? $main_epoches[-1] - $sample_epoches[-1] : $max_delay_check;
97 1         5 for (my $delay = -$delay1; $delay <= $delay2; $delay++) {
98 54         51 $error{$delay} = 0;
99 54         49 foreach my $epoch (@sample_epoches) {
100 1404         853 my $sample_epoch = $epoch - $delay;
101 1404 100       1626 if (!defined $main{$sample_epoch}) {
102 3         7 for (my $i = 1; $i < scalar keys @main_epoches; $i++) {
103 3 50       7 if ($main_epoches[$i] > $sample_epoch) {
104             $main{$sample_epoch} = _interpolate(
105             $main_epoches[$i - 1],
106             $main{$main_epoches[$i - 1]},
107 3         9 $main_epoches[$i], $main{$main_epoches[$i]},
108             $sample_epoch
109             );
110 3         3 last;
111             }
112             }
113             }
114 1404         1473 $error{$delay} += ($main{$sample_epoch} - $sample->{$epoch})**2;
115             }
116 54 100 100     168 if (!defined $min_error || $error{$delay} < $min_error) {
117 13         9 $min_error = $error{$delay};
118 13         20 $delay_for_min_error = $delay;
119             }
120             # $error{$delay} =~ s/(\d{8}).+?e/$1e/;
121             }
122              
123 1         20 return (\%error, $delay_for_min_error);
124             }
125              
126             sub _interpolate {
127 3     3   5 my ($x1, $y1, $x2, $y2, $x) = @_;
128 3         5 my $y = $y1 + ($x - $x1) * ($y2 - $y1) / ($x2 - $x1);
129 3         7 return $y;
130             }
131              
132             =head1 AUTHOR
133              
134             Maksym Kotielnikov, C<< >>
135              
136             =head1 BUGS
137              
138             Please report any bugs or feature requests to C, or through
139             the web interface at L. I will be notified, and then you'll
140             automatically be notified of progress on your bug as I make changes.
141              
142              
143              
144              
145             =head1 SUPPORT
146              
147             You can find documentation for this module with the perldoc command.
148              
149             perldoc Feed::PhaseCheck
150              
151              
152             You can also look for information at:
153              
154             =over 4
155              
156             =item * RT: CPAN's request tracker (report bugs here)
157              
158             L
159              
160             =item * AnnoCPAN: Annotated CPAN documentation
161              
162             L
163              
164             =item * CPAN Ratings
165              
166             L
167              
168             =item * Search CPAN
169              
170             L
171              
172             =back
173              
174              
175             =head1 ACKNOWLEDGEMENTS
176              
177              
178              
179             =cut
180              
181             1; # End of Feed::PhaseCheck