For your graphing enjoyment...an L or C Impedance Graph with selectable frequency sweep and scaling.
Original version used the Gnome viewer to display the graph. This "final" version uses a PaintDC and is thus platform independant. Many thanks to Mark Dootson for the PaintDC code.
#! /home/pete/CitrusPerl/perl/bin/perl
# ImpedanceGraph2.pl
# Impedance calculator for Ls & Cs with graphic display
#
# Example of using GD::Graph with wxPerl to draw a simple line graph.
#
# Calculates and graphs the L or C impedance for a range of frequencie
+s.
# Graph and save_chart borrowed from GD::Graph sample51.pl
#
# Notes: Original version used the Linux Gnome File Viewer - eog - to
+display the graph file.
#
# This version uses a Display Dialog and Display Panel to display
+the
# png graph image using a PaintDC. This version is platform Indepe
+ndant.
#
# James M. Lynes, Jr.
# Last Modified: June 29, 2013
#
# DisplayDialog and DisplayPanel code provided by Mark Dootson, integr
+ated June 29, 2013.
#
package main;
use strict;
use warnings;
my $app = App->new();
$app->MainLoop;
package App;
use strict;
use warnings;
use base 'Wx::App';
sub OnInit {
Wx::InitAllImageHandlers();
my $frame = Frame->new();
$frame->Show(1);
}
package DisplayPanel;
use strict;
use warnings;
use Wx qw(:everything);
use base qw(Wx::Panel);
use Wx::Event qw( EVT_PAINT );
sub new {
my ($class, $parent, $bitmap) = @_;
my $self = $class->SUPER::new($parent, -1, wxDefaultPosition,
[ $bitmap->GetWidth, $bitmap->GetHeight
+], wxBORDER_NONE);
$self->{bitmap} = $bitmap;
EVT_PAINT($self, \&OnEvtPaint);
return $self;
}
sub OnEvtPaint {
my ($self, $event) = @_;
my $dc = Wx::PaintDC->new($self);
$dc->DrawBitmap($self->{bitmap}, 0,0,0);
}
package DisplayDialog;
use strict;
use warnings;
use Wx qw(:everything);
use base qw(Wx::Dialog);
sub new {
my($class, $parent, $image) = @_;
my $self = $class->SUPER::new($parent, -1, 'Impedance vs. Frequenc
+y Graph');
my $bitmap = Wx::Bitmap->new($image);
my $canvas = DisplayPanel->new($self, $bitmap);
my $sizer = Wx::BoxSizer->new(wxVERTICAL);
$sizer->Add($canvas,1,wxEXPAND|wxALL,0);
$self->SetSizerAndFit($sizer);
return $self;
}
package Frame;
use strict;
use warnings;
use Wx qw(:everything);
use base qw(Wx::Frame);
use Wx::Event qw(EVT_BUTTON EVT_CHOICE);
use GD::Graph::lines;
use Data::Dumper;
sub new {
my($self) = @_;
$self = $self->SUPER::new(undef, -1, "L or C Impedance Graph",
wxDefaultPosition, [375, 550]);
my @Inductors = ("nH", "uH", "mH");
my @Capacitors = ("pF", "nF", "uF");
my @Frequency = ("Hz", "KHz", "MHz");
$self->{lmultiplyer} = 1E-09; # nH Default Scale Factors
$self->{cmultiplyer} = 1E-12; # pF
$self->{flmultiplyer} = 1E06; # MHz
$self->{fhmultiplyer} = 1E06; # MHz
$self->{swmultiplyer} = 1E06; # Mhz
$self->{xamultiplyer} = 1E06; # Mhz
$self->{st1} = Wx::StaticText->new($self, -1, "Inductor Value", Wx
+::Point->new(25,50),
wxDefaultSize, wxALIGN_LEFT);
$self->{st2} = Wx::StaticText->new($self, -1, "Capacitor Value", W
+x::Point->new(25,100),
wxDefaultSize, wxALIGN_LEFT);
$self->{st3} = Wx::StaticText->new($self, -1, "Sweep Start", Wx::P
+oint->new(25,150),
wxDefaultSize, wxALIGN_LEFT);
$self->{st4} = Wx::StaticText->new($self, -1, "Sweep End", Wx::Poi
+nt->new(25,200),
wxDefaultSize, wxALIGN_LEFT);
$self->{st5} = Wx::StaticText->new($self, -1, "Sweep Step", Wx::Po
+int->new(25,250),
wxDefaultSize, wxALIGN_LEFT);
$self->{st6} = Wx::StaticText->new($self, -1, "Enter an L or C and
+ a Sweep Range to be Graphed",
Wx::Point->new(25,15), wxDefaul
+tSize, wxALIGN_LEFT);
$self->{st7} = Wx::StaticText->new($self, -1, "Y-Axis Max", Wx::Po
+int->new(25,450),
wxDefaultSize, wxALIGN_LEFT);
$self->{st8} = Wx::StaticText->new($self, -1, "Y-Axis Ticks", Wx::
+Point->new(25,475),
wxDefaultSize, wxALIGN_LEFT);
$self->{st8} = Wx::StaticText->new($self, -1, "X-Axis Scale", Wx::
+Point->new(25,500),
wxDefaultSize, wxALIGN_LEFT);
$self->{tc1} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,50), Wx::Size->new(100,20));
$self->{tc2} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,100), Wx::Size->new(100,20));
$self->{tc3} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,150), Wx::Size->new(100,20));
$self->{tc4} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,200), Wx::Size->new(100,20));
$self->{tc5} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,250), Wx::Size->new(100,20));
$self->{tc6} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,450), Wx::Size->new(100,20));
$self->{tc7} = Wx::TextCtrl->new($self, -1, "", Wx::Point->new(150
+,475), Wx::Size->new(100,20));
$self->{tc1}->SetValue(0); # L = 0 Default Data Values
$self->{tc2}->SetValue(0); # C = 0
$self->{tc3}->SetValue(1); # 1 MHz
$self->{tc4}->SetValue(30); # 30 MHz
$self->{tc5}->SetValue(1); # 1 MHz
$self->{tc6}->SetValue(10000); # 10K ohms
$self->{tc7}->SetValue(20); # 20 ticks
$self->{lc} = Wx::Choice->new($self, 1, Wx::Point->new(250, 50), w
+xDefaultSize, \@Inductors);
$self->{cc} = Wx::Choice->new($self, 2, Wx::Point->new(250, 100),
+wxDefaultSize, \@Capacitors);
$self->{flc} = Wx::Choice->new($self, 3, Wx::Point->new(250, 150),
+ wxDefaultSize, \@Frequency);
$self->{fhc} = Wx::Choice->new($self, 4, Wx::Point->new(250, 200),
+ wxDefaultSize, \@Frequency);
$self->{swc} = Wx::Choice->new($self, 5, Wx::Point->new(250, 250),
+ wxDefaultSize, \@Frequency);
$self->{xscale} = Wx::Choice->new($self, 6, Wx::Point->new(150, 50
+0), wxDefaultSize, \@Frequency);
$self->{flc}->SetSelection(2); # MHz Defaut Choices
$self->{fhc}->SetSelection(2); # MHz
$self->{swc}->SetSelection(2); # MHz
$self->{xscale}->SetSelection(2); # MHz
$self->{bt1} = Wx::Button->new($self, 4, "Graph Cs", Wx::Point->ne
+w(25,350), wxDefaultSize);
$self->{bt1} = Wx::Button->new($self, 5, "Graph Ls", Wx::Point->ne
+w(150,350), wxDefaultSize);
$self->{bt1} = Wx::Button->new($self, 6, "Clear C and L", Wx::Poin
+t->new(25,300), wxDefaultSize);
$self->{bt2} = Wx::Button->new($self, wxID_CLOSE, "Exit", Wx::Poin
+t->new(25,400), wxDefaultSize);
EVT_BUTTON($self, 4, \&CalcC);
EVT_BUTTON($self, 5, \&CalcL);
EVT_BUTTON($self, 6, \&ClearAll);
EVT_BUTTON($self, wxID_CLOSE, \&Close);
EVT_CHOICE($self, 1, \&ChoiceL);
EVT_CHOICE($self, 2, \&ChoiceC);
EVT_CHOICE($self, 3, \&ChoiceFL);
EVT_CHOICE($self, 4, \&ChoiceFH);
EVT_CHOICE($self, 5, \&ChoiceSW);
EVT_CHOICE($self, 6, \&ChoiceXA);
return $self;
}
sub CalcC {
my($self, $event) = @_;
my @xvalues;
my @yvalues;
my $C = $self->{tc2}->GetValue * $self->{cmultiplyer};
if($C == 0) {return};
my $fl = $self->{tc3}->GetValue * $self->{flmultiplyer};
my $fh = $self->{tc4}->GetValue * $self->{fhmultiplyer};
my $sw = $self->{tc5}->GetValue * $self->{swmultiplyer};
for(my $F = $fl; $F <= $fh; $F += $sw) {
my $I = 1/(6.28 * $C * $F);
push(@xvalues, $F/$self->{xamultiplyer});
push(@yvalues, $I);
}
Graph($self, \@xvalues, \@yvalues);
}
sub CalcL {
my($self, $event) = @_;
my @xvalues;
my @yvalues;
my $L = $self->{tc1}->GetValue * $self->{lmultiplyer};
if($L == 0) {return};
my $fl = $self->{tc3}->GetValue * $self->{flmultiplyer};
my $fh = $self->{tc4}->GetValue * $self->{fhmultiplyer};
my $sw = $self->{tc5}->GetValue * $self->{swmultiplyer};
for(my $F = $fl; $F <= $fh; $F += $sw) {
my $I = 6.28 * $L * $F;
push(@xvalues, $F/$self->{xamultiplyer});
push(@yvalues, $I);
}
Graph($self, \@xvalues, \@yvalues);
}
sub ChoiceL {
my($self, $event) = @_;
if($self->{lc}->GetSelection == 0) {$self->{lmultiplyer} = 1E-09};
+ # nH
if($self->{lc}->GetSelection == 1) {$self->{lmultiplyer} = 1E-06};
+ # uH
if($self->{lc}->GetSelection == 2) {$self->{lmultiplyer} = 1E-03};
+ # mH
}
sub ChoiceC {
my($self, $event) = @_;
if($self->{cc}->GetSelection == 0) {$self->{cmultiplyer} = 1E-12};
+ # pF
if($self->{cc}->GetSelection == 1) {$self->{cmultiplyer} = 1E-09};
+ # nF
if($self->{cc}->GetSelection == 2) {$self->{cmultiplyer} = 1E-06};
+ # uF
}
sub ChoiceFL {
my($self, $event) = @_;
if($self->{flc}->GetSelection == 0) {$self->{flmultiplyer} = 1};
+ # Hz
if($self->{flc}->GetSelection == 1) {$self->{flmultiplyer} = 1E03}
+; # KHz
if($self->{flc}->GetSelection == 2) {$self->{flmultiplyer} = 1E06}
+; # MHz
}
sub ChoiceFH {
my($self, $event) = @_;
if($self->{fhc}->GetSelection == 0) {$self->{fhmultiplyer} = 1};
+ # Hz
if($self->{fhc}->GetSelection == 1) {$self->{fhmultiplyer} = 1E03}
+; # KHz
if($self->{fhc}->GetSelection == 2) {$self->{fhmultiplyer} = 1E06}
+; # MHz
}
sub ChoiceSW {
my($self, $event) = @_;
if($self->{swc}->GetSelection == 0) {$self->{swmultiplyer} = 1};
+ # Hz
if($self->{swc}->GetSelection == 1) {$self->{swmultiplyer} = 1E03}
+; # KHz
if($self->{swc}->GetSelection == 2) {$self->{swmultiplyer} = 1E06}
+; # MHz
}
sub ChoiceXA {
my($self, $event) = @_;
if($self->{xscale}->GetSelection == 0) {$self->{xamultiplyer} = 1}
+; # Hz
if($self->{xscale}->GetSelection == 1) {$self->{xamultiplyer} = 1E
+03}; # KHz
if($self->{xscale}->GetSelection == 2) {$self->{xamultiplyer} = 1E
+06}; # MHz
}
sub ClearAll {
my($self, $event) = @_;
$self->{tc1}->SetValue(0); # L = 0
$self->{tc2}->SetValue(0); # C = 0
}
sub Close {
my($self, $event) = @_;
$self->Destroy;
}
sub Graph { # GD::Graph::lines Line Graph Module
my($self, $xvalues, $yvalues) = @_; # From GDGraph-1.45.tar
+.gz sample51.pl
my @data = ( # Other graph formats are supported.
+See the pod.
[(@{$xvalues}) ],
[(@{$yvalues})],
);
my $xlskip = (int(@{$xvalues}) / 30) + 1; # Only about 30 label
+s will fit on the x axis. Gotta skip some.
# Labels still overwrite on occasions. Play wi
+th the scaling.
my $my_graph = new GD::Graph::lines(600,400);
my $xscale = $self->{xscale}->GetStringSelection; # Hz, KHz, MH
+z
$my_graph->set(
x_label => "Frequency($xscale)",
y_label => 'Impedance(Ohms)',
title => 'Impedance vs. Frequency',
y_max_value => $self->{tc6}->GetValue,
y_min_value => 0,
y_tick_number => $self->{tc7}->GetValue,
y_label_skip => 2,
box_axis => 0,
line_width => 3,
transparent => 0,
x_label_position => 1/2,
x_label_skip => $xlskip,
);
my $gd = $my_graph->plot(\@data);
#save_chart($my_graph, 'impedance'); # From sample51.pl not
+ used in this configuration
#system('eog /home/pete/Projects/perlprojects/RFdesign/impedance.g
+if');
# Get the raw PNG data
my $png = $gd->png;
# Get a file handle and load it as a wxImage
open my $fh, '<', \$png;
my $img = Wx::Image->new($fh, &Wx::wxBITMAP_TYPE_PNG);
close $fh;
my $dialog = DisplayDialog->new($self, $img);
$dialog->Centre;
$dialog->ShowModal();
$dialog->Destroy;
}
sub save_chart # Separate sub because the sampl
+e51.pl was setup this way.
{ # Not used in this configuration
my $chart = shift or die "Need a chart!";
my $name = shift or die "Need a name!";
local(*OUT);
my $ext = $chart->export_format;
open(OUT, ">$name.$ext") or
die "Cannot open $name.$ext for write: $!";
binmode OUT;
print OUT $chart->gd->$ext();
close OUT;
}
1;