#=============================================== # TkIVFit #=============================================== package TkIVFit; use clib::TkFittingCommon; @ISA = qw(TkFittingCommon); use strict; use Tk::JPEG; use Utils; use IniFile; use CSV; use MyTk::GraphFrameArray; use GraphData; use Sci qw($pi $kB $c $e $e0 $me $mn $h $hbar $torad $todeg); use Sci::Material; use Sci::Ellipsometry; use Sci::Optimize; my $material = new Material; #============================================================ # 変数等取得関数 #============================================================ sub FileType { return shift->{FileType}; } sub SetFileType { my ($this,$t)=@_; return $this->{FileType} = $t; } sub FileName { return shift->{FileName}; } sub SetFileName { my ($this,$f)=@_; return $this->{FileName} = $f; } sub SetDataArray { my ($this, $da)=@_; return $this->{DataArray} = $da; } sub DataArray { return shift->{DataArray}; } sub GetColor { return shift->{Color}; } sub ColorMapImage { return shift->{ColorMapImage}; } sub SetColorMapImage { my ($this,$m)=@_; return shift->{ColorMapImage} = $m; } #============================================================ # コンストラクタ、デストラクタ #============================================================ 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(); my $Program = "IVFit2007"; $this->{ini} = new IniFile; $this->{dini} = new IniFile; $this->InitializeParameters($this->{ini}, $this->{dini}); $this->SUPER::CreateWidgets(); return if($DoSuperOnly); $mw->SetTitle("$Program / TkPlot"); $this->App()->SetProgram("$Program / TkPlot"); #=================================================== # ペインを作製 #=================================================== 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 => [\&ButtonPressed, $this, 'RButtonDown', 'SaveParam'], )->pack(-side => 'left'); $this->{EditParamButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'EditParam'], )->pack(-side => 'left'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeChooseFileEntry($Frame, 'CSV', 'CSV:', $this->{ini}->pVariable("DataFile", ""), '&Choose', sub { $this->ChooseFile(@_); }, "ChooseCSVFile"); $this->{EditDataButton} = $Frame->MyButton( -text => 'ed', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'EditData'], )->pack(-side => 'left'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); my $lsb1 = $this->{ChooseXListBox} = $Frame->MyBrowseEntry( -label => "X:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb1->configure(-browsecmd => [\&SelChangeListBox, $this, "X", $this->{ChooseXListBox}]); my $lsb2 = $this->{ChooseY1ListBox} = $Frame->MyBrowseEntry( -label => "Y1:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => [], -SelIndex => 1, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb2->configure(-browsecmd => [\&SelChangeListBox, $this, "Y1", $this->{ChooseY1ListBox}]); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->MakeLabelEntry($Frame, "FitXMin", "XMin:", $this->{ini}->pVariable('FitXMin', ''), "%s", $EntryWidth, "", 0, 0); $this->MakeLabelEntry($Frame, "FitXMin", "XMax:", $this->{ini}->pVariable('FitXMax', ''), "%s", $EntryWidth, "", 0, 1); $this->MakeLabelEntry($Frame, "nSkipData", "nSkip:", $this->{ini}->pVariable('nSkipData', 0), "%d", $EntryWidth, "", 0, 2); $this->MakeLabelEntry($Frame, "EPS", "EPS:", $this->{ini}->pVariable('EPS', 1.0e-5), "%12.4g", $EntryWidth, "", 1, 0); $this->MakeLabelEntry($Frame, "nMaxIter", "MaxIter:", $this->{ini}->pVariable('nMaxIter', 1000), "%d", $EntryWidth, "", 1, 1); $this->MakeLabelEntry($Frame, "nSaveSpectraInterval", "SaveIntvl:", $this->{ini}->pVariable('nSaveSpectraInterval', 10), "%d", $EntryWidth, "", 1, 2); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{ChooseLSQMethodListBox} = $Frame->MyBrowseEntry( -label => "LSQ Method:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => ['Amoeba::Simplex', 'PDL::Simplex', 'ModifiedNewton'], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); if(0) { $this->{ChooseFitToListBox} = $Frame->MyBrowseEntry( -label => "Fit To:", -state => "readonly", -takefocus => 1, -width => 10, -Selections => ['I'], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); } my $lsb3 = $this->{ChooseModelListBox} = $Frame->MyBrowseEntry( -label => "Model:", -state => "readonly", -takefocus => 1, -width => 5, -Selections => ["Polynomial", "Ohmic/SCLC", "SymForwardSchottky", "SymReverseSchottky", "SymReverseNDSchottky"], -SelIndex => 0, )->pack(-side => 'left', -expand => 'yes', -fill => 'x'); $lsb2->configure(-browsecmd => [\&SelChangeListBox, $this, "Model", $this->{ChooseModelListBox}]); $Frame = $mw->MyFrame()->pack(-anchor => 'nw'); $this->MakeLabelEntry($Frame, "T", "T:", $this->{ini}->pVariable('T', 300.0), "%g", $EntryWidth, "K", 0, 0); $this->MakeLabelEntry($Frame, "S", "S:", $this->{ini}->pVariable('S', 1.0), "%g", $EntryWidth, "cm-2", 0, 1); $Frame = $mw->MyLabFrame( -label => 'metal', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeLabelEntry($Frame, "EFm", "EF:", $this->{ini}->pVariable('EFm', 4.0), "%8.6g", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "Nem", "Ne:", $this->{ini}->pVariable('Nem', 5.0e22), "%12.6g", $EntryWidth, "cm-3", 0, 1); $this->MakeLabelEntry($Frame, "mem", "me:", $this->{ini}->pVariable('mem', 1.0), "%8.6g", $EntryWidth, "me", 2, 0); $this->MakeLabelEntry($Frame, "Am", "A*:", $this->{ini}->pVariable('Am', 1.0), "%12.6g", $EntryWidth, "A/m2/K2", 2, 1); $Frame = $mw->MyLabFrame( -label => 'semiconductor', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeLabelEntry($Frame, "ECs", "EC:", $this->{ini}->pVariable('ECs', 3.0), "%8.6g", $EntryWidth, "eV", 0, 0); $this->MakeLabelEntry($Frame, "EVs", "EV:", $this->{ini}->pVariable('EVs', 4.0), "%8.6g", $EntryWidth, "eV", 0, 1); $this->MakeLabelEntry($Frame, "mes", "me:", $this->{ini}->pVariable('mes', 0.35), "%8.6g", $EntryWidth, "me", 2, 0); $this->MakeLabelEntry($Frame, "NCs", "NC:", $this->{ini}->pVariable('NCs', 0.0), "%8.6g", $EntryWidth, "cm-3", 2, 1); $this->MakeCheckEntry($Frame, "NDs", "ND:", $this->{ini}->pVariable('NDscheck', 1), $this->{ini}->pVariable('NDs', 1.0e18), "%12.6g", $EntryWidth, "cm-3", 3, 0); $this->MakeLabelEntry($Frame, "Nes", "Ne:", $this->{ini}->pVariable('Nes', 1.0e18), "%12.6g", $EntryWidth, "cm-3", 3, 1); $this->MakeLabelEntry($Frame, "EFs", "EF:", $this->{ini}->pVariable('EFs', 0.0), "%8.6g", $EntryWidth, "eV", 4, 0); $this->MakeLabelEntry($Frame, "Epss", "er:", $this->{ini}->pVariable('Epss', 11.9), "%12.6g", $EntryWidth, "e0", 5, 0); $this->MakeLabelEntry($Frame, "mus", "u:", $this->{ini}->pVariable('mus', 10.0), "%12.6g", $EntryWidth, "cm2/Vs", 5, 1); $this->MakeLabelEntry($Frame, "ds", "d:", $this->{ini}->pVariable('ds', 1e-6), "%12.6g", $EntryWidth, "cm", 6, 0); $Frame = $mw->MyLabFrame( -label => 'junction', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "phiSBH", "phiB:", $this->{ini}->pVariable('phiSBHcheck', 1), $this->{ini}->pVariable('phiSBH', 0.0), "%8.6g", $EntryWidth, "eV", 0, 0); $this->MakeCheckEntry($Frame, "ndiode", "n:", $this->{ini}->pVariable('ndiodecheck', 0), $this->{ini}->pVariable('ndiode', 12.0), "%8.6g", $EntryWidth, "", 0, 1); $this->MakeCheckEntry($Frame, "Vd", "Vd:", $this->{ini}->pVariable('Vdcheck', 1) , $this->{ini}->pVariable('Vd', 0.0), "%8.6g", $EntryWidth, "eV", 1, 0); $this->MakeLabelEntry($Frame, "Is0", "Is0:", $this->{ini}->pVariable('Is0', 10.0), "%12.6g", $EntryWidth, "A", 1, 1); $this->MakeLabelEntry($Frame, "bs", "bs:", $this->{ini}->pVariable('bs', 10.0), "%12.6g", $EntryWidth, "eV/sq(V/m)", 2, 0); $this->MakeCheckEntry($Frame, "kbs", "kbs:", $this->{ini}->pVariable('kbscheck', 0), $this->{ini}->pVariable('kbs', 1.0), "%8.6g", $EntryWidth, "", 2, 1); $Frame = $mw->MyLabFrame( -label => 'ohmic/SCLC', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "sigma", "s:", $this->{ini}->pVariable('sigmacheck', 1), $this->{ini}->pVariable('sigma', 0.0), "%12.6g", $EntryWidth, "S/cm", 0, 0); $this->MakeCheckEntry($Frame, "mus", "u:", $this->{ini}->pVariable('muscheck', 1), $this->{ini}->pVariable('mus', 10.0), "%12.6g", $EntryWidth, "cm2/Vs", 0, 1); $Frame = $mw->MyLabFrame( -label => 'polynomial', -labelside => 'acrosstop', )->pack(-anchor => 'nw'); $this->MakeCheckEntry($Frame, "c0", "c0:", $this->{ini}->pVariable('c0check', 1), $this->{ini}->pVariable('c0', 0.0), "%8.6g", $EntryWidth, "", 0, 0); $this->MakeCheckEntry($Frame, "c1", "c1:", $this->{ini}->pVariable('c1check', 1), $this->{ini}->pVariable('c1', 0.0), "%8.6g", $EntryWidth, "", 0, 1); $this->MakeCheckEntry($Frame, "c2", "c2:", $this->{ini}->pVariable('c2check', 1), $this->{ini}->pVariable('c2', 0.0), "%8.6g", $EntryWidth, "", 2, 0); $this->MakeCheckEntry($Frame, "c3", "c3:", $this->{ini}->pVariable('c3check', 1), $this->{ini}->pVariable('c3', 0.0), "%8.6g", $EntryWidth, "", 2, 1); $Frame = $mw->MyFrame()->pack(-anchor => 'nw', -fill => 'x'); $this->{RecalcButton} = $Frame->MyButton( -text => 'Re&calc', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'Recalc'], )->pack(-side => 'left'); $this->{FitButton} = $Frame->MyButton( -text => '&Fit', -takefocus => 1, -command => [\&ButtonPressed, $this, 'RButtonDown', 'Fit'], )->pack(-side => 'left'); $this->UpdateParameters(); #ツールバーのOpenボタンをファイル読み込みにバインドする $mw->{OpenButton}->configure( -command => [ \&ChooseFile, $this, $this->{SPEFileFileEntry} ], ) if($mw->{OpenButton}); } sub InsertToolBar { my ($this, $frame) = @_; #ツールバーに追加 my $spb1 = $this->mw()->{ShowRecalcDataButton} = $frame->MyCheckbutton( -text => 'Show Recalc data', -takefocus => 1, -variable => $this->{ini}->pVariable('ShowRecalcData', 1), -indicatoron => 0, )->pack(-side => 'left', -fill => 'x'); my $spb2 = $this->mw()->{ShowCalcPlotButton} = $frame->MyCheckbutton( -text => 'Show CalcPlot', -takefocus => 1, -variable => $this->{ini}->pVariable('ShowCalcPlot', 1), -indicatoron => 0, )->pack(-side => 'left', -fill => 'x'); my $spb3 = $this->mw()->{AutoUpdateButton} = $frame->MyCheckbutton( -text => 'Auto Update', -takefocus => 1, -variable => $this->{ini}->pVariable('AutoUpdate', 0), -indicatoron => 0, )->pack(-side => 'left', -fill => 'x'); } sub ButtonPressed { my ($this, $event, $type) = @_; my $App = $this->App(); if($type eq 'Recalc') { &Recalc($this); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); return; } elsif($type eq 'Fit') { &Fit($this); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); return; } elsif($type eq 'SaveParam') { $this->{ini}->{Model} = $this->{ChooseModelListBox}->GetText(); $this->{ini}->{X} = $this->{ChooseXListBox}->GetText(); $this->{ini}->{Y1} = $this->{ChooseY1ListBox}->GetText(); $this->{ini}->SetIniFile($this->{ini}->{ParameterFile}, undef, 1); if(!defined $this->{ini}->IniFile() or $this->{ini}->IniFile() eq '') { my $path = $this->ChooseSaveFile('save.prm', '*.prm'); if($path) { $this->{ini}->SetIniFile($path, undef, 1); $this->{ini}->{ParameterFile} = $path; } else { return; } } $this->{ini}->WriteAll(); return; } elsif($type eq 'EditParam') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{ParameterFile}; my $command = "$Editor $File"; system($command); return; } elsif($type eq 'EditData') { my $Editor = $this->App()->{EditorPath}; my $File = $this->{ini}->{DataFile}; my $command = "$Editor $File"; system($command); return; } } sub UpdateParameters { my ($this) = @_; my $mater = new Material; my $Dc0 = $mater->Dc0($this->{ini}->{mes}*$me, 1.0); $this->{ini}->{NCs} = $mater->Nc($this->{ini}->{mes}*$me, 1.0, $this->{ini}->{T}) * 1.0e-6; $this->{ini}->{EFs} = $this->{ini}->{ECs} + $mater->CalEFFromNe($this->{ini}->{Nes}*1.0e6, $this->{ini}->{T}); # $this->{ini}->{EFs} = $mater->BMShift($this->{ini}->{Nes}*1.0e6, $Dc0); my ($R, $Reff) = $mater->RichardsonDushman($this->{ini}->{mem}*$me); $this->{ini}->{Am} = $Reff; # $this->{ini}->{Vd} = -($this->{ini}->{EFs} - $this->{ini}->{EFm}); # $this->{ini}->{phiSBH} = -($this->{ini}->{ECs} - $this->{ini}->{EFm}); $this->{ini}->{bs} = sqrt($e / 4.0 / $pi / $e0 / $this->{ini}->{Epss}); my $T = $this->{ini}->{T}; my $ekT = $e / $kB / $T; $this->{ini}->{Is0} = $this->{ini}->{Am} * $T * $T * exp(-$this->{ini}->{phiSBH} * $ekT) * $this->{ini}->{S} * 1.0e-4; my $pEA = $this->{pEntryArray}; for(my $i = 0 ; $i < @$pEA ; $i++) { $pEA->[$i]->Update(); } } sub EntryFocusedOut { my ($this, $obj, $event, $type) = @_; #print "type: $type\n"; my $mater = new Material; if($event eq 'FocusOut') { if($type eq 'Am') { $this->{ini}->{mem} = $mater->CalEffectiveMassFromRichardsonDushman($this->{ini}->{Am}) / $me; } elsif($type eq 'Vd') { $this->{ini}->{EFm} = $this->{ini}->{EFs} + $this->{ini}->{Vd}; } elsif($type eq 'phiSBH') { $this->{ini}->{ECs} = $this->{ini}->{EFm} - $this->{ini}->{phiSBH}; } } if($this->{ini}->{AutoUpdate} and defined $this->{ini}->{"${type}check"}) { &Recalc($this); $this->CreateGraphFrame() if(!defined $this->{GraphFrameArray}); $this->AssignGraphData(0); $this->Draw(); } else { $this->UpdateParameters(); } } #=================================================== # データ処理 #=================================================== sub Recalc { my ($this) = @_; return if(!$this->{ini}->{ShowCalcPlot}); $this->UpdateParameters(); my $iXLabel = $this->{"ChooseXListBox"}->GetCurSel(); my $ppDataArray = $this->{ppDataArray}; my $pV = $ppDataArray->[$iXLabel]; return unless($pV); my $Model = $this->{"ChooseModelListBox"}->GetText(); my $Show = $this->{ini}->{ShowRecalcData}; if($Model eq 'Polynomial') { ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{c0}, $this->{ini}->{c1}, $this->{ini}->{c2}, $this->{ini}->{c3}, $Show); } elsif($Model eq 'Ohmic/SCLC') { ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{sigma}, $this->{ini}->{mus}, $Show); } elsif($Model eq 'SymForwardSchottky') { ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $Show); } elsif($Model eq 'SymReverseSchottky') { ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}, $Show); } elsif($Model eq 'SymReverseNDSchottky') { my $lnNDs = log($this->{ini}->{NDs}); ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}, $lnNDs, $this->{ini}->{Vd}, $Show); } } sub Fit { my ($this) = @_; my $ini = $this->{ini}; $this->UpdateParameters(); my $iXLabel = $this->{"ChooseXListBox"}->GetCurSel(); my $iY1Label = $this->{"ChooseY1ListBox"}->GetCurSel(); my $ppDataArray = $this->{ppDataArray}; my $pV = $ppDataArray->[$iXLabel]; my $pY1 = $ppDataArray->[$iY1Label]; my $nData = @$pV; my $MaxI = 0.0; for(my $i = 0 ; $i < $nData ; $i++) { my $absI = abs($pY1->[$i]); $MaxI = $absI if($MaxI < $absI); } # my $Opt = new Optimize; my $optimize = new Optimize; $this->{Optimize} = $optimize; my $FitXMin = $ini->{FitXMin}; my $FitXMax = $ini->{FitXMax}; my $nSkipData = $ini->{nSkipData}; my $Method = $this->{ChooseLSQMethodListBox}->GetText(); my $EPS = $ini->{EPS}; my $nMaxIter = $ini->{nMaxIter}; my $iPrintLevel = $ini->{iPrintLevel}; my $Model = $this->{"ChooseModelListBox"}->GetText(); if($Model eq 'Polynomial') { my ($pName, $ppVariable, $pGuess, $pOptId, $pScale) = $optimize->AddParameters( "c0", \$this->{ini}->{c0}, $this->{ini}->{c0check}, 1, "C1", \$this->{ini}->{c1}, $this->{ini}->{c1check}, 1, "C2", \$this->{ini}->{c2}, $this->{ini}->{c2check}, 1, "C3", \$this->{ini}->{c3}, $this->{ini}->{c3check}, 1, ); } if($Model eq 'Ohmic/SCLC') { my ($pName, $ppVariable, $pGuess, $pOptId, $pScale) = $optimize->AddParameters( "sigma", \$this->{ini}->{sigma}, $this->{ini}->{sigmacheck}, $MaxI*10.0, "mus", \$this->{ini}->{mus}, $this->{ini}->{c1check}, 1.0, ); } elsif($Model eq 'SymForwardSchottky') { my ($pName, $ppVariable, $pGuess, $pOptId, $pScale) = $optimize->AddParameters( "phiSBH", \$this->{ini}->{phiSBH}, $this->{ini}->{phiSBHcheck}, 1, "ndiode", \$this->{ini}->{ndiode}, $this->{ini}->{ndiodecheck}, 1, ); } elsif($Model eq 'SymReverseSchottky') { my ($pName, $ppVariable, $pGuess, $pOptId, $pScale) = $optimize->AddParameters( "phiSBH", \$this->{ini}->{phiSBH}, $this->{ini}->{phiSBHcheck}, 1, "ndiode", \$this->{ini}->{ndiode}, $this->{ini}->{ndiodecheck}, 1, "kbs", \$this->{ini}->{kbs}, $this->{ini}->{kbscheck}, 1, ); } elsif($Model eq 'SymReverseNDSchottky') { my $lnNDs = log($this->{ini}->{NDs}); my ($pName, $ppVariable, $pGuess, $pOptId, $pScale) = $optimize->AddParameters( "phiSBH", \$this->{ini}->{phiSBH}, $this->{ini}->{phiSBHcheck}, 1, "ndiode", \$this->{ini}->{ndiode}, $this->{ini}->{ndiodecheck}, 1, "kbs", \$this->{ini}->{kbs}, $this->{ini}->{kbscheck}, 1, "lnNDs", \$lnNDs, $this->{ini}->{NDscheck}, 20, "Vd", \$this->{ini}->{Vd}, $this->{ini}->{Vdcheck}, 1, ); } my ($OptVars, $MinVal) = $optimize->Optimize( $Method, undef, undef, undef, $EPS, $nMaxIter, $iPrintLevel, sub { $this->CalS2($FitXMin, $FitXMax, $nSkipData, @_); }, undef, sub { Optimize::BuildDifferentialMatrixes(@_); }, ); print "\nOptimized at S=$MinVal:\n"; my $pNames = $optimize->pParameterNameArray(); for(my $i = 0 ; $i < @$OptVars ; $i++) { print "$i:[$pNames->[$i]] $OptVars->[$i]\n"; } my $IsPrint = 0; if($Model eq 'Polynomial') { ($this->{ini}->{c0}, $this->{ini}->{c1}, $this->{ini}->{c2}, $this->{ini}->{c3}) = @$OptVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{c0}, $this->{ini}->{c1}, $this->{ini}->{c2}, $this->{ini}->{c3}, $IsPrint); } elsif($Model eq 'Ohmic/SCLC') { ($this->{ini}->{sigma}, $this->{ini}->{mus}) = @$OptVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{sigma}, $this->{ini}->{mus}, $IsPrint); } elsif($Model eq 'SymForwardSchottky') { ($this->{ini}->{phiSBH}, $this->{ini}->{ndiode}) = @$OptVars; $this->{ini}->{ECs} = $this->{ini}->{EFm} - $this->{ini}->{phiSBH}; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $IsPrint); } elsif($Model eq 'SymReverseSchottky') { ($this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}) = @$OptVars; $this->{ini}->{ECs} = $this->{ini}->{EFm} - $this->{ini}->{phiSBH}; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}, $IsPrint); } elsif($Model eq 'SymReverseNDSchottky') { my $lnNDs; ($this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}, $lnNDs, $this->{ini}->{Vd}) = @$OptVars; $this->{ini}->{NDs} = exp($lnNDs); $this->{ini}->{ECs} = $this->{ini}->{EFm} - $this->{ini}->{phiSBH}; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $this->{ini}->{phiSBH}, $this->{ini}->{ndiode}, $this->{ini}->{kbs}, $lnNDs, $this->{ini}->{Vd}, $IsPrint); } print "\nOptimized at:\n"; # $optimize->PrintParameters(1); # $optimize->RecoverParameters($OptVars); # $this->SetS2($MinVal); $this->UpdateParameters(); } sub CalS2 { my ($this, $FitXMin, $FitXMax, $nSkipData, $pVars, $iPrintLevel) = @_; my $optimize = $this->{Optimize}; my $ini = $this->{ini}; my $iXLabel = $this->{"ChooseXListBox"}->GetCurSel(); my $iY1Label = $this->{"ChooseY1ListBox"}->GetCurSel(); my $ppDataArray = $this->{ppDataArray}; my $pV = $ppDataArray->[$iXLabel]; my $pY1 = $ppDataArray->[$iY1Label]; my $nData = @$pV; return 1.0e10 unless($pV); # $optimize->RecoverParameters($pVars); $optimize->IncrementnS2(); my $nS2 = $optimize->nS2Calculation(); my $nS2Interval = $ini->{nSaveSpectraInterval}; my $Model = $this->{"ChooseModelListBox"}->GetText(); if($Model eq 'Polynomial') { my ($c0, $c1, $c2, $c3) = @$pVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $c0, $c1, $c2, $c3, 0); } elsif($Model eq 'Ohmic/SCLC') { my ($sigma, $mus) = @$pVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $sigma, $mus, 0); } elsif($Model eq 'SymForwardSchottky') { my ($phiSBH, $n) = @$pVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $phiSBH, $n, 0); } elsif($Model eq 'SymReverseSchottky') { my ($phiSBH, $n, $kbs) = @$pVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $phiSBH, $n, $kbs, 0); } elsif($Model eq 'SymReverseNDSchottky') { my ($phiSBH, $n, $kbs, $lnNDs, $Vd) = @$pVars; ($this->{pVcal}, $this->{pIcal}) = $this->CalI($Model, $pV, $this->{ini}->{T}, $phiSBH, $n, $kbs, $lnNDs, $Vd, 0); } my $MaxI = 0.0; my $S2 = 0.0; my $c = 0; $pV = $this->{pVcal}; $nData = @$pV; for(my $i = 0 ; $i < $nData ; $i++) { #print "$i: $pY1->[$i], $this->{pIcal}->[$i]\n"; my $V = $pV->[$i]; my $r = ($pV->[$i] - $FitXMin) / ($FitXMax - $FitXMin); next if($r < 0.0 or $r > 1.0); next if($nSkipData > 1 and $i % $nSkipData != 0); my $dif = $pY1->[$i] - $this->{pIcal}->[$i]; $S2 += $dif * $dif; my $absI = abs($pY1->[$i]); $MaxI = $absI if($MaxI < $absI); $c++; } $c = 1 if($c <= 0); $S2 = $S2 / $c / $MaxI / $MaxI; print "S2=$S2\n"; # $optimize->PrintParameters(1, $pVars, $S2, 0); if($nS2Interval > 0 and $nS2 % $nS2Interval == 0) { # $this->SetS2($S2, 0); $this->Recalc(); # $this->CreateGraphFrame(); $this->AssignGraphData(0); $this->Draw(); } $this->UpdateParameters(); $this->mw()->update(); return $S2; } sub CalI { my ($this, $Model, $IsPrint) = @_; my ($pV, $T, $phiB, $n, $kbs, $lnNDs, $Vd); my ($c0, $c1, $c2, $c3); my ($sigma, $mus); if($Model eq 'Polynomial') { ($this, $Model, $pV, $c0, $c1, $c2, $c3, $IsPrint) = @_; } elsif($Model eq 'Ohmic/SCLC') { ($this, $Model, $pV, $sigma, $mus, $IsPrint) = @_; } elsif($Model eq 'SymForwardSchottky') { ($this, $Model, $pV, $T, $phiB, $n, $IsPrint) = @_; } elsif($Model eq 'SymReverseSchottky') { ($this, $Model, $pV, $T, $phiB, $n, $kbs, $IsPrint) = @_; } elsif($Model eq 'SymReverseNDSchottky') { ($this, $Model, $pV, $T, $phiB, $n, $kbs, $lnNDs, $Vd, $IsPrint) = @_; } #print "Model: $Model IsPrint: $IsPrint\n"; my $ini = $this->{ini}; my $FitXMin = $ini->{FitXMin}; my $FitXMax = $ini->{FitXMax}; my $nSkipData = $ini->{nSkipData}; my (@Vcal, @Ical); my $nData = @$pV; # my $T = $this->{ini}->{T}; my $S = $this->{ini}->{S} * 1.0e-4; # m2 my $c = 0; if($Model eq 'Polynomial') { for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; next if($nSkipData > 1 and $i % $nSkipData != 0); next if($V < $FitXMin or $FitXMax < $V); $Vcal[$c] = $V; $Ical[$c] = ($c0 + $c1 * $V + $c2 * $V**2 + $c3 * $V**3) * $S; print "$V: $Ical[$c]\n" if($IsPrint); $c++; } } elsif($Model eq 'Ohmic/SCLC') { my $K1 = $sigma * $this->{ini}->{S} / $this->{ini}->{ds}; my $K2 = 9.0/8.0 * ($mus * 1.0e-4) * ($e0 * $this->{ini}->{Epss}) / ($this->{ini}->{ds} * 1.0e-2)**3 * $this->{ini}->{S}; for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; next if($nSkipData > 1 and $i % $nSkipData != 0); next if($V < $FitXMin or $FitXMax < $V); my $sign = 1.0; $sign = -1.0 if($V < 0.0); $Vcal[$c] = $V; $Ical[$c] = $K1 * $V + $sign * $K2 * $V*$V; print "$V: $Ical[$c]\n" if($IsPrint); $c++; } } elsif($Model eq 'SymForwardSchottky') { my $ekT = $e / $kB / $T; my $K = $this->{ini}->{Am} * $T * $T * exp(-$phiB * $ekT); my $enkT = $e / $kB / $T / $n; for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; next if($nSkipData > 1 and $i % $nSkipData != 0); next if($V < $FitXMin or $FitXMax < $V); $Vcal[$c] = $V; $Ical[$c] = $K * $S * (exp($V * $enkT) - exp(-$V * $enkT)) / 2.0; print "$V: $Ical[$c]\n" if($IsPrint); $c++; } } elsif($Model eq 'SymReverseSchottky') { my $ekT = $e / $kB / $T; my $ekbskT = $this->{ini}->{bs} * $kbs * $ekT; my $K = $this->{ini}->{Am} * $T * $T * exp(-$phiB * $ekT); my $enkT = $e / $kB / $T / $n; my $d = $this->{ini}->{ds} * 1.0e-2; # m for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; next if($nSkipData > 1 and $i % $nSkipData != 0); next if($V < $FitXMin or $FitXMax < $V); $Vcal[$c] = $V; my $E = $V / $d; my $I = $S * $K * (exp($ekbskT * sqrt(abs($E))) - 1.0); if($V >= 0.0) { $Ical[$c] = $I; } else { $Ical[$c] = -$I; } print "$V: $Ical[$c]\n" if($IsPrint); $c++; } } elsif($Model eq 'SymReverseNDSchottky') { my $ekT = $e / $kB / $T; my $ekbskT = $this->{ini}->{bs} * $kbs * $ekT; my $K = $this->{ini}->{Am} * $T * $T * exp(-$phiB * $ekT); my $enkT = $e / $kB / $T / $n; my $ND = exp($lnNDs) * 1.0e6; # m-3 my $er = $this->{ini}->{Epss}; my $Ke = $e / $e0 / $er; my $Kc = sqrt(2.0)/4.0/$pi; #print "Ke=$Ke, $e, $e0, $er, Kc=$Kc\n"; #print "Ke^1.5=", $Ke**1.5, "\n"; my $Kexp = $ekT * sqrt( $Ke**1.5 * $Kc * sqrt($ND)); #print "ekT=$ekT, n=$n, enkT=$enkT\n"; #print "Kexp=$Kexp, ND=$ND m-3\n"; for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; next if($nSkipData > 1 and $i % $nSkipData != 0); next if($V < $FitXMin or $FitXMax < $V); $Vcal[$c] = $V; if($V >= 0.0) { if($Vd + $V >= 0.0) { $Ical[$c] = -$S * $K * exp( $Kexp * ($Vd + $V)**0.25 ) * (exp(-$V * $ekT) - 1.0); } else { $Ical[$c] = -$S * $K * $Kexp * (exp(-$V * $ekT) - 1.0); } } else { if($Vd - $V >= 0.0) { $Ical[$c] = $S * $K * exp( $Kexp * ($Vd - $V)**0.25 ) * (exp($V * $ekT) - 1.0); } else { $Ical[$c] = $S * $K * $Kexp * (exp($V * $ekT) - 1.0); } } print "$V: $Ical[$c]\n" if($IsPrint); $c++; } } return (\@Vcal, \@Ical); } sub ReadFile { my ($this, $filepath, $IsPrint, $UpdateRange) = @_; $UpdateRange = 1 if(!defined $UpdateRange); my $App = $this->App(); #print "type=$type\n"; $this->{Path} = $filepath; $this->{CSV} = new CSV(); my ($nData, $pLabelArray, @pDataArray) = CSV::GetArraysFromFile($filepath); # if(!defined $nData) { if(!$this->{CSV}->Read($this->{Path})) { $App->print("Error: Can not read [$filepath].\n"); return $this->{Path} = undef; } # $this->{pLabelArray} = $pLabelArray; # $this->{ppDataArray} = \@pDataArray; $this->{pLabelArray} = $this->{CSV}->LabelArray(); $this->{ppDataArray} = $this->{CSV}->DataArray(); my $nDataArray = @$pLabelArray; #print "nDataArray: $nDataArray\n"; $this->{"ChooseXListBox"}->DeleteAllItem(); $this->{"ChooseY1ListBox"}->DeleteAllItem(); for(my $i = 0 ; $i < $nDataArray ; $i++) { #print "$i: $pLabelArray->[$i]\n"; $this->{"ChooseXListBox"}->AddItem($pLabelArray->[$i]); $this->{"ChooseY1ListBox"}->AddItem($pLabelArray->[$i]); } $this->{"ChooseXListBox"}->SetCurSel('V', '.*V.*'); $this->{"ChooseY1ListBox"}->SetCurSel('AJ.*', 'AI.*', 'J.*', 'I.*', '.*J.*', '.*I.*'); if($UpdateRange or !defined $this->{ini}->{FitXMin}) { ($this->{ini}->{FitXMin}, $this->{ini}->{FitXMax}) = Utils::CalMinMax($pDataArray[0]); } $this->CreateGraphFrame(); $this->AssignGraphData($UpdateRange); #print "R: $ResetViewRange\n"; 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); $XScale0->SetScaleStringVisible(1); $XScale0->SetCaptionVisible(1); $GraphFrame0->SetViewRange(0, 0, 1, 1); } sub AssignGraphData { my ($this, $ResetViewRange) = @_; $ResetViewRange = 1 if(!defined $ResetViewRange); my $GraphFrameArray = $this->GetGraphFrameArray(); if(!defined $GraphFrameArray) { $this->CreateGraphFrame(); $GraphFrameArray = $this->GetGraphFrameArray(); } my $GraphFrame0 = $GraphFrameArray->GetGraphFrame(0); $GraphFrame0->ClearAllData(); my $iXLabel = $this->{"ChooseXListBox"}->GetCurSel(); $iXLabel = 0 if(!defined $iXLabel); my $iY1Label = $this->{"ChooseY1ListBox"}->GetCurSel(); $iY1Label = 1 if(!defined $iY1Label); my $XLabel = $this->{"ChooseXListBox"}->GetText(); $XLabel = 'V' if(!defined $XLabel); my $Y1Label = $this->{"ChooseY1ListBox"}->GetText(); $Y1Label = 'I' if(!defined $Y1Label); my $pLabelArray = $this->{pLabelArray}; my $ppDataArray = $this->{ppDataArray}; my $pX = $ppDataArray->[$iXLabel]; my $pY1 = $ppDataArray->[$iY1Label]; if($pX) { my $nData = @$pX; my $nDataArray = @$pLabelArray; return unless($pX or $pY1); $GraphFrame0->SetXCaption($XLabel); $GraphFrame0->SetYCaption($Y1Label); my $nData0 = $GraphFrame0->AddGraphData($pX, $pY1, 1, "black", "", 6, "red", 0, "red", "XAutoSkip", $XLabel, $Y1Label); } if($this->{ini}->{ShowCalcPlot} and $this->{pIcal}) { my $nData1 = $GraphFrame0->AddGraphData($this->{pVcal}, $this->{pIcal}, 1, "red", "", 6, "red", 0, "red", "XAutoSkip", $XLabel, "${Y1Label}(cal)"); } $GraphFrame0->SetYScalePlotType('x'); $GraphFrame0->CalMinMax(); $GraphFrame0->AdjustViewRange(0.05, 0.05, 0.05, 0.05); if($ResetViewRange) { $this->{ini}->{FitXMin} = $GraphFrame0->XMin(); $this->{ini}->{FitXMax} = $GraphFrame0->XMax(); } } sub AdjustViewRange { my ($this) = @_; my $GraphFrameArray = $this->GetGraphFrameArray(); my $pGraphFrame = $GraphFrameArray->GetpGraphFrameArray(); my $FileType = $this->FileType(); if($FileType =~ /(Ids)/i) { } } sub Draw { my ($this, $canvas, $TargetData) = @_; my $mw = $this->mw(); $canvas = $this->Canvas() if(!$canvas); # my $FileType = $this->FileType(); my $App = $this->App(); my $font = $App->{'GraphFrameFont'}; my @font = split(/,/, $font) if($font); my $GraphFrameArray = $this->GetGraphFrameArray(); return unless($GraphFrameArray); $canvas->ClearAll(); $mw->RefleshCanvas(); if($font) { $canvas->SetFont(\@font); $GraphFrameArray->SetFont(\@font); } my $w = $canvas->width(); my $h = $canvas->height(); $GraphFrameArray->SetCanvasSize($w, $h); $this->mw()->WriteStatusBar("Drawing IV..."); # $this->ReadFiles($this->FileName(), $TargetData); # $this->CreateGraphFrame($canvas, $TargetData); # $this->AssignGraphData(); $mw->Balloon()->detach($canvas); $GraphFrameArray->Draw($canvas); $this->mw()->WriteStatusBar("Finish IV."); } sub SelChangeListBox { my ($this, $type, $lb) = @_; #print "this:$this lb=$lb\n"; my $s = $lb->GetText(); # if($s =~ /Solar/i) { # } # $this->CreateGraphFrame(); $this->AssignGraphData(); $this->Draw(); } sub ChooseFile { my ($this, $type, $widget, $Option) = @_; my $App = $this->App(); my $canvas = $this->Canvas(); my $mw = $this->mw(); my $mode = 'open'; my $fmask = '*.csv'; 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, $mode, $fmask, $defstr, $message, $dir); if($filepath) { my $DirPath = $this->SetWorkDir($filepath); if($widget) { $widget->SetText($filepath); } } else { return undef; } my $ret; if($Option eq 'ChooseParameterFile') { $this->{ini}->{DataFile} = ''; $this->{ini}->ReadAll($filepath); $this->{ini}->{ParameterFile} = $filepath; $this->{ChooseModelListBox}->SetText($this->{ini}->{Model}) if($this->{ChooseModelListBox} and $this->{ini}->{Model}); $this->{ChooseXListBox}->SetText($this->{ini}->{X}) if($this->{ChooseXListBox} and $this->{ini}->{X}); $this->{ChooseY1ListBox}->SetText($this->{ini}->{Y1}) if($this->{ChooseY1ListBox} and $this->{ini}->{Y1}); if($this->{ini}->{DataFile}) { $ret = $this->ReadFile($this->{ini}->{DataFile}, 1, 0); return undef unless($ret); $this->Draw(); } } elsif($Option eq 'ChooseCSVFile') { $ret = $this->ReadFile($filepath); return undef unless($ret); $this->Draw(); } return $ret; } sub ChooseSaveFile { my ($this, $path, $fmask, $widget) = @_; $path = 'save.csv' if(!defined $path); $fmask = '*.csv' if(!defined $fmask); $path = $widget->GetText() if($widget); $path = 'out.csv' if(!$path); my $App = $this->App(); my $mw = $this->mw(); my $dir = $this->App()->{WorkDir}; chdir($dir) if($dir); my $defstr = $path; my $message = 'Choose file'; my $filepath = Dialog::OpenFileDialog($mw, 'save', $fmask, $defstr, $message, $dir); if($filepath) { my $DirPath = $this->SetWorkDir($filepath); if($widget) { $widget->SetText($filepath); } } return $filepath; } sub InitializeParameters { my ($this, $ini, $dini) = @_; # $this->AddParameters($ini, $dini, "EF", 0.0, 0, 1.0, '', ''); } 1;