awk script to calculate delay from trace file ns-3 - awk

I want to measure time between transmitted and received packets in below trace file.
Input:
+ 0.01 /NodeList/1/DeviceList/1/$ns3::PointToPointNetDevice/TxQueue/Enqueue
- 0.01 /NodeList/1/DeviceList/1/$ns3::PointToPointNetDevice/TxQueue/Dequeue
r 0.0200001 /NodeList/0/DeviceList/2/$ns3::PointToPointNetDevice/MacRx
+ 0.11 /NodeList/1/DeviceList/1/$ns3::PointToPointNetDevice/TxQueue/Enqueue
- 0.11 /NodeList/1/DeviceList/1/$ns3::PointToPointNetDevice/TxQueue/Dequeue
r 0.12 /NodeList/0/DeviceList/2/$ns3::PointToPointNetDevice/MacRx
+ 0.12 /NodeList/0/DeviceList/3/$ns3::PointToPointNetDevice/TxQueue/Enqueue
- 0.12 /NodeList/0/DeviceList/3/$ns3::PointToPointNetDevice/TxQueue/Dequeue
r 0.120001 /NodeList/2/DeviceList/2/$ns3::PointToPointNetDevice/MacRx
Here + represents transmitted data and r represents received data. 2nd column in the trace file shows the time.
How can I measure time between r and + for the whole file using awk code?
The expected output can be as below:
Output:
0.0100001
0.01
0.000001
I'll be grateful if anyone helps.

I generated my own trace file, called trace, as follows:
+ 0.1 Stuff stuff and more stuff
- 0.2 Yet more stuff
r 0.4 Something new
+ 0.8 Something else, not so new
- 1.6 Jiggery
r 3.2 Pokery
+ 6.4 Higgledy Piggledy
Then, I would approach your question with awk as follows:
awk '/^+/{tx=$2} /^r/{rx=$2; d=rx-tx; $1=$1 "(d=" d ")"} 1' trace
Sample Output
+ 0.1 Stuff stuff and more stuff
- 0.2 Yet more stuff
r(d=0.3) 0.4 Something new
+ 0.8 Something else, not so new
- 1.6 Jiggery
r(d=2.4) 3.2 Pokery
+ 6.4 Higgledy Piggledy
That says... "If you see a line starting with +, save the second field as variable tx. If you see a line starting with r, save the second field as variable rx. Calculate the difference between rx and tx and save it as d. Rebuild the first field of the line by appending (d=variable d) to the end of whatever it was. The 1 at the end tells awk to do its natural thing - i.e. print the line."

Related

sum 4th field data between the pattern

suppose my data is :
*dnet *1234 1.2
1 port *12 2.3
3 port1 *34 0.2
7 *15 0.1
*dnet *234 0.2
2 *12 0.1
4 *123 *234 1.2
fields are separated by space.
In this I want to get the sum of 4th fields of data present inside each *dnet. Some fields have 4th field data some has not. I want 4th field sum value for each *dnet seperate.
I tried using awk but could not get. It will be thankful if someone helps.
the output for above will look like
*dnet *1234 1.2 2.5
*dnet *234 0.2 1.2
Commented, slightly simplified, version of the comment...
awk '
# look for header line
$1=="*dnet" {
# print any previously calculated sum
if (header) print header, sum
# reset sum for next block of lines
sum = 0
# save new header line
header = $0
# skip remaining actions
next
}
# if we get here, we know this is not a header line
# if there is a 4th field, add it to the sum
$4 {
sum += $4
}
END {
# print the final sum
if (header) print header, sum
}
' datafile

How to do multi-row calculations using awk on a large file

I have a big file that is sorted on the first word. I need to add a new column for each line with the proportional value: line value/total value for that group; group is determined by the first column. In the below example, the total of group "a" = 100 and hence each line gets a proportion. The total of group "the" is 1000 and hence each line gets the proprotion value of the total of that group.
I need an awk script to do this.
Sample File:
a lot 10
a few 20
a great 20
a little 40
a good 10
the best 250
the dog 750
zisty cool 20
Output:
a lot 10 0.1
a few 20 0.2
a great 20 0.1
a little 40 0.4
a good 10 0.1
the best 25 .25
the dog 75 .75
zisty cool 20 1
You describe this as a "big file." Consequently, this solution tries to save memory: it holds no more than one group in memory at a time. When we are done with that group, we print it out before starting on the next group:
$ awk -v i=0 'NR==1{name=$1} $1==name{a[i]=$0;b[i++]=$3;tot+=$3+0;next} {for (j=0;j<i;j++){print a[j],b[j]/tot} name=$1;a[0]=$0;tot=b[0]=$3;i=1} END{for (j=0;j<i;j++){print a[j],b[j]/tot}}' file
a lot 10 0.1
a few 20 0.2
a great 20 0.2
a little 40 0.4
a good 10 0.1
the best 250 0.25
the dog 750 0.75
zisty cool 20 1
How it works
-v i=0
This initializes the variable i to zero.
NR==1{name=$1}
For the first line, set the variable name to the first field, $1. This is the name of the group.
$1==name {a[i]=$0; b[i++]=$3; tot+=$3+0; next}
If the first field matches name, then save the whole line into array a and save the value of column (field) three into array b. Increment the variable tot by the value of the third field. Then, skip the rest of the commands and jump to the next line.
for (j=0;j<i;j++){print a[j],b[j]/tot} name=$1;a[0]=$0;tot=b[0]=$3;i=1
If we get to this line, then we are at the start of a new group. Print out all the values for the old group and initialize the variables for the start of the next group.
END{for (j=0;j<i;j++){print a[j],b[j]/tot}}
After we get to the last line, print out what we have for the last group.
awk '{a[$1]+=$3; b[i++]=$0; c[j++]=$1; d[k++]=$3} END{for(i=0;i<NR;i++) {print b[i], d[i]/a[c[i]]}}' File
Example:
sdlcb#Goofy-Gen:~/AMD$ cat ff
a lot 10
a few 20
a great 20
a little 40
a good 10
the best 250
the dog 750
zisty cool 20
sdlcb#Goofy-Gen:~/AMD$ awk '{a[$1]+=$3; b[i++]=$0; c[j++]=$1; d[k++]=$3} END{for(i=0;i<NR;i++) {print b[i], d[i]/a[c[i]]}}' ff
a lot 10 0.1
a few 20 0.2
a great 20 0.2
a little 40 0.4
a good 10 0.1
the best 250 0.25
the dog 750 0.75
zisty cool 20 1
Logic: update an array (a[]) with first column as index for each line. save array b[] with complete line for each line, to be used in the end for printing. similarly, update arrays c[] and d[] with first and third column values for each line. at the end, use these arrays to get the results using a for loop, looping through all the lines processed. First printing the line as itself, then the proportion value.

How to Read/Store many files using GrADS?

I would like to know if anyone can help me to find the issue about this code in GrADS language.
I'd like to read many files and compute and store them, but when I perform that in GraDS, I have the same answer for all imput file.
Could anyone help me in this problem, please?
'reinit'
****Modify here******
var = v10
ano = 1980
while(ano <= 2013)
*Desire point
local = IAG
**lat = -22.3
**lon = 314.62
latInitialP = -34.58
lonInitialP = 305.43
*******************************************************
'sdfopen C:\Pesquisa_Michelle\dados_amandenha\V10m_'ano'.nc'
*Storing out
'set gxout print'
'set prnopts %10.2f 1 1'
in = 1
test = 1460
if ( math_fmod(ano,4) = 0 )
test = 1464
endif
while(in <= test)
'set t 'in
in2 = in + 3
say in
say in2
'define m = ave('var',t='in',t='in2')'
'set lat 'latInitialP''
'set lon 'lonInitialP''
'd m'
valor = sublin(result,2)
lixo = write('C:\Pesquisa_Michelle\dados_amandenha\'var'_'ano'.txt',valor)
in = in + 4
endwhile
lixo = close(''var'_'ano'.txt')
ano = ano + 1
endwhile
update
I don't get an error (message) about that. That works fine, the problem is the result files. All result files have the first result, like a file replication. When I perform that not using a loop, but changing each value for "ano" by myself, I got different result.
The problem is, in my point of view, the command:
'sdfopen C:\Pesquisa_Michelle\dados_amandenha\V10m_'ano'.nc'
This command aren't replace the files for each "ano".
The problem is that you are never closing your input datafile or resetting grads during your main loop. Consider this example where I open a file:
% grads -l
ga-> open data/semicircle-qv14_s.ctl
Scanning description file: data/semicircle-qv14_s.ctl
Data file data/semicircle-qv14_00%y4_s.dat is open as file 1
LON set to -79.5 79.5
LAT set to -79.5 79.5
LEV set to 0.05 0.05
Time values set: 0:7:3:0 0:7:3:0
E set to 1 1
Notice that it says open as file 1. Now I'll narrow down my selection to a single grid point and display the pressure:
ga-> set lat 0
LAT set to 0.125 0.125
ga-> set lon 0
LON set to 0.125 0.125
ga-> set lev 5
LEV set to 4.92368 4.92368
ga-> d prs
Result value = 55198.4
The pressure is 551 hPa. Looks good. Now lets open another data file without closing this one:
ga-> open data-fine/semicircle-qv14_s.ctl
Scanning description file: data-fine/semicircle-qv14_s.ctl
Data file data-fine/semicircle-qv14_00%y4_s.dat is open as file 2
Notice this says open as file 2. Lets display pressure from this file:
ga-> d prs
Result value = 55198.4
Wait, this is the same value? Yes, because we are still displaying from file 1, here prs is the same as writing prs.1. If we want pressure from the second file, we need to use prs.2:
ga-> d prs.2
Result value = -9.99e+08
Different result (and this on is missing because there is no data at this time step in the second file.
There are two ways to fix this.
Where you are incrementing ano in your loop, add the command close 1. This will close the input data file so when the next one is loaded the display commands will properly display its content.
At the top of your loop, before sdfopen add reinit, which will reset lots of things, including closing all open files. You set your output up in each loop iteration so this shouldn't be a problem for you.

Pascal- How to convert Real to Integer variable

I'm writing a task in pascal.
Everything is ok, just my result is not right.
I'm summing some numbers
Example: 2.3 + 3.4+ 3.3 = 9
But output shows: 9.000000 + EEE or something like that.
So- how to convert, to be only 9, not this REAL variable.
To actually convert:
var
i: integer;
...
i := round(floatVar);
To output only the integer part:
writeln(floatVar:9:0);
Let's consider this quite simpler equation:
3.5 + 2.5
What do you expect? 6, right? Let's try this code
write(3.5 + 2.5);
Unfortunately, it's a floating-point number, so it would produce a number represented in a scientific way:
6.00000000000E+00
or 6.0000000000 x 100, or 6 x 10o. Whatever, you only care about 6, who need this weird useless long number? So the idea is to cut off the decimal part and output to the console only the integer part, which can be done with this line of code:
write(3.5 + 2.5 : 0 : 0);
Ok, now it outputs a beautiful number as expected
6
Seems like the problem is solved, but you say that:
I'm summing some numbers
Example: 2.3 + 3.4+ 3.3 = 9
Ohh so that the evenly, beautiful integer is just randomly appeared? Here the problem comes, how do you expect this equation would output?
3.6 + 2.5
It should be 6.1, right? Let's try it with the worked line of code:
write(3.6 + 2.5 : 0 : 0);
And the output is...
6
Unexpected, right? So how about rounding to some decimal places, like 1?
write(3.5 + 2.5 : 0 : 1);
write(3.6 + 2.5 : 0 : 1);
Then, 3.5 + 2.5 = 6.0 and 3.6 + 2.5 = 6.1. But 6.0 may look quite long, so how to make it output 6 for 6.0 and 6.1 for 6.1?
Actually, you can't make the program auto-detect if a real variable contains an integer value because the way a real var is stored is completely different from an integer var (how different they are, please contact Google; but you can do it manually by making a function to do the job).
So my solution is, to be easy, making the output rounded to some decimal places, and that's it.
For purpose of showing pretty output on the screen you can use something like this:
Writeln(result:0:2);
Result on screen would be this:
9.00
What this means someone would ask? Well first number 0 means how wide filed is. if you say it's 0 then Pascal writes it at the very left side of screen. If you said writeln(result:5:2) result would be:
9.00
In other words i would print form the right side and leave 5 chars to do so.
Second number 2, in this example means you want that result printed with 2 decimal places. You can place it only if you want to print on screen value that is real, single, double, extended and so on.You can round to any number of decimals, and if you do writeln(result:0:0) you would get ouput:
9
If you are printing integer and want to have some length of field, lets sat 5 you would do: writeln(int:5). If you added :2 to the end you would get compile time error.
This all also works for something like this: writeln(5/3.5+sqrt(3):0:3),
You should know that this does not round variable itself but just formats output. This is also legal:
program test;
var
a:real;
n,m:integer;
begin
readln(a,m,n);
writeln(a:m:n);
end.
What i did here is i asked user if on how many decimals and with what length of field he wants to write entered number a. This can be useful so i'm pointing it out. Thank you for reading. I hope i helped
You can convert to string, get the int part, e convert to int number!
Or Float to Str than Str to Int:
nPage := StrToInt(FloatToStr(Int(nReg / nTPages))) + 1;

Plotting a function directly from a text file

Is there a way to plot a function based on values from a text file?
I know how to define a function in gnuplot and then plot it but that is not what I need.
I have a table with constants for functions that are updated regularly. When this update happens I want to be able to run a script that draws a figure with this new curve. Since there are quite few figures to draw I want to automate the procedure.
Here is an example table with constants:
location a b c
1 1 3 4
2
There are two ways I see to solve the problem but I do not know if and how they can be implemented.
I can then use awk to produce the string: f(x)=1(x)**2+3(x)+4, write it to a file and somehow make gnuplot read this new file and plot on a certain x range.
or use awk inside gnuplot something like f(x) = awk /1/ {print "f(x)="$2 etc., or use awk directly in the plot command.
I any case, I'm stuck and have not found a solution to this problem online, do you have any suggestions?
Another possibilty to have a somewhat generic version for this, you can do the following:
Assume, the parameters are stored in a file parameters.dat with the first line containing the variable names and all others the parameter sets, like
location a b c
1 1 3 4
The script file looks like this:
file = 'parameters.dat'
par_names = system('head -1 '.file)
par_cnt = words(par_names)
# which parameter set to choose
par_line_num = 2
# select the respective string
par_line = system(sprintf('head -%d ', par_line_num).file.' | tail -1')
par_string = ''
do for [i=1:par_cnt] {
eval(word(par_names, i).' = '.word(par_line, i))
}
f(x) = a*x**2 + b*x + c
plot f(x) title sprintf('location = %d', location)
This question (gnuplot store one number from data file into variable) had some hints for me in the first answer.
In my case I have a file which contains parameters for a parabola. I have saved the parameters in gnuplot variables. Then I plot the function containing the parameter variables for each timestep.
#!/usr/bin/gnuplot
datafile = "parabola.txt"
set terminal pngcairo size 1000,500
set xrange [-100:100]
set yrange [-100:100]
titletext(timepar, apar, cpar) = sprintf("In timestep %d we have parameter a = %f, parameter c = %f", timepar, apar, cpar)
do for [step=1:400] {
set output sprintf("parabola%04d.png", step)
# read parameters from file, where the first line is the header, thus the +1
a=system("awk '{ if (NR == " . step . "+1) printf \"%f\", $1}' " . datafile)
c=system("awk '{ if (NR == " . step . "+1) printf \"%f\", $2}' " . datafile)
# convert parameters to numeric format
a=a+0.
c=c+0.
set title titletext(step, a, c)
plot c+a*x**2
}
This gives a series of png files called parabola0001.png,
parabola0002.png,
parabola0003.png,
…, each showing a parabola with the parameters read from the file called parabola.txt. The title contains the parameters of the given time step.
For understanding the gnuplot system() function you have to know that:
stuff inside double quotes is not parsed by gnuplot
the dot is for concatenating strings in gnuplot
the double quotes for the awk printf command have to be escaped, to hide them from gnuplot parser
To test this gnuplot script, save it into a file with an arbitrary name, e.g. parabolaplot.gplot and make it executable (chmad a+x parabolaplot.gplot). The parabola.txt file can be created with
awk 'BEGIN {for (i=1; i<=1000; i++) printf "%f\t%f\n", i/200, i/100}' > parabola.txt
awk '/1/ {print "plot "$2"*x**2+"$3"*x+"$4}' | gnuplot -persist
Will select the line and plot it
This was/is another question about how to extract specific values into variables with gnuplot (maybe it would be worth to create a Wiki entry about this topic).
There is no need for using awk, you can do this simply with gnuplot only (hence platform-independent), even with gnuplot 4.6.0 (March 2012).
You can do a stats (check help stats) and assign the values to variables.
Data: SO15007620_Parameters.txt
location a b c
1 1 3 4
2 -1 2 3
3 2 1 -1
Script: (works with gnuplot 4.6.0, March 2012)
### read parameters from separate file into variables
reset
FILE = "SO15007620_Parameters.txt"
myLine = 1 # line index 0-based
stats FILE u (a=$2, b=$3, c=$4) every ::myLine::myLine nooutput
f(x) = a*x**2 + b*x + c
plot f(x) w l lc rgb "red" ti sprintf("f(x) = %gx^2 + %gx + %g", a,b,c)
### end of script
Result: