Snippets

John Peck Plot bandwidth measurements made with the CGR-201 using gnuplot

Created by John Peck last modified John Peck
#!/opt/ActiveTcl-8.6/bin/tclsh
# Hey Emacs, use -*- Tcl -*- mode

set scriptname [file rootname $argv0]

# ----------------------- Gnuplot settings ----------------------------

# The wxt terminal can keep windows alive after the gnuplot process
# exits.  This allows calling multiple persistent windows which allow
# zooming and annotation.
set gnuplot_terminal wxt

# ---------------------- Command line parsing -------------------------
package require cmdline
set usage "usage: [file tail $argv0] \[options] filename"
set options {
}

try {
    array set params [::cmdline::getoptions argv $options $usage]
} trap {CMDLINE USAGE} {msg o} {
    # Trap the usage signal, print the message, and exit the application.
    # Note: Other errors are not caught and passed through to higher levels!
    puts $msg
    exit 1
}

proc iterint {start points} {
    # Return a list of increasing integers starting with start with
    # length points
    set count 0
    set intlist [list]
    while {$count < $points} {
	lappend intlist [expr $start + $count]
	incr count
    }
    return $intlist
}

proc dashline {width} {
    # Return a string of dashes of length width
    set dashline ""
    foreach dashchar [iterint 0 $width] {
	append dashline "-"
    }
    return $dashline
}

# After cmdline is done, argv will point to the last argument
if {[llength $argv] == 1} {
    set input_file_name $argv
} else {
    puts [cmdline::usage $options $usage]
    exit 1
}

proc iterint {start points} {
    # Return a list of increasing integers starting with start with
    # length points
    set count 0
    set intlist [list]
    while {$count < $points} {
	lappend intlist [expr $start + $count]
	incr count
    }
    return $intlist
}

proc lmean {input_list} {
    # Find the mean of a list
    set total 0
    set count 0
    foreach item $input_list {
	incr count
	set total [expr $total + $item]
    }
    set mean [expr $total/double($count)]
    return $mean
}

proc loffset {input_list offset} {
    # Move all list elements by offset
    foreach item $input_list {
	lappend no_offset_list [expr $item - $offset]
    }
    return $no_offset_list
}

proc lrms {input_list} {
    # Calculate RMS value of list
    set sum 0
    set count 0
    foreach item $input_list {
	incr count
	set sum [expr $sum + $item**2]
    }
    set rms [expr sqrt( $sum/double($count) )]
    return $rms
}

proc read_file {filename} {
    # Return a list of lines from an input file
    #
    # Arguments:
    #   filename -- relative or full path to file
    if { [catch {open $filename r} fid] } {
	    puts "Could not open file $filename"
	return
    }
    set datafile_list [split [read $fid] "\n"]
    return $datafile_list
}

proc write_gnuplot_data {filename frequency_hz_list magnitude_db_list} {
    # Write a data file that can be plotted by gnuplot
    #
    # Arguments:
    #   filename -- Name of the output data file
    #   frequency_hz_list -- List of frequencies in Hz
    #   magnitude_db_list -- List of transfer function magnitudes in dB
    global params
    if { [catch {open $filename w} fp] } {
	puts "Could not open $filename for writing"
	return
    }
    foreach frequency $frequency_hz_list magnitude $magnitude_db_list {
	puts $fp "$frequency $magnitude"
    }
    close $fp
}

proc write_gnuplot_script {filename datafile measurement_dict} {
    # Write a gnuplot script to plot data in datafile
    #
    # Arguments:
    #   filename -- Name of the gnuplot script to be written
    #   datafile -- Name of the file containing data to be plotted
    global gnuplot_terminal
    global scriptname
    global input_file_name
    if { [catch {open $filename w} fp] } {
	puts "Could not open $filename for writing"
	return
    }
    # Set the fractional amount of padding to require at the top
    # of the y-axis.  This makes more room for the plot legend.  A
    # value of 1 will give no padding, and a value of 2 will make
    # the padding twice the maximum current value plotted.
    set plot_padding 1.5
    # Annotation x postion in graph (0 --> 1) coordinates
    set anno_x 0.05
    # Annotation y position in graph (0 --> 1) coordinates
    set anno_y 0.7
    # Spacing between annotation lines in graph (0 --> 1) coordinates
    set anno_incr 0.05
    puts $fp "reset"
    puts $fp "set terminal $gnuplot_terminal size 800,600"
    puts $fp "set logscale x"
    puts $fp "set format y '%0.1s %c'"
    puts $fp "set format x '%0.0s %c'"
    puts $fp "set mxtics 10"
    puts $fp "set xlabel 'Frequency (Hz)'"
    puts $fp "set ylabel 'Magnitude (dB)'"
    puts $fp "set title 'Lafayette transimpedance bandwidth"
    # Start annotations
    foreach measurement [dict keys $measurement_dict] {
	set annotation "[dict get $measurement_dict $measurement title] = "
	append annotation [format "%0.1f" [dict get $measurement_dict $measurement value]]
	append annotation " [dict get $measurement_dict $measurement units]"
	puts $fp "set label '$annotation' at graph $anno_x,$anno_y"
	set anno_y [expr $anno_y - $anno_incr]
    }
    # Use noenhanced here to prevent underscores from becoming subscripts
    set plot_instruction "using 1:2 with lines title '$input_file_name' noenhanced"
    puts $fp "plot '$datafile' $plot_instruction"
    puts $fp {yaxis_max = GPVAL_Y_MAX}
    puts $fp {ydata_max = GPVAL_DATA_Y_MAX}
    puts $fp {yaxis_min = GPVAL_Y_MIN}
    puts $fp {ydata_min = GPVAL_DATA_Y_MIN}
    puts $fp "if (yaxis_max < ($plot_padding * ydata_max)) \{"
    puts $fp "  set yrange \[ydata_min:($plot_padding * ydata_max)\] "
    puts $fp "  replot"
    puts $fp "\}"
    puts $fp "set output '$scriptname.eps'"
    puts $fp "set terminal postscript eps color size 6in,4in"
    puts $fp "replot"
    puts $fp "set terminal wxt size 800,600"
    puts $fp "replot"
    close $fp
}

########################## Main entry point ##########################

set file_line_list [read_file $input_file_name]
if {[llength $file_line_list] == 0} {
    puts "No input data"
    exit
}

set counter -1
foreach line $file_line_list {
    incr counter
    if {$counter == 0} {
	# This is the header row
	continue
    }
    if {[llength $line] == 0} {
	# This is a blank line
	continue
    }
    set line_list [split $line ","]
    lappend frequency_hz_list [lindex $line_list 0]
    lappend magnitude_db_list [lindex $line_list 1]
}

set flatband_gain [lmean [lrange $magnitude_db_list 0 9]]
set 3db_frequency_hz 0
set in_flatband true
foreach gain $magnitude_db_list frequency $frequency_hz_list {
    set normalized_db [expr $gain - $flatband_gain]
    lappend normalized_db_list $normalized_db
    if {$normalized_db <= -3 && $in_flatband} {
	set in_flatband false
	set 3db_frequency_hz $frequency
    }
}

dict set measurement_dict bandwidth title "-3dB bandwidth"
dict set measurement_dict bandwidth value [expr $3db_frequency_hz/1e6]
dict set measurement_dict bandwidth units "MHz"

dict set measurement_dict shunt title "Shunt resistance"
dict set measurement_dict shunt value 6.2
dict set measurement_dict shunt units ohms

write_gnuplot_data gnuplot.dat $frequency_hz_list $normalized_db_list
write_gnuplot_script bandwidth.gp gnuplot.dat $measurement_dict

set gnuplot "c:/Program Files/gnuplot/bin/wgnuplot.exe"
exec $gnuplot -persist bandwidth.gp

Comments (0)

HTTPS SSH

You can clone a snippet to your computer for local editing. Learn more.