how to use Tcl language to control simulation - tcl

I want to use tcl to control simulation iteration.
In each iteration, I get some random value, and save the results
set set_of_double_values{0}
foreach y_val $set_of_double_values {
set_parameter Snr $y_val ;
set numsim 2;
set_value/$env(sim_name)/numsim $numsim;
for {set i 0} {$i < $numsim} {incr i 1} {
some random value
}
run_iteration;
}
run_iteration
using this code, I always run the inner part many times, and I can not save the right results...

Related

Does TCL containg built in functions of type get_bits and set_bits?

The get_bits will return specific bits of a value and set_bits will set specific bits of a value to a specified value. Does TCL contain such functions built in or should they be written by the user?
The binary scan command does come close to the get_bits function but is not the same thing.
There's no specific function for getting or setting a particular bit. We can make them.
proc get_bit {value bit} {
expr {($value & (1 << $bit)) != 0}
}
proc set_bit {varName bit {value 1}} {
upvar 1 $varName var
if {$value} {
set var [expr {$var | (1 << $bit)}]
} else {
set var [expr {$var & ~(1 << $bit)}]
}
}
Those will work with integer values of any width; you're not restricted to 32 bits or 64 bits.
# Lots of bits!
set x 123456789012345678901234567890
# Fetch a particular bit
puts [get_bit $x 17]
# Set a bit to 1
set_bit x 78
puts "x = $x"
# Set a bit to 0
set_bit x 75 0
puts "x = $x"

Assign random number to node in TCL script for ns-2: ERROR variable is array

I am trying to run the following tcl script but getting an error
can't set "val": variable is array
while executing
"set val [random_int $upper_limit]"
Here is my code,Please any help
proc random_int { upper_limit } {
global myrand
set myrand [expr int(rand() * $upper_limit + 1)]
return $myrand
}
set upper_limit 21
set val [random_int $upper_limit]
$ns at 0.6 "[$node($val) set ragent_] malicious"
Your current main problem is that there's an existing use of the val as an array; Tcl's variables can't simultaneously be scalars and arrays. The most expedient fix is to change the name of the variable, perhaps to value.
set value [random_int $upper_limit]
$ns at 0.6 "[$node($value) set ragent_] malicious"
Apart from that, your random number generator could be a bit sharper code. It probably doesn't need to access any global variables, and it really should have the expression put in braces (for a bunch of reasons including both speed and safety). Here's the trimmed/tuned version:
proc random_int { upper_limit } {
expr { int(rand() * $upper_limit + 1) }
}
Occasionally, I write such procedures slightly differently, like this:
proc random_int { upper_limit } {expr {
int(rand() * $upper_limit + 1)
}}
It's semantically identical, but it makes it clearer what the author is really thinking about.

multidimensional array search in tcl

I am using multidimensional associative array in tcl ,from fourth column to N column I am storing values and i will compare each of those with second column and store the result in third column for each of row's values.Sometimes it searches the perfectly sometimes it skips the values and gives out error.Is there any better way to search in multidimensional array in tcl ? What is the problem with this code?
for {set index 1} {$index < $count} {incr index} {
for {set val 3} {$val < $d1 } {incr val} {
if {$flag1 != 1} {
if {$asarr($index,2)== $asarr($index,$val)} {
set asarr($index,1) 50
} else {
set asarr($index,1) 100
set flag1 1
break
}
}
}
set flag1 0
}
There is a discrepancy between your code and the problem explanation in your question.
From your question I summarise these requirements:
data is stored in 2 dimensional array
each row stores one set of data
within each row, data is stored in columns where:
1st column is not mention in the original question
2nd column contains a value against which all 'data columns' will be compared
3rd column is where the result of the comparison will be stored (looking at the code, result is either a 50 or a 100)
4th to Nth column hold the data that needs to be compared against value of 2nd column
And this is what your code actually does:
# start iterating array by rows
# first row has index 1
for {set index 1} {$index < $count} {incr index} {
# start iterating over columns
# NOTE: either column indexes are assumed to start at 0
# or we, in fact, start with the 3rd column instead of 4th
for {set val 3} {$val < $d1 } {incr val} {
# check the special flag named 'flag1'
# NOTE: it would be better to give it a meaningful name
# such as 'found' since it signals that we found
# an element equal to the one in 2nd column
if {$flag1 != 1} {
if {$asarr($index,2)== $asarr($index,$val)} {
# if the element at current position ($index,$val)
# is equal to the element at ($index,2)
# write '50' at ($index,1)
# NOTE: result is stored in 1st column,
# not in 3rd as the question would assume
set asarr($index,1) 50
} else {
# if the current element is not equal to the one
# in 2nd column, write '100' at ($index, 1).
# Again, this is not the 3rd column as requested originally
set asarr($index,1) 100
# set the special flag to 1, meaning that the above
# IF clause will not be run again
set flag1 1
# execute a break, meaning that we immediately interrupt
# the inner FOR loop, meaning that the above IF clause
# will not be run again in this iteration.
# As Donal pointed out, you could completely
# remove the $flag1 and achieve the same result with
# this break clause
break
}
}
}
# reset the flag so that IF clause is executed at least once
# for the next iteration of the outer loop
set flag1 0
}
If we assume that the 'flag1' is set to 0 (or anything != 1) before the FOR loops start, then the end result is that the code iterates through array rows, compares each column (starting from 3rd!) against column number 2, it repeats this for all other columns BUT ONLY if their values are equal to column 2 and EACH TIME OVERWRITES THE SAME value '50' over column 1. As soon as a different value is encountered, the result '100' is written to column 1 and the rest of the values are immediately skipped. Execution then starts from the beginning but with the next row.
How does that compare against your original intentions?
The code could (and should) be greatly simplified at least so it doesn't overwrite the same value many times, however, I am not exactly sure what you are trying to achieve. Please try to clarify your requirements.
I don't know if this will be useful (you said that the code does not behave as you would like it to), but here is an alternative version that behaves according to the requirements I guessed from your question (and listed above):
for {set index 1} {$index < $count} {incr index} {
set asarr($index,3) 50
for {set val 4} {$val < $d1 } {incr val} {
if {$asarr($index,2)!= $asarr($index,$val)} {
set asarr($index,3) 100
break
}
}
}

