#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3

    Linear Interpolation


    I am trying to use linear interpolation on a data file that has wavelength and another value (its not important what the 2nd value is.) I am using interpolation so i can run another set of wavelengths from a diff. file (slightly different values then the other wavelengths) thru. The original wavelengths tell me what the 2nd value shud be for X wavelength. Now i need to compare another set of wavelengths from a different file and ask what the 2nd variable should be.

    I have been trying to use either, Math::Interpolate, Math::Interpolation, but i cant figure out how to use the module.

    Code:
    #!/usr/bin/perl
    #use warnings;
    use Data::Dumper;
    use FileHandle;
    use FindBin;
    #use strict;
    use lib "$FindBin::Bin/../CLAPv3/";
    use lib "$FindBin::Bin/../CLAPv3/Math/Interpolator/";
    use Math::Interpolate;
    #use PDL::Interpolate;
    #use Math::Interpolate qw(derivatives constant_interpolate
    #                          linear_interpolate robust_interpolate);
    use Math::Interpolate qw(derivatives linear_interpolate);
    #use Math::Interpolator;
    #use Math::Interpolator::Linear;
    #use Math::Interpolator::Source;
    #use Math::Interpolator::Knot;
    #### Done  in Hashes
    
    our %data;
    our %datac;
    &intro;
    
    sub intro {
    	print " Welcome to C.L.A.P. 1.0\n\n";
    	&calcscan;
    	&calccsv;
    }
    sub calcscan {
    	#@files = qw($redscan $bluescan $greenscan);
    	$redscan = 'red_scan.txt';
    	$bluescan = 'blue_scan.txt';
    	$greenscan = 'green_scan.txt';
    		open (FH, $redscan) or die "Oooooh Snap ";
    		while (<FH>) {
    			chomp;
    			next if $. < 417;
    			next if $. > 3664;
    			 ($key,$value) = split (' ');
    			$data{$key}= $value;
    			#print dump(\%data);
    			foreach $key (sort {$a <=> $b} keys %data) {
    			}
    		}
    		close FH;
    }
    sub calccsv {
    	$csv = 'CLAP_sensor_sensitivity.csv';
    	open $FHc, $csv or die "Oh Snap";
    	while (<$FHc>) {
    		chomp;
    		next if $. < 2;
    		#next if $. > 100;
    		 ($keyc,$valuec) = split (' ');
    		chop($keyc);
    		$data{$keyc}= $valuec;
    		#print Dumper(\%data);
    		foreach $keyc (sort {$a <=> $b} keys %datac) {}
    		my @x = $keyc;
    		my @y = $valuec;
    		my @dy =  derivatives( \@x, \@y);
    		my($l_y, $l_dy) = linear_interpolate($value, \@x, \@y);
    		print $l_y, "\n";
    		
    }
    close $FHc;
    
    
    
    }
    I am trying to use Math::Interpolate here.
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
    Why did you comment out the strict and warnings pragmas?

    Your first step is to re-enable those pragmas and fix the problems that they point out.

    Why are you attempting to load Math::Interpolate twice?

    Since that module hasn't been maintained since 1999, I'd suggest that you find newer module which is being maintained. Possibly Math::Interpolator::Robust which is a subclass of Math::Interpolator.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    I think im going to try and take out all the modules and do the task manually. I have found a thread with code similar to what i need but im having a hard time reverse engineering it for my needs.
    Code:
    #!/usr/bin/perl -w
    use strict;
    use Time::Local;
    use Data::Dumper;
    
    my @data;
    my @graph;
    my $one_day = 60*60*24;    #one day in seconds
    
    while (<DATA>)
    {
       next if /^\s*$/;                #skip blank lines
       my ($date, $weight) = split;
       my $epoch = epoch($date);
       push (@data, [$epoch, $weight]);
    }
    
    # input data is sorted already sorted
    # But the algortihm depends upon sorted date information
    # so I did that to make sure
    #
      @data = sort{$a->[0] <=> $b->[0]} @data; 
                                              
    # axis x will be adjusted to #days from the date of first data
    # axis y is in weight  
    
    my ($x_base_epoch, $y1) = @{shift(@data)};
    my $x1_day =0;
                                                
    foreach my $r_xy(@data)
    {
       my ($x2, $y2) = @$r_xy;
       $x2 -= $x_base_epoch;
       my $x2_day = int($x2/$one_day);
         
       # slope is delta weight/ delta days
         my $slope = ($y2-$y1)/($x2_day-$x1_day); 
       
       # fill in missing data points...
       # by linear interpolation 
       
       for (; $x1_day< $x2_day; $x1_day++) # x interval not tested for
                                           # other than 1
       {
          my $y = $slope*($x1_day-$x2_day) + $y2;
          push @graph, [$x1_day,$y];
       }   
             
       $y1= $y2;
    }
    
    #fix-up for last data point
    my ($fx,$fy) = @{$data[-1]};
    push @graph, [($fx-$x_base_epoch)/$one_day, $fy];
    
    ### data to graph is in @graph  ###
    ### I leave that part to the OP ###
    print "$_->[0] $_->[1]\n" foreach @graph;
    
    sub epoch
    {
       my $date = shift;
       my ($month, $day, $year) = split(m|/|,$date);
       my $time = timelocal(0,0,0, $day, $month-1, $year-1900); 
       return $time;
    }
    I need to take out the time factor. I can extract the info from the files and split it appropriately. Epoc is confusing me, im not sure if or how its related to what im trying to do.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    Jun 2012
    Posts
    836
    Rep Power
    496
    Take out all the modules is probably a wrong idea. You have there usually very well written pieces of code, generally much better written than if you or I would write it.

    There are some environments at my work where it is pretty complicated to obtain the installation of a module, I sometimes have to give up and to try to find another solution (like, sometimes, simply copy the code of the .pm module I need), but taking out the modules is a wrong idea.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    I have the same problem with modules. I wont take out all the modules i just need another solution for the interpolation module.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
    I have not used or tested any of the math interpolation modules, but based on your opening question, I wonder if Math::Interpolator::Linear is the module you need. I can't say for sure because I'm not sure what you are needing to accomplish.
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    I have a graph. I need the program to connect the dots(with a line.) Then I give it a random X value. The program will look at the X value and find where it intersects with the 'line' i talked about at the beginning. It will return the Y value (I already know what X is.)

    To sum it up if you have not understood me this far. The program makes an educated guess (based on the data points) as to what the Y value is. The random X i am asking for lies close to the original data points of X but not exactly on any of them.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    for example i have X= 100 and Y = 10. Whats Y going to be when X is 100.1. (remember linear interpolation uses 2 data points that are close together when making the educated guess.)
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Intermediate (1500 - 1999 posts)

    Join Date
    Apr 2009
    Posts
    1,940
    Rep Power
    1225
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    929
    Do you have two points? If so don't bother with a module; recall how you did it in algebra class and compute slope/intercept. Plug in your new x value and have an appropriate amount of fun.

    More than two points? Push the points into an ordinary least squares regression. That will hand you a slope/intercept. Plug in your new x value and have an appropriate amount of fun.

    Statistics::LineFit can be used to perform the regression:

    Code:
    C:\temp>cat ols.pl
    use Statistics::LineFit;
    
    my @x = ( 10, 20, 30 );
    my @y = ( 10, 40, 70 );
    
    $ols = Statistics::LineFit->new;
    $ols->setData( \@x, \@y );
    
    my ($b, $m) = $ols->coefficients;
    
    my $x2 = 15;
    
    printf "Interpolated f(%d) = %d\n", $x2, ($x2 * $m) + $b;
    
    C:\temp>perl ols.pl
    Interpolated f(15) = 25
    Edit--To clarify, I mean if you're interpolating based on two points, not that you only have two points total. (For example if you had a rough outline of a curve and were interpolating from the closest two points on either side of the value you want.) The OLS is only useful if you have many approximations of points on the line. (For example a number of measurements that could contain some discrepancy due to other factors or measurement error.)
    Last edited by OmegaZero; August 11th, 2012 at 08:51 PM.
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    Thanks OmegaZero, ur advice helps.I think I may be able to do it without Statistics module. I need to take X[1] - X[0] and same with Y (equation for slope.) I am going to do something along the lines of using a counter and put " $keyc[i] - $keyc[i+1] " i will need increase by 1 till the end of file. The problem im having is that the list of values is stored inside a scalar value (i thought it went into an array but it didnt.) I cannot access values by doing $keyc[X] because its not in an array. Should i convert it some how? I am talking about this piece of code
    Code:
    ($keyc,$valuec) = split (' ');
    		chop($keyc);
    		$datac{$keyc}= $valuec;
    		foreach $keyc (sort {$a <=> $b} keys %datac) { print $keyc; }
    you can igonore the chop line. I tried switching around some $ to @ to try and make it into an array but i have come up with noting but errors.
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Novice (500 - 999 posts)

    Join Date
    May 2007
    Posts
    765
    Rep Power
    929
    You might do something like:
    Code:
    for $key (sort keys %hash) {
      unless( defined $last_key ) {
        $last_key = $key;
        next;
      }
      # ... do something with $last_key and $hash{$last_key}
      # ... and $key and $hash{$key}
    }
    to avoid using an array.

    I would still stick with the array solution though. Probably something like:
    Code:
    push @array, [ split /\s+/ ] while <FILE>;
    @array= sort { $a->[0] <=> $b->[0] } @array;
    
    for $i ( 1 .. $#array ) {
      # ... do something with $array[$i-1][0] and $array[$i-1][1]
      # ... and $array[$i][0] and $array[$i][1]
    }
    sub{*{$::{$_}}{CODE}==$_[0]&& print for(%:: )}->(\&Meh);
  24. #13
  25. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2012
    Posts
    30
    Rep Power
    3
    I followed your advice, my problem now is adding or subtracting them. This code prints the correct answer for the first value but then it repeats it 100 times instead of moving on. The value it prints is correct mathematically but it is not what i want. This subtracts key - value. $datac{$last_key} = $valuec.
    Code:
    sub calccsv {
    	$csv = 'CLAP_sensor_sensitivity.csv';
    	open $FHc, $csv or die "Oh Snap";
    	while (<$FHc>) {
    		chomp;
    		next if $. < 2;
    		next if $. > 100;
    		 ($keyc,$valuec) = split (' ');
    		chop($keyc);
    		$datac{$keyc}= $valuec;
    		for $key (sort keys %datac) {
    			unless ( defined $last_key) {
    				$last_key = $keyc;
    				next;
    		} 
    		@newkey = $last_key + $datac{$last_key};
    		foreach (@newkey) {
    			print $newkey[1..100], "\n";
    }	
    		
    		#return ($keyc, $valuec);
    
    }

IMN logo majestic logo threadwatch logo seochat tools logo