#=============================================== # TkTFT #=============================================== package TkTFT; use clib::TkFittingCommon; @ISA = qw(TkFittingCommon); #公開したいサブルーチン #@EXPORT = qw(DelSpace Reduce01 MakePath RegExpQuote); use strict; use Tk::JPEG; use Utils; use CSV; use MyTk::GraphFrameArray; use GraphData; use Sci qw($pi $kB $c $e $e0 $me $mp $mn $h $hbar); use Sci::Material; use Sci::TFT; my $material = new Material; #============================================================ # 変数等取得関数 #============================================================ #============================================================ # コンストラクタ、デストラクタ #============================================================ #呼び出されることはない sub new { my ($module, $app) = @_; # my ($module, $app, $canvas) = @_; my $this = {}; bless $this; $this->SetApplication($app); # $this->SetCanvas($canvas); return $this; } sub DESTROY { my $this = shift; $this->SUPER::DESTROY(@_); } #============================================================ # 継承クラスで定義しなおす関数 #============================================================ sub CreateLeftFrame { my ($this, $ConfigSide, @args) = @_; # return $this->SUPER::CreateLeftFrame(); return undef; } sub CreateSelectFilePane { my ($this) = @_; # return $this->SUPER::CreateSelectFilePane(); return undef; } sub CreateFileContentPane { return undef; } sub CreateWidgets { my ($this, $DoSuperOnly) = @_; $DoSuperOnly = 0 if(!defined $DoSuperOnly); my $App = $this->App(); my $args = $App->Args(); my $mw = $this->mw(); $this->{ini} = new TFT(); $this->{dini} = new TFT(); $this->InitializeParameters($this->{ini}, $this->{dini}); $this->SUPER::CreateWidgets(); return if($DoSuperOnly); $mw->SetTitle("TFT2007 / TkPlot"); $this->App()->SetProgram("TFT2007 / TkPlot"); #=================================================== # TFTペインを作製 #=================================================== my $EntryWidth = 12; my $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'Param', 'Param:', $this->{ini}->pVariable("ParameterFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseParameterFile"); $this->{SaveParamButton} = $Frame->MyButton( -text => '&Save', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'SaveParam'); }, )->pack(-side => 'left'); $this->{EditParamButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'EditParam'); }, )->pack(-side => 'left'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'VdsIds', 'Vds-Ids:', $this->{ini}->pVariable('VdsIdsFile', ''), '&Choose', sub { $this->ChooseFile("VdsIds", @_); } ); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'VgsIds', 'Vgs-Ids:', $this->{ini}->pVariable('VgsIdsFile', ''), '&Choose', sub { $this->ChooseFile("VdsIds", @_); } ); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); my $lsb1 = $this->{ChooseVdsIdsPlotTypeListBox} = $Frame->MyBrowseEntry( -label => "VdsIds plot:", -state => "readonly", -takefocus => 1, -Selections => ["Vds-Ids", "Vds-log(|Ids|)"], -SelIndex => 0, # -browsecmd => [\&SelChangeListBox, "VdsIds", $this], )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); my $lsb2 = $this->{ChooseVdsIdsPlotTypeListBox} = $Frame->MyBrowseEntry( -label => "Data:", -state => "readonly", -takefocus => 1, -Selections => ["all"], -SelIndex => 0, # -browsecmd => [\&SelChangeListBox, "VdsIds", $this], )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "Vds0", "Vds:", $this->{ini}->pVariable('OutputVds0', 0.0), "%g", $EntryWidth, "", 0, 0); $this->MakeLabelEntry($Frame, "Vds1", "-", $this->{ini}->pVariable('OutputVds1', 10.0), "%g", $EntryWidth, "", 0, 1); $this->MakeLabelEntry($Frame, "VdsStep", ",", $this->{ini}->pVariable('OutputVdsStep', 0.5), "%g", $EntryWidth, "V", 0, 2); $this->MakeLabelEntry($Frame, "Vgs0", "Vgs:", $this->{ini}->pVariable('OutputVgs0', 0.0), "%g", $EntryWidth, "", 1, 0); $this->MakeLabelEntry($Frame, "Vgs1", "-", $this->{ini}->pVariable('OutputVgs1', 10.0), "%g", $EntryWidth, "", 1, 1); $this->MakeLabelEntry($Frame, "VgsStep", ",", $this->{ini}->pVariable('OutputVgsStep', 1.0), "%g", $EntryWidth, "V", 1, 2); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); my $lsb3 = $this->{ChooseVgsIdsPlotTypeListBox} = $Frame->MyBrowseEntry( -label => "VgsIds plot:", -state => "readonly", -takefocus => 1, -Selections => ["Vgs-Ids", "Vgs-log(|Ids|)"], -SelIndex => 0, # -browsecmd => [\&SelChangeListBox, "VgsIds", $this], )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); my $lsb4 = $this->{ChooseVgsIdsPlotTypeListBox} = $Frame->MyBrowseEntry( -label => "Data:", -state => "readonly", -takefocus => 1, -Selections => ["all"], -SelIndex => 0, # -browsecmd => [\&SelChangeListBox, "VgsIds", $this], )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "TransferVds0", "Vds:", $this->{ini}->pVariable('TransferVds0', 0.0), "%g", $EntryWidth, "", 0, 0); $this->MakeLabelEntry($Frame, "TransferVds1", "-", $this->{ini}->pVariable('TransferVds1', 10.0), "%g", $EntryWidth, "", 0, 1); $this->MakeLabelEntry($Frame, "TransferVdsStep", ",", $this->{ini}->pVariable('TransferVdsStep', 1.0), "%g", $EntryWidth, "V", 0, 2); $this->MakeLabelEntry($Frame, "TransferVgs0", "Vgs:", $this->{ini}->pVariable('TransferVgs0', 0.0), "%g", $EntryWidth, "", 1, 0); $this->MakeLabelEntry($Frame, "TransferVgs1", "-", $this->{ini}->pVariable('TransferVgs1', 10.0), "%g", $EntryWidth, "", 1, 1); $this->MakeLabelEntry($Frame, "TransferVgsStep", ",", $this->{ini}->pVariable('TransferVgsStep', 0.5), "%g", $EntryWidth, "V", 1, 2); $Frame = $mw->MyFrame()->pack(-anchor => 'nw'); $this->{ChooseModelListBox} = $Frame->MyBrowseEntry( -label => "Model:", -state => "readonly", -takefocus => 1, -width => 20, -Selections => ["Exact", "Small Vds"], -SelIndex => 0, )->grid(-row => 0, -column => 3, -columnspan => 1, -sticky => 'e' ); $this->{ChooseModelListBox}->configure( -browsecmd => sub { $this->SelChangeListBox("Model", $this->{ChooseModelListBox}); } ); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "T", "T:", $this->{ini}->pVariable('T', 300.0), "%g", $EntryWidth, "", 0, 0); $this->MakeLabelEntry($Frame, "W", "W:", $this->{ini}->pVariable('W', 250.0), "%g", $EntryWidth, "", 1, 0); $this->MakeLabelEntry($Frame, "L", "L:", $this->{ini}->pVariable('L', 50.0), "%g", $EntryWidth, "", 1, 1); $this->MakeCheckEntry($Frame, "Dit", "Dit:", $this->{dini}->pVariable('Ditcheck', 0), $this->{ini}->pVariable('Dit', 1.0e12), "%g", $EntryWidth, "cm-2eV-1", 2, 0); $this->MakeLabelEntry($Frame, "S", "S:", $this->{ini}->pVariable('S', 0.0), "%g", $EntryWidth, "V/dec", 2, 1, "disabled"); $this->MakeCheckEntry($Frame, "Vth", "Vth:", $this->{dini}->pVariable('Vthcheck', 0), $this->{ini}->pVariable('Vth', 0.0), "%g", $EntryWidth, "V", 3, 0); # $this->MakeLabelEntry($Frame, "Neg", "Neg(gate):", # $this->{ini}->pVariable('Neg', 0.0), "%g", $EntryWidth, "cm-1", 3, 1, 'disabled'); $this->MakeLabelEntry($Frame, "VB", "VB:", $this->{ini}->pVariable('VB', 0.0), "%g", $EntryWidth, "V", 4, 0, 'disabled'); $this->MakeLabelEntry($Frame, "VFB", "VFB:", $this->{ini}->pVariable('VFB', 0.0), "%g", $EntryWidth, "V", 4, 1, 'disabled'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{RecalcButton} = $Frame->MyButton( -text => 'Re&calc', -takefocus => 1, -command => sub { $this->ButtonPressed('RButtonDown', 'Recalc'); }, )->pack(-side => 'left'); $Frame = $mw->MyLabFrame( -label => 'metal', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "EFm", "EF:", $this->{ini}->pVariable('EFm', 4.0), "%g", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "Nem", "Nem:", $this->{ini}->pVariable('Nem', 5.0e22), "%g", $EntryWidth, "cm-3", 0, 1); $this->MakeLabelEntry($Frame, "mem", "mem:", $this->{ini}->pVariable('mem', 1.0), "%g", $EntryWidth, "me", 2, 0); $this->MakeLabelEntry($Frame, "Am", "A*:", $this->{ini}->pVariable('Am', 1.0), "%g", $EntryWidth, "cm-3", 2, 1, "disabled"); $Frame = $mw->MyLabFrame( -label => 'insulator', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "EFi", "EF:", $this->{ini}->pVariable('EFi', 3.0), "%g", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "ECi", "EC:", $this->{ini}->pVariable('ECi', 1.0), "%g", $EntryWidth, "eV", 1, 0); $this->MakeLabelEntry($Frame, "EVi", "EV:", $this->{ini}->pVariable('EVi', 7.0), "%g", $EntryWidth, "eV", 1, 1); $this->MakeLabelEntry($Frame, "Epsi", "er:", $this->{ini}->pVariable('Epsi', 4.0), "%g", $EntryWidth, "e0", 2, 0); $this->MakeLabelEntry($Frame, "dgate", "d(gate):", $this->{ini}->pVariable('dgate', 100.0), "%g", $EntryWidth, "nm", 3, 0); $this->MakeLabelEntry($Frame, "Cox", "Cox:", $this->{ini}->pVariable('Cox', 0.0), "%g", $EntryWidth, "F/cm2", 3, 1, "disabled"); $Frame = $mw->MyLabFrame( -label => 'semiconductor', -labelside => 'acrosstop', )->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "ECs", "EC:", $this->{ini}->pVariable('ECs', 3.0), "%g", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "EVs", "EV:", $this->{ini}->pVariable('EVs', 4.0), "%g", $EntryWidth, "eV", 0, 1); $this->MakeLabelEntry($Frame, "Egs", "Eg:", $this->{ini}->pVariable('Egs', 0.0), "%g", $EntryWidth, "eV", 1, 0, "disabled"); $this->MakeLabelEntry($Frame, "mes", "me:", $this->{ini}->pVariable('mes', 0.35), "%g", $EntryWidth, "me", 2, 0); $this->MakeLabelEntry($Frame, "mhs", "mh:", $this->{ini}->pVariable('mhs', 1.5), "%g", $EntryWidth, "me", 2, 1); $this->MakeLabelEntry($Frame, "NCs", "NC:", $this->{ini}->pVariable('NCs', 8.5e18), "%g", $EntryWidth, "cm-3", 3, 0, "disabled"); $this->MakeLabelEntry($Frame, "NVs", "NV:", $this->{ini}->pVariable('NVs', 8.5e20), "%g", $EntryWidth, "cm-3", 3, 1, "disabled"); $this->MakeLabelEntry($Frame, "EFs", "EF:", $this->{ini}->pVariable('EFs', 3.3), "%g", $EntryWidth, "eV", 4, 0); $this->MakeLabelEntry($Frame, "Eis", "Ei:", $this->{ini}->pVariable('Eis', 0.0), "%g", $EntryWidth, "eV", 4, 1, "disabled"); $this->MakeLabelEntry($Frame, "Nes", "Ne:", $this->{ini}->pVariable('Nes', 1.0e15), "%g", $EntryWidth, "cm-3", 5, 0, "disabled"); $this->MakeLabelEntry($Frame, "Nhs", "Nh:", $this->{ini}->pVariable('Nhs', 1.0e15), "%g", $EntryWidth, "cm-3", 5, 1, "disabled"); $this->MakeLabelEntry($Frame, "Nis", "Ni:", $this->{ini}->pVariable('Nis', 0.0), "%g", $EntryWidth, "cm-3", 6, 0, "disabled"); $this->MakeCheckEntry($Frame, "uFE", "uFE:", $this->{dini}->pVariable('uFEcheck', 0), $this->{ini}->pVariable('uFE', 10.0), "%g", $EntryWidth, "cm2/Vs", 7, 0); $this->MakeLabelEntry($Frame, "Epss", "er:", $this->{ini}->pVariable('Epss', 11.9), "%g", $EntryWidth, "e0", 7, 1); #ツールバーのOpenボタンをファイル読み込みにバインドする $mw->{OpenButton}->configure( -command => sub { $this->ChooseVdsIdsFile($this->{VdsIdsFileEntry}); }, ) if($mw->{OpenButton}); #Replotボタンを再バインドする # $mw->{ReplotButton}->configure( # -command => [ \&Draw, $this ], # ) if($mw->{ReplotButton}); #Refleshボタンを再バインドする # $mw->{RefleshButton}->configure( # -command => sub { $this->Draw(); }, #mw()->RefleshCanvas(1); }, # ) if($mw->{RefleshButton}); #$mw->bind('all', '', [\&CheckLogin, Ev('K'), 0]); #$mw->bind($ent, '', [\&CheckLogin, 'Enter', 1]); #$mw->bind($ent, '', [\&CheckLogin, 'Leave', 1]); #$mw->bind($ent, '', [\&CheckLogin, 'Property', 1]); #$mw->bind($ent, '', [\&CheckLogin, 'FocusIn', 1]); #$mw->bind($ent, '', [\&CheckLogin, 'FocusOut', 1]); # $this->{ini} = new TFT; $this->UpdateParameters(); } sub ChooseFile { my ($this, $type, $widget, $Option) = @_; my $App = $this->App(); my $canvas = $this->Canvas(); my $mw = $this->mw(); #print "Opt=$Option\n"; my $mode = 'open'; my $fmask = '*.csv;*.spe;*.jel;*.asp;*.smo;*isa;*.ref;*.pal;*.bef;*.aft'; if($Option eq 'ChooseParameterFile') { # $mode = 'save'; $fmask = '*.prm'; } my $dir = ''; unless($widget) { $dir = $this->App()->{WorkDir}; chdir($dir); } my $defstr = ''; my $message = 'Choose file'; my $filepath = Dialog::OpenFileDialog($mw, 'open', $fmask, $defstr, $message, $dir); if($filepath) { my $DirPath = $this->SetWorkDir($filepath); if($widget) { $widget->SetText($filepath); } } else { return undef; } my $ret; if($type eq 'Param') { $ret = $this->ReadParameterFile($filepath); return undef unless($ret); $this->Draw(); } elsif($type eq 'VdsIds') { # $ret = $this->ReadParameterFile($filepath); return undef unless($ret); $this->Draw(); } elsif($type eq 'VdsIgs') { # $ret = $this->ReadSampleDataFile($filepath); return undef unless($ret); $this->Draw(); } return $ret; } sub ButtonPressed { my ($this, $event, $type) = @_; if($type eq 'Recalc') { $this->Recalc(); $this->CreateGraphFrame() if(!defined $this->{GraphFrameArray}); $this->AssignGraphData(1); $this->Draw(); } else { $this->SUPER::ButtonPressed($event, $type); } } sub UpdateParameters { my ($this) = @_; my $T = $this->{ini}->{T}; my $Epsi = $this->{ini}->{Epsi}; my $Epss = $this->{ini}->{Epss}; my $ECs = $this->{ini}->{ECs}; my $EVs = $this->{ini}->{EVs}; my $mes = $this->{ini}->{mes}; my $mhs = $this->{ini}->{mhs}; my $EFm = $this->{ini}->{EFm}; my $EFs = $this->{ini}->{EFs}; my $EFi = $this->{ini}->{EFi}; my $dgate = $this->{ini}->{dgate}*1.0e-9; my $Egs = $this->{ini}->{Egs} = -($this->{ini}->{ECs} - $this->{ini}->{EVs}); my $NCs = $this->{ini}->{NCs} = $material->Nc($mes*$me, 1.0, $T) * 1.0e-6; # cm-3 my $NVs = $this->{ini}->{NVs} = $material->Nc($mhs*$me, 1.0, $T) * 1.0e-6; # cm-3 my $Nis = $this->{ini}->{Nis} = sqrt($NCs * $NVs) * exp(-0.5 * $Egs / $kB / $T * $e); # cm-3 my $Eis = $this->{ini}->{Eis} = ($ECs+$EVs)*0.5 + 0.75*$kB*$T/$e * log($mhs/$mes); # my $Eis = $this->{ini}->{Eis} = ($ECs+$EVs)*0.5 + 0.5*$kB*$T/$e * log($NVs/$NCs); $this->{ini}->{Nes} = $NCs * exp(-($EFs-$ECs)/$kB/$T*$e); $this->{ini}->{Nhs} = $NVs * exp(-($EVs-$EFs)/$kB/$T*$e); my $VFB = $this->{ini}->{VFB} = -($EFm - $EFs); my $VB = $this->{ini}->{VB} = $Eis - $EFs; my $Cox = $this->{ini}->{Cox} = $material->CalCapacitance($Epsi, 0.01*0.01, $dgate); # F/cm2 my $S = $this->{ini}->{S} = $material->CalSubthresholdSwing($T, $Epsi, $dgate, $this->{ini}->{Dit}*1.0e4); # $this->{ini}->{Neg} = $this->{Cox} * ($this->{Vgs} - $this->{Vth}) / $e; # cm-2 my $Nes = $this->{ini}->{Nes} * 1.0e6; my $Vth = $this->{ini}->{Vth} = $VFB + 2 * $VB + sqrt(abs(2 * $Epss * $e0 * $e * $Nes * 2 * $VB)) / ($Cox * 1.0e4); my $pEA = $this->{pEntryArray}; for(my $i = 0 ; $i < @$pEA ; $i++) { $pEA->[$i]->Update(); } } sub EntryFocusedIn { my ($this, $obj, $event, $type) = @_; if($event eq 'FocusIn') { $this->{PrevValue} = $obj->GetText(); } } sub EntryFocusedOut { my ($this, $obj, $event, $type) = @_; #print "type: $type\n"; return if($this->{PrevValue} eq $obj->GetText()); if($event eq 'FocusOut') { if($type eq 'T') { } } $this->UpdateParameters(); } #=================================================== # データ処理 #=================================================== sub Initialize { my ($this, $InitializeParameterFile, $InitializeData) = @_; $this->{Optimize} = undef; if($InitializeParameterFile) { $this->{ini}->{SampleCSVFile} = ''; } if($InitializeData) { $this->{pEArray} = undef; } } sub InitializeParameters { my ($this, $ini, $dini) = @_; # $this->AddParameters($ini, $dini, "T", 300.0, 0, 100.0, 0.0, ''); # $this->AddParameters($ini, $dini, "W", 250.0, 0, 100.0, 0.0, ''); # $this->AddParameters($ini, $dini, "L", 50.0, 0, 10.0, 0.0, ''); # $this->AddParameters($ini, $dini, "dgate", 100.0, 0, 100.0, 0.0, ''); # $this->AddParameters($ini, $dini, "er", 11.9, 0, 10.0, 0.0, ''); # $this->AddParameters($ini, $dini, "Cox", 0.0, 0, 1.0, 0.0, ''); $this->AddParameters($ini, $dini, "Dit", 0.0, 0, 1.0, 0.0, ''); # $this->AddParameters($ini, $dini, "S", 0.0, 0, 1.0, 0.0, ''); $this->AddParameters($ini, $dini, "uFE", 10.0, 0, 10.0, 0.0, ''); $this->AddParameters($ini, $dini, "Vth", 0.0, 0, 1.0, 0.0, ''); # $this->AddParameters($ini, $dini, "Vds", 0.0, 0, 1.0, 0.0, ''); # $this->AddParameters($ini, $dini, "Vgs", 0.0, 0, 1.0, 0.0, ''); $this->AddParameters($ini, $dini, "Neg", 1.0e12, 0, 1.0e12, 0.0, ''); } sub Recalc { my ($this) = @_; $this->UpdateParameters(); my $Model = $this->{ChooseModelListBox}->GetText(); if($this->{"VgsIds-nData"}) { my $VgsIdsData = new GraphData; my $nData = $this->{"VgsIds-nData"}; for(my $i = 1 ; $i < $nData ; $i++) { $VgsIdsData->SetXDataArray($i-1, $this->{"VgsIds-ppDataArray"}->[0]); $VgsIdsData->SetYDataArray($i-1, $this->{"VgsIds-ppDataArray"}->[$i]); } $VgsIdsData->CalMinMax(); my ($Imin, $Imax) = $VgsIdsData->GetYMinMax(); #print "I: $Imin, $Imax\n"; my $logImin = log(abs($Imin)); my $logImax = log(abs($Imax)); my $avLogI = ($logImin + $logImax) / 2.0; my $avI = exp($avLogI); my $avV = $VgsIdsData->XVal(0, $avI); #print "av: $avV, $avI\n"; my $n = 101; my $Istep = ($logImax - $logImin) / ($n - 1); my $S = $this->{S}; my $Vth = $this->{Vth}; my @V; my @I; my $ln10 = log(10.0); for(my $i = 0 ; $i < $n ; $i++) { my $logI = $logImin + $Istep*$i; $I[$i] = exp($logI); $V[$i] = $S / $ln10 * ($logI - $avLogI) + $avV; } $this->{"SS-ppDataArray"} = [\@V, \@I]; } else { $this->{ini}->PrepareForCalculation(); my $OVds0 = $this->{ini}->{OutputVds0}; my $OVds1 = $this->{ini}->{OutputVds1}; my $OVdsStep = $this->{ini}->{OutputVdsStep}; my $nOVds = int( ($OVds1 - $OVds0) / $OVdsStep + 1.001 ); my $OVgs0 = $this->{ini}->{OutputVgs0}; my $OVgs1 = $this->{ini}->{OutputVgs1}; my $OVgsStep = $this->{ini}->{OutputVgsStep}; my $nOVgs = int( ($OVgs1 - $OVgs0) / $OVgsStep + 1.001 ); my @OVgs; my @pOVds; my @pOIds; my @Vpinch; my @Ipinch; for(my $ig = 0 ; $ig < $nOVgs ; $ig++) { my $Vgs = $OVgs0 + $OVgsStep * $ig; my $Vpinch; if($Model eq 'Exact') { $Vpinch = $this->{ini}->PinchoffVds($Vgs); } else { $Vpinch = $this->{ini}->PinchoffVdsAtSmallVds($Vgs); } $Vpinch[$ig] = $Vpinch; $Ipinch[$ig] = $this->{ini}->Ids($Vgs, $Vpinch); $OVgs[$ig] = $Vgs; $pOVds[$ig] = []; $pOIds[$ig] = []; for(my $id = 0 ; $id < $nOVds ; $id++) { my $Vds = $OVds0 + $OVdsStep * $id; $pOVds[$ig][$id] = $Vds; my $Ids; if($Model eq 'Exact') { if($Vds > $Vpinch) { $Ids = $this->{ini}->Ids($Vgs, $Vpinch); } else { $Ids = $this->{ini}->Ids($Vgs, $Vds); } } else { if($Vds > $Vpinch) { $Ids = $this->{ini}->IdsAtSmallVds($Vgs, $Vpinch); } else { $Ids = $this->{ini}->IdsAtSmallVds($Vgs, $Vds); } } $pOIds[$ig][$id] = $Ids; printf "Vds=%4.2f Vgs=%4.2f Ids=%9.3g A Vpinch=%4.2f\n", $Vds, $Vgs, $Ids, $Vpinch; } } $this->{pOVgs} = \@OVgs; $this->{ppOVds} = \@pOVds; $this->{ppOIds} = \@pOIds; $this->{pVpinch} = \@Vpinch; $this->{pIpinch} = \@Ipinch; print "\n"; my $TVds0 = $this->{ini}->{TransferVds0}; my $TVds1 = $this->{ini}->{TransferVds1}; my $TVdsStep = $this->{ini}->{TransferVdsStep}; my $nTVds = int( ($TVds1 - $TVds0) / $TVdsStep + 1.001 ); my $TVgs0 = $this->{ini}->{TransferVgs0}; my $TVgs1 = $this->{ini}->{TransferVgs1}; my $TVgsStep = $this->{ini}->{TransferVgsStep}; my $nTVgs = int( ($TVgs1 - $TVgs0) / $TVgsStep + 1.001 ); my @TVds; my @pTVgs; my @pTIds; for(my $id = 0 ; $id < $nTVds ; $id++) { my $Vds = $TVds0 + $TVdsStep * $id; $TVds[$id] = $Vds; $pTVgs[$id] = []; $pTIds[$id] = []; for(my $ig = 0 ; $ig < $nTVgs ; $ig++) { my $Vgs = $TVgs0 + $TVgsStep * $ig; $pTVgs[$id][$ig] = $Vgs; my $Vpinch; if($Model eq 'Exact') { $Vpinch = $this->{ini}->PinchoffVds($Vgs); } else { $Vpinch = $this->{ini}->PinchoffVdsAtSmallVds($Vgs); } my $Ids; if($Model eq 'Exact') { if($Vds > $Vpinch) { $Ids = $this->{ini}->Ids($Vgs, $Vpinch); } else { $Ids = $this->{ini}->Ids($Vgs, $Vds); } } else { if($Vds > $Vpinch) { $Ids = $this->{ini}->IdsAtSmallVds($Vgs, $Vpinch); } else { $Ids = $this->{ini}->IdsAtSmallVds($Vgs, $Vds); } } $pTIds[$id][$ig] = $Ids; printf "Vgs=%4.2f Vds=%4.2f Ids=%9.3g A Vpinch=%4.2f\n", $Vgs, $Vds, $Ids, $Vpinch; } } $this->{pTVds} = \@TVds; $this->{ppTVgs} = \@pTVgs; $this->{ppTIds} = \@pTIds; } } sub SaveParameterFile { my ($this, $filepath) = @_; $this->{ini}->{Model} = $this->{ChooseModelListBox}->GetText() if($this->{ChooseModelListBox}); if(!defined $filepath or $filepath eq '') { $filepath = $this->ChooseSaveFile('save.prm', '*.prm'); if($filepath) { $this->{ini}->{ParameterFile} = $filepath; } else { return; } } $this->{ini}->SetIniFile($filepath, undef, 1); $this->App()->print("\nSaveParameterFile: [$filepath]\n"); $this->ComposeParameters($this->{dini}, $this->{ini}); $this->{ini}->WriteAll(); $this->DecomposeParameters($this->{ini}, $this->{dini}); } sub ReadParameterFile { my ($this, $filepath) = @_; my $DirectorySeparator = Deps::DirectorySeparator(); my $RegSeparator = Utils::RegExpQuote($DirectorySeparator); my $ini = $this->{ini}; my $dini = $this->{dini}; $this->Initialize(1, 1); $this->App()->print("\nRead paramter from [$filepath].\n"); $this->{ini}->ReadAll($filepath); # $this->{ini}->{ParameterFile} = $filepath; $this->DecomposeParameters($ini, $dini); if($this->{ini}->{SampleCSVFile}) { my $ret; if(-e $this->{ini}->{SampleCSVFile}) { $ret = $this->ReadSampleDataFile($this->{ini}->{SampleCSVFile}, 1, 0, 0); } unless($ret) { my ($drive0, $directory0, $filename0, $ext0, $lastdir0, $filebody0) = Deps::SplitFilePath($this->{ini}->{ParameterFile}); my ($drive1, $directory1, $filename1, $ext1, $lastdir1, $filebody1) = Deps::SplitFilePath($filepath); $this->{ini}->{SampleCSVFile} =~ s/\//$DirectorySeparator/g; my $RelPath = Utils::MakeRelativePath($this->{ini}->{SampleCSVFile}, "$drive0$directory0"); $RelPath =~ s/^\.$RegSeparator/$drive1$directory1/; if(-e $RelPath) { $ret = $this->ReadSampleDataFile($RelPath, 1, 0, 0); } unless($ret) { ($drive0, $directory0, $filename0, $ext0, $lastdir0, $filebody0) = Deps::SplitFilePath($filepath); ($drive1, $directory1, $filename1, $ext1, $lastdir1, $filebody1) = Deps::SplitFilePath($this->{ini}->{SampleCSVFile}); my $f = Deps::MakePath("$drive0$directory0", $filename1, 0); $ret = $this->ReadSampleDataFile($f, 1, 0, 0); return undef unless($ret); $this->{ini}->{SampleCSVFile} = $f; } else { $this->{ini}->{SampleCSVFile} = $RelPath; } } } $this->{ini}->{ParameterFile} = $filepath; $this->{ChooseModelListBox}->SetText($this->{ini}->{Model}); return 1; } sub ReadFiles { my ($this, $filepath, $type, $IsPrint) = @_; my $App = $this->App(); #print "type=$type\n"; $this->{"${type}-Path"} = $filepath; my ($nData, $pLabelArray, @pDataArray) = CSV::GetArraysFromFile($filepath); if(!defined $nData) { $App->print("Error: Can not read [$filepath] for [$type].\n"); return $this->{"${type}-Path"} = undef; } my @Vanother; $this->{"${type}-nData"} = $nData; $this->{"${type}-pLabelArray"} = $pLabelArray; $this->{"${type}-ppDataArray"} = \@pDataArray; $this->{"${type}-pVanother"} = \@Vanother; if($IsPrint) { my $pX = $this->{"${type}-ppDataArray"}->[0]; for(my $i = 0 ; $i < $nData ; $i++) { my $x = $pX->[$i]; $App->print("$i: $x, "); for(my $j = 1 ; $j < @pDataArray ; $j++) { my $pY = $this->{"${type}-ppDataArray"}->[$j]; my $y = $pY->[$i]; $App->print("$y,"); } $App->print("\n"); } } $this->{"Choose${type}PlotTypeListBox"}->DeleteAllItem(); $this->{"Choose${type}PlotTypeListBox"}->AddItem("all"); $App->print("Vanother: "); for(my $j = 1 ; $j < @pDataArray ; $j++) { my $j1 = $j-1; # ($Vanother[$j1]) = ($pLabelArray->[$j] =~ /([\+\-]?\d*(\.\d*)?([eEdD][\+\-]?\d+)?)/); ($Vanother[$j1]) = ($pLabelArray->[$j] =~ /([\+\-]?[\d\.]+([eEdD][\+\-]?\d+)?)/); if($j == 1) { $App->print("$Vanother[$j1]"); } else { $App->print(",$Vanother[$j1]"); } $this->{"Choose${type}PlotTypeListBox"}->AddItem($pLabelArray->[$j]); } $App->print("\n"); $this->CreateGraphFrame(); $this->AssignGraphData(); return $filepath; } sub CreateGraphFrame { my ($this, $canvas, $TargetData) = @_; $canvas = $this->Canvas(); my $App = $this->App(); my $font = $App->{'GraphFrameFont'}; my @font = split(/,/, $font) if($font); my $w = $canvas->width(); my $h = $canvas->height(); my $GraphFrameArray = $this->{'GraphFrameArray'} = new GraphFrameArray($this->mw()); $GraphFrameArray->SetCanvasSize($w, $h); $GraphFrameArray->AddGraphFrame(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); my $FramePosStr0 = $App->{"GraphFrame0Position"}; my $XScale0 = $GraphFrame0->GetXScale(0); my $YScale0 = $GraphFrame0->GetYScale(0); $GraphFrame0->SetPositionByStr($FramePosStr0); $GraphFrameArray->AddGraphFrame(); my $GraphFrame1 = $GraphFrameArray->GetGraphFrame(1); my $FramePosStr1 = $App->{"GraphFrame1Position"}; my $XScale1 = $GraphFrame1->GetXScale(0); my $YScale1 = $GraphFrame1->GetYScale(0); $GraphFrame1->SetPositionByStr($FramePosStr1); $GraphFrame0->SetXCaption("Vds / V"); $GraphFrame0->SetYCaption("Ids / A"); $GraphFrame1->SetXCaption("Vgs / V"); $GraphFrame1->SetYCaption('Ids / A'); $XScale0->SetScaleStringVisible(1); $XScale0->SetCaptionVisible(1); $XScale1->SetScaleStringVisible(1); $XScale1->SetCaptionVisible(1); $GraphFrame0->SetViewRange(0, 0, 1, 1); $GraphFrame1->SetViewRange(0, 0, 1, 1); } sub AssignGraphData { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); my $GraphFrameArray = $this->GetGraphFrameArray(); my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); my $GraphFrame1 = $GraphFrameArray->GetGraphFrame(1); $GraphFrame0->ClearAllData() if($GraphFrame1); $GraphFrame1->ClearAllData() if($GraphFrame1); # my $pDataArray = $this->DataArray(); # my $FileType = $this->FileType(); # my $TargetData = $pDataArray->{'TargetData'}; # return unless($pDataArray); # my $Data0 = $pDataArray->GetGraphData(0); # my $Data1 = $pDataArray->GetGraphData(1); # return unless($Data1); # my $nData = $Data0->nData(); # my $title = $Data0->Title(); if($this->{"VdsIds-nData"}) { my $PlotType = $this->{ChooseVdsIdsPlotTypeListBox}->GetText(); #print "PlotType: $PlotType\n"; my $nData = $this->{"VdsIds-nData"}; my $pLabelArray = $this->{"VdsIds-pLabelArray"}; my $ppDataArray = $this->{"VdsIds-ppDataArray"}; my $nDataAray = @$ppDataArray; my $pVgs = $this->{"VdsIds-pVanother"}; return unless($pLabelArray); my $pX = $ppDataArray->[0]; for(my $i = 1 ; $i < $nDataAray ; $i++) { next if($PlotType ne 'all' and $PlotType ne $pLabelArray->[$i]); my $i1 = $i - 1; my $pY = $ppDataArray->[$i]; my $Vgs = $pVgs->[$i1]; #print "pX=$pX, pY/$i=$pY Vgs=$Vgs\n"; my $nData0 = $GraphFrame0->AddGraphData($pX, $pY, 1, "black", "", 6, "red", 0, "red", "XAutoSkip", "Vds", "Vgs=$Vgs"); } $GraphFrame0->SetYScalePlotType('x'); if($ResetViewRange) { $GraphFrame0->CalMinMax(); $GraphFrame0->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } if($this->{"VgsIds-nData"}) { my $PlotType = $this->{ChooseVgsIdsPlotTypeListBox}->GetText(); my $nData = $this->{"VgsIds-nData"}; my $pLabelArray = $this->{"VgsIds-pLabelArray"}; my $ppDataArray = $this->{"VgsIds-ppDataArray"}; my $nDataAray = @$ppDataArray; my $pVds = $this->{"VgsIds-pVanother"}; return unless($pLabelArray); my $pX = $ppDataArray->[0]; for(my $i = 1 ; $i < $nDataAray ; $i++) { next if($PlotType ne 'all' and $PlotType ne $pLabelArray->[$i]); my $i1 = $i - 1; my $pY = $ppDataArray->[$i]; my $Vds = $pVds->[$i1]; #print "pX=$pX, pY/$i=$pY Vds=$Vds\n"; my $nData0 = $GraphFrame1->AddGraphData($pX, $pY, 1, "black", "", 6, "red", 0, "red", "XAutoSkip", "Vgs", "Vds=$Vds"); } $GraphFrame1->SetYScalePlotType('log(|x|)'); $GraphFrame1->CalMinMax(); if($ResetViewRange) { $GraphFrame1->{YMin}= 1.0e-15; $GraphFrame1->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } if($this->{"SS-ppDataArray"}) { my $pV = $this->{"SS-ppDataArray"}->[0]; my $pI = $this->{"SS-ppDataArray"}->[1]; my $nData0 = $GraphFrame1->AddGraphData($pV, $pI, 0.5, "red", "", 6, "red", 0, "red", "XAutoSkip", "Vgs", "Ids-SS(cal)"); $GraphFrame1->CalMinMax(); if($ResetViewRange) { $GraphFrame1->{YMin}= 1.0e-15; $GraphFrame1->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } if($this->{pOVgs}) { my $pOVgs = $this->{pOVgs}; my $ppOVds = $this->{ppOVds}; my $ppOIds = $this->{ppOIds}; my $n = @$ppOVds; for(my $ig = 0 ; $ig < $n ; $ig++) { my $Vgs = $pOVgs->[$ig]; #print "ig=$ig / $n: Vgs=$Vgs\n"; #print "ig=$ig: $ppOVds->[$ig], $ppOIds->[$ig]\n"; my $nData0 = $GraphFrame0->AddGraphData($ppOVds->[$ig], $ppOIds->[$ig], 0.5, "red", "", 6, "red", 0, "red", "XAutoSkip", "Ids-Vds", "Vgs=$Vgs"); } my $pVpinch = $this->{pVpinch}; my $pIpinch = $this->{pIpinch}; my $nData0 = $GraphFrame0->AddGraphData($pVpinch, $pIpinch, 0, "blue", "circle", 6, "", 1, "blue", "XAutoSkip", "Pinch-off", "Pinch-off"); $GraphFrame0->CalMinMax(); if($ResetViewRange) { $GraphFrame0->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } if($this->{pTVds}) { my $pTVds = $this->{pTVds}; my $ppTVgs = $this->{ppTVgs}; my $ppTIds = $this->{ppTIds}; my $n = @$ppTVgs; for(my $id = 0 ; $id < $n ; $id++) { my $Vds = $pTVds->[$id]; my $nData0 = $GraphFrame1->AddGraphData($ppTVgs->[$id], $ppTIds->[$id], 0.5, "red", "", 6, "red", 0, "red", "XAutoSkip", "Ids-Vgs", "Vds=$Vds"); } $GraphFrame1->CalMinMax(); if($ResetViewRange) { $GraphFrame1->SetYScalePlotType('log(|x|)'); $GraphFrame1->{YMin}= 1.0e-8; $GraphFrame1->AdjustViewRange(0.05, 0.05, 0.05, 0.05); } } } sub AdjustViewRange { my ($this) = @_; my $GraphFrameArray = $this->GetGraphFrameArray(); my $pGraphFrame = $GraphFrameArray->GetpGraphFrameArray(); my $FileType = $this->FileType(); if($FileType =~ /(Ids)/i) { } } 1;