1 2 3 4 5 6 #### C:\> manet.pl 9 -g 40 -s 2 -S -G 1 #### #!/usr/bin/perl -w use vars qw($VERSION); $VERSION = "1.0 - 16 APR 2010"; use strict; use warnings; use Getopt::Long qw(:config no_ignore_case); #bundling use Pod::Usage; my %opt; my ($opt_help, $opt_man, $opt_versions); GetOptions( 'acceleration=i' => \$opt{acceleration}, 'delay=i' => \$opt{delay}, 'Distances:s' => \$opt{Distances}, 'grid=i' => \$opt{size}, 'Grid:s' => \$opt{Grid}, 'iterations=i' => \$opt{loop}, 'Locations:s' => \$opt{Locations}, 'signal=f' => \$opt{multiplier}, 'Signals:s' => \$opt{Signals}, 'help!' => \$opt_help, 'man!' => \$opt_man, 'versions!' => \$opt_versions ) or pod2usage(-verbose => 0); pod2usage(-verbose => 1) if defined $opt_help; pod2usage(-verbose => 2) if defined $opt_man; if(defined $opt_versions){ print "\nModules, Perl, OS, Program info:\n", " $0\n", " Version $VERSION\n", " strict $strict::VERSION\n", " warnings $warnings::VERSION\n", " Pod::Usage $Pod::Usage::VERSION\n", " Getopt::Long $Getopt::Long::VERSION\n", " Perl version $]\n", " Perl executable $^X\n", " OS $^O\n", "\n\n"; exit } # Start Program ######################################################## if ((!@ARGV) || ($ARGV[0] !~ /^\d+$/)) { pod2usage(-verbose => 0, -message => "$0: number of nodes required\n") } if ($ARGV[0] < 2) { pod2usage(-verbose => 0, -message => "$0: number of nodes >= 2\n") } my @nodes; my $numnodes = $ARGV[0]; my $delay = $opt{delay} || 0; my $acceleration = $opt{acceleration} || 2; $acceleration += 1; my $size = $opt{size} || 5*$numnodes; $size -= 1; my $iterations = $opt{loop} || -1; my $multiplier = $opt{multiplier} || 1; if ($size <= $numnodes) { $size = 5*$numnodes - 1; } if ($multiplier <= 0) { $multiplier = 1 } # Initialize Nodes for my $i (1..$numnodes) { my %coords; $coords{x} = $coords{y} = int($size/2); $nodes[$i] = \%coords; } my $i = 0; while ($i++ != $iterations) { move(\@nodes, $size); if (defined($opt{Distances}) || defined($opt{Grid}) || defined($opt{Locations}) || defined($opt{Signals})) { print "---- ITERATION $i ----\n" } if (defined($opt{Locations})) { print "LOCATIONS\n"; print_locations(\@nodes); if ($opt{Locations} ne '') { if ($^O eq 'MSWin32') { system('cls') } else { system('clear') } } } my ($distances, $signals) = compute(\@nodes); if (defined($opt{Distances})) { print "DISTANCES\n"; print_metrics(\@nodes, $distances); if ($opt{Distances} ne '') { if ($^O eq 'MSWin32') { system('cls') } else { system('clear') } } } if (defined($opt{Signals})) { print "SIGNALS\n"; print_metrics(\@nodes, $signals); if ($opt{Signals} ne '') { if ($^O eq 'MSWin32') { system('cls') } else { system('clear') } } } print "UNION/INTERSECTION\n"; print_union(\@nodes, $signals); if (defined($opt{Grid})) { print "GRID\n"; print_grid(\@nodes, $size); if ($opt{Grid} ne '') { if ($^O eq 'MSWin32') { system('cls') } else { system('clear') } } } sleep ($delay); } ######################################## sub compute { my ($node) = @_; my @distance; my @signal; for my $i (1..$#{$node}) { for my $j ($i+1..$#{$node}) { # Pythagoras $distance[$i][$j] = sqrt( (($node->[$i]->{x} - $node->[$j]->{x}) * ($node->[$i]->{x} - $node->[$j]->{x})) + (($node->[$i]->{y} - $node->[$j]->{y}) * ($node->[$i]->{y} - $node->[$j]->{y})) ); # Signal by distance if ($distance[$i][$j] <= 1 * $multiplier) { $signal[$i][$j] = 5; } elsif ($distance[$i][$j] <= 2 * $multiplier) { $signal[$i][$j] = 4; } elsif ($distance[$i][$j] <= 3 * $multiplier) { $signal[$i][$j] = 3; } elsif ($distance[$i][$j] <= 4 * $multiplier) { $signal[$i][$j] = 2; } elsif ($distance[$i][$j] <= 5 * $multiplier) { $signal[$i][$j] = 1; } else { $signal[$i][$j] = 0; } } } return (\@distance, \@signal) } sub move { my ($node, $size) = @_; for my $i (1..$#{$node}) { my $speed = int(rand($acceleration)); my $dir = int(rand(9)); if ($speed > 0) { # Direction is as follows. Node starts at 4 # # 0 1 2 # 3 4 5 # 6 7 8 # if ($dir == 0) { if (($node->[$i]->{x} - $speed) >= 0) { $node->[$i]->{x} -= $speed } if (($node->[$i]->{y} - $speed) >= 0) { $node->[$i]->{y} -= $speed } } elsif ($dir == 1) { if (($node->[$i]->{y} - $speed) >= 0) { $node->[$i]->{y} -= $speed } } elsif ($dir == 2) { if (($node->[$i]->{x} + $speed) <= $size) { $node->[$i]->{x} += $speed } if (($node->[$i]->{y} - $speed) >= 0) { $node->[$i]->{y} -= $speed } } elsif ($dir == 3) { if (($node->[$i]->{x} - $speed) >= 0) { $node->[$i]->{x} -= $speed } } elsif ($dir == 4) { # no move } elsif ($dir == 5) { if (($node->[$i]->{x} + $speed) <= $size) { $node->[$i]->{x} += $speed } } elsif ($dir == 6) { if (($node->[$i]->{x} - $speed) >= 0) { $node->[$i]->{x} -= $speed } if (($node->[$i]->{y} + $speed) <= $size) { $node->[$i]->{y} += $speed } } elsif ($dir == 7) { if (($node->[$i]->{y} + $speed) <= $size) { $node->[$i]->{y} += $speed } } elsif ($dir == 8) { if (($node->[$i]->{x} + $speed) <= $size) { $node->[$i]->{x} += $speed; } if (($node->[$i]->{y} + $speed) <= $size) { $node->[$i]->{y} += $speed } } } } } sub print_locations { my ($node) = @_; for my $i (1..$#{$node}) { printf "$i => (%i,%i)\n", $node->[$i]->{x}, $node->[$i]->{y} } print "\n" } sub print_grid { my ($node, $size) = @_; my @grid; for my $i (1..$#{$node}) { $grid[$node->[$i]->{x}][$node->[$i]->{y}] = $i } print "-" for (0..$size+2); print "\n"; for my $y (0..$size) { print "|"; for my $x (0..$size) { printf "%s", defined($grid[$x][$y]) ? $grid[$x][$y] : " " } print "|\n" } print "-" for (0..$size+2); print "\n" } sub print_metrics { my ($node, $metric) = @_; print " "; for my $i (2..$#{$node}) { printf "%5i ", $i } print "\n "; for my $i (2..$#{$node}) { printf "----- ", } print "\n"; for my $i (1..$#{$node}-1) { printf "%2i] ", $i; for my $j (2..$#{$node}) { my $p = sprintf "%2.2f", defined($metric->[$i][$j]) ? $metric->[$i][$j] : 9999; printf "%5s ", ($p == 9999) ? " - " : $p } print "\n" } print "\n" } sub print_union { my ($node, $signal) = @_; # PERL CODE found for union/intersection # # foreach $e (@a) { $union{$e} = 1 } # foreach $e (@b) { # if ( $union{$e} ) { $isect{$e} = 1 } # $union{$e} = 1; # } # @union = keys %union; # @isect = keys %isect; my (@srcs, @dsts); for my $i (1..$#{$node}-1) { for my $j (2..$#{$node}) { if (defined($signal->[$i][$j])) { if ($signal->[$i][$j] > 0) { push @srcs, $i; push @dsts, $j; push @srcs, $j; push @dsts, $i } } } } my %neighbors; for my $n (1..$#{$node}) { my @neighbor; # print "$n -> "; for my $i (0..$#srcs) { if ($srcs[$i] == $n) { # print "$dsts[$i] "; push @neighbor, $dsts[$i] } } $neighbors{$n} = \@neighbor; # print "\n" } my %allnodes; my %seen; my @onstack; my $FULL= 0; my $DONE = 0; my @nodeneigh; for my $n (1..$#{$node}) { if (!exists($allnodes{$n})) { (%seen, @onstack) = (); while (1) { if (!exists($seen{$n})) { $seen{$n} = 1; $allnodes{$n} = 1; push @onstack, $n } my $a = pop @onstack; if (!defined($a)) { last } do_it($a, \%neighbors, \%seen, \%allnodes, \@onstack); if ((my $hshcount = keys %seen) == $#{$node}) { $FULL = 1; last } if ((my $hshcount = keys %allnodes) == $#{$node}) { $DONE = 1; last } } if ($FULL) { last } else { my @temp; push @temp, $_ for (keys %seen); $nodeneigh[$n] = \@temp; if ($DONE) { last } } } } if ($FULL) { print "FULL\n" } else { for my $i (@nodeneigh) { my $NEWLINE; for my $j (@{$i}) { if (defined($j)) { print "$j "; $NEWLINE = 1 } } if ($NEWLINE) { print "\n" } } } print "\n"; sub do_it { my ($n, $neighbors, $seen, $allnodes, $onstack) = @_; for my $neighbor (@{$neighbors->{$n}}) { if (!exists($seen->{$neighbor})) { $seen->{$neighbor} = 1; $allnodes->{$neighbor} = 1; push @{$onstack}, $neighbor; do_it($neighbor, $neighbors, $seen, $allnodes, $onstack) } } } } ######################################################## # End Program __END__ =head1 NAME MANET - Simulate MANET =head1 SYNOPSIS manet [options] nodes =head1 DESCRIPTION Mobile Ad-Hoc Network (MANET) simulator takes a variable number of nodes and creates an appropriate grid size to randomly move the nodes about. Distance and signal strength are computed for each iteration of node moves. =head1 ARGUMENTS nodes The number of nodes. =head1 OPTIONS: -a # Use # as an optional acceleration multiplier for --acceleration each node move. A random number x: 0 <= x <= # is chosen to accelerate the move in the randomly selected direction for each node on each iteration. DEFAULT: (or not specified) 2. -D [1] Print distance between each node matrix. --Distances Optional argument causes screen refresh after each iteration. -g # Force grid size of # x #. nodes < # < MAX_INT --grid DEFAULT: (or not specified) nodes*5 x nodes*5. -G [1] Print visual representation of grid with nodes. -Grid Optional argument causes screen refresh after each iteration. -i # Run the simulation # times. -iterations DEFAULT: (or not specified) Loop forever. -L [1] Print node coordinates. -Locations Optional argument causes screen refresh after each iteration. -s # Signal multiplier. There are 6 signal levels: -signal 0 = no signal 1 = weak 2 = weak-to-moderate 3 = moderate 4 = moderate-to-strong 5 = strong By default, signal is inversely proportional to node distance. Distance between nodes <= 1 --> Signal 5 Distance between nodes <= 2 --> Signal 4 Distance between nodes <= 3 --> Signal 3 Distance between nodes <= 4 --> Signal 2 Distance between nodes <= 5 --> Signal 1 Distance between nodes > 5 --> Signal 0 This option # allows for a floating point number multiplier to adjust signal calculation as below: Distance between nodes <= 1 * # --> Signal 5 Distance between nodes <= 2 * # --> Signal 4 Distance between nodes <= 3 * # --> Signal 3 Distance between nodes <= 4 * # --> Signal 2 Distance between nodes <= 5 * # --> Signal 1 Distance between nodes > 5 * # --> Signal 0 DEFAULT: (or not specified) 1. -S [1] Print signal strenght between each node matrix. -Signals Optional argument causes screen refresh after each iteration. --help Print Options and Arguments. --man Print complete man page. --versions Print Modules, Perl, OS, Program info. =head1 LICENSE This software is released under the same terms as Perl itself. If you don't know what that means visit L. =head1 AUTHOR Copyright (C) Michael Vincent 2010 L All rights reserved =cut