writing proc avg in tcl script in NS2

I want to calculate avg of { energy_level ,number of nodes & traffic's data on nodes } by one mobile sink in the network with 5 static nodes.
I have to calculate this avg with proc in tcl script code not with awk code.
Please help me
If you have collected a list of values that you want to compute the average of, use this procedure to do the computation:
proc ArithmeticMean {listOfValues} {
set length [llength $listOfValues]
if {$length == 0} {
return 0.0
}
set sum [::tcl::mathop::+ {*}$listOfValues]
return [expr {double($sum) / $length}]
}
The summing of the values uses the + “operator command” with expansion syntax, and is the cheapest way of adding them all together.

Converting this algorithm in TCL

I need help in converting this algorithm into tcl for my work, I am not so good in tcl language.
Inputs: STA−1, STA−2, STA−3, ..., STA−n
//requests from various stations for channel access
Shared Variables:
for every i, 1 ≤ i ≤ n
counter[i] ∈ { / 0, 1, 2,..., N}, initially 0, updated by stations
Sequence Number, K ∈ { / 0, 1, 2,..., N}, initially 0, will be set to a positive integer
Procedure:
//Initialization
Set sequence number K = m; //based on the action selected
for (i = 1 to n)
counter[i] = 0;
for (i = 1 to n)
{
while (channel access[i])
if (counter[i]! = K)
{
if (channel == idle)
{
if (counter[i]<min(counter[i+1], counter[i+2], ..., counter[i + n]))
access channel;
else
defer access;
}
counter[i]+ +;
}
else
defer access;
}
This is for CPS devices to access internet using a WSN in between..basic network is done but need help with adding this algo to it..
Can someone help me code that algo in tcl?
Your question isn't clear enough.
For syntax, I'd recommend referring TCL online help.
Some quick snippets:
# Inputs: STA−1, STA−2, STA−3, ..., STA−n
set stations [list "STA−1" "STA−2" "STA−3"]
# Shared Variables:
# for every i, 1 ≤ i ≤ n
# counter[i] ∈ { / 0, 1, 2,..., N}, initially 0, updated by stations
array set counter {}
set n 10
set i 0
while {$i < $n} {
set counter($i) 0
incr i
}
The core of your method is converted to this, assuming that counter is converted to an (associative) array, and that channel identifiers are stored in the channel array:
variable K 0
for {set i 1} {$i <= $n} {incr i} {
set counter($i) 0
}
for {set i 1} {$i <= $n} {incr i} {
while {[channelAccess $channel($i)]} {
if {$counter($i) != $K} {
if {[channelIdle $channel($i)]} {
set minimum [getMinimum [expr {$i + 1}] [expr {$i + $n}]]
if {$counter($i) < $minimum} {
accessChannel $channel($i)
} else {
deferAccess $channel($i)
}
}
incr counter($i)
} else {
deferAccess $channel($i)
}
}
}
You'll also need this procedure:
proc getMinimum {from to} {
upvar 1 counter counter
set minVal $counter($from)
for {set i $from} {$i <= $to} {incr i} {
set minVal [expr {min($minVal, $counter($i))}]
}
return $minVal
}
And you'll need to define channelAccess, channelIdle, accessChannel and deferAccess; they're things that your algorithm doesn't specify. There's also nothing to say what various variable are actually updated by. But that's the algorithm converted.
Note the patterns for using for; those are idiomatic Tcl for this sort of thing. Also note the brace positioning; your life will be easiest in Tcl if you use that style.