package SolarCell; use Exporter; @ISA = qw(Exporter); #公開したいサブルーチン @EXPORT = qw(); use strict; use File::Basename; use Utils; use Sci qw($pi $kB $R $NA $c $e $e0 $u0 $me $mp $mn $h $hbar $torad $todeg); use Sci::Algorism; use Sci::Material; use Sci::Optimize; use CSV; #============================================================ # 変数等取得、再定義関数 #============================================================ sub SetLightIntensity { my ($this, $F) = @_; $this->{F} = $F; } sub SetTemplature { my ($this, $T) = @_; $this->{T} = $T; } #============================================================ # コンストラクタ、デストラクタ #============================================================ sub new { my ($module) = @_; my $this = {}; bless $this; return $this; } sub DESTROY { my $this = shift; } #============================================================ # 一般関数 #============================================================ sub ReadIVData { my ($this, $path, $VLabel, $ILabel, $JLabel, $nMinimumLabels, $ReadCheckFunc) = @_; $VLabel = "V.*" if(!defined $VLabel); $ILabel = "I.*" if(!defined $ILabel); $JLabel = $ILabel if(!defined $JLabel); $this->{CSV} = new CSV; return undef if(!$this->{CSV}->Read($path, undef, undef, $nMinimumLabels, $ReadCheckFunc)); #my $pLabelArray = $this->{CSV}->LabelArray(); #print "Label: ", join(',', @$pLabelArray), "\n"; #my $pDataArray = $this->{CSV}->DataArray(); $this->{pV} = $this->{CSV}->GetXData($VLabel); $this->{pI} = $this->{CSV}->GetYData($ILabel); $this->{pJ} = $this->{CSV}->GetYData($JLabel); $this->{nData} = scalar @{$this->{pV}}; return ($this->{pV}, $this->{pI}, $this->{pJ}, $this->{nData}); } sub Analyze { my ($this, $IsPrint) = @_; $this->{Area} = $this->{pI}->[0] / $this->{pJ}->[0]; ($this->{Vmin}, $this->{Vmax}) = Utils::CalMinMax($this->{pV}); ($this->{Imin}, $this->{Imax}) = Utils::CalMinMax($this->{pI}); my $nData = $this->{nData}; my $pV = $this->{pV}; my $pJ = $this->{pJ}; my $pW = []; my $pdJdV = []; my ($Vop, $Jop); my $Wmax = 0.0; my $Vsat; my $dJdVmin = 1.0e10; my $dJdVmaxAtForward = -1.0e10; my $VforR; my $dJdVminAtReverse = 1.0e10; my $VrevR; for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; $pW->[$i] = -$V * $pJ->[$i] * 1.0e3; $pdJdV->[$i] = Algorism::DifferentiateByCubicSpline($pV, $pJ, $V); next if($i == $nData-1 or $i == 0); if($V >= 0.0) { if($dJdVmaxAtForward < $pdJdV->[$i]) { $dJdVmaxAtForward = $pdJdV->[$i]; $VforR = $V; } } if($V >= 0.0 and $pJ->[$i] <= 0.0) { if($Wmax < $pW->[$i]) { $Wmax = $pW->[$i]; $Vop = $V; $Jop = -$pJ->[$i] * 1.0e3; #mA/cm2 } } if($V <= 0.0) { if($dJdVmin > $pdJdV->[$i]) { $dJdVmin = $pdJdV->[$i]; $Vsat = $V; } if($dJdVminAtReverse > $pdJdV->[$i] and $pdJdV->[$i] >= 0.0) { $dJdVminAtReverse = $pdJdV->[$i]; $VrevR = $V; } } } $this->{Vsat} = $Vsat; $this->{Jsat} = -$this->{CSV}->YVal($pV, $pJ, $Vsat) * 1.0e3; #mA/cm2 $this->{Jsc} = -$this->{CSV}->YVal($pV, $pJ, 0.0) * 1.0e3; #mA/cm2 $this->{Voc} = $this->{CSV}->XValByBinaryMethod($pV, $pJ, 0.0);#, 1.0e-6, 300, 0.0, $Vmax, 0.01); $this->{Vop} = $Vop; $this->{Jop} = $Jop; $this->{Wmax} = $Wmax; if($this->{Jsc} * $this->{Voc} == 0.0) { $this->{FF} = 0.0; $this->{Eff} = 0.0; } else { $this->{FF} = $Wmax / ($this->{Jsc} * $this->{Voc}); $this->{Eff} = $this->{Voc} * $this->{Jsc} * $this->{FF} * 100.0 / $this->{F}; } $this->{RsOn} = 1.0 / $dJdVmaxAtForward; $this->{RsVoc} = 1.0 / $this->{CSV}->YVal($pV, $pdJdV, $this->{Voc}); $this->{Rsh0} = 1.0 / $this->{CSV}->YVal($pV, $pdJdV, 0.0); $this->{RsRev} = 1.0 / $dJdVminAtReverse; $this->{VforR} = $VforR; $this->{VrevR} = $VrevR; my $log10 = log(10.0); my $Joffset = 1.0e-10; my $plogJ = []; my $pdlogJdV = []; my $pDiodeFactor = []; my $dlogJdVmin = 1.0e10; my $Vdfactor; my $dlogJdVdfactor; my $ekT = $e / $kB / $this->{T}; for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; $plogJ->[$i] = log(abs($pJ->[$i] + $this->{Jsc}*1.0e-3 + $Joffset));# / $log10; } for(my $i = 0 ; $i < $nData ; $i++) { my $V = $pV->[$i]; $pdlogJdV->[$i] = Algorism::DifferentiateByCubicSpline($pV, $plogJ, $V); if($V >= 0.0) { if($dlogJdVmin > $pdlogJdV->[$i]) { $dlogJdVmin = $pdlogJdV->[$i]; $Vdfactor = $V; $dlogJdVdfactor = $pdlogJdV->[$i]; } } if($V > 0.0 and $pdlogJdV->[$i] > 0.0) { $pDiodeFactor->[$i] = $ekT * $V / $pdlogJdV->[$i]; } } $this->{pdJdV} = $pdJdV; $this->{pdlogJdV} = $pdlogJdV; $this->{pW} = $pW; $this->{pDiodeFactor} = $pDiodeFactor; print "dlog(|J|)/dV(min)=$dlogJdVdfactor (V=$Vdfactor V)\n" if($IsPrint); my $pV1 = []; my $plogJ1 = []; my $c = 0; for(my $i= 0 ; $i < $nData ; $i++) { next if($pV->[$i] <= 0.0); $pV1->[$c] = $pV->[$i]; $plogJ1->[$c] = $plogJ->[$i]; #print "${i}[$c]: $pV1->[$c], $plogJ1->[$c]\n"; $c++; } my $iPrintLevel2 = 0; my $m = 2; my ($pCi, $S2) = Optimize->new()->Optimize("mlsq", $pV1, $plogJ1, $m, $iPrintLevel2); if($IsPrint) { print "C0=$pCi->[0]\n"; print "C1=$pCi->[1]\n"; print "C2=$pCi->[2]\n"; print "S2=$S2\n"; } $this->{J0} = exp($pCi->[0]); $this->{n} = $ekT / $pCi->[1]; $this->{Jpv} = $this->{Jsat}*1.0e-3 - $this->{J0}; } sub WriteAnalyzeCSV { my ($this, $path) = @_; my $nData = $this->{nData}; my $pV = $this->{pV}; my $pI = $this->{pI}; my $pJ = $this->{pJ}; my $pdJdV = $this->{pdJdV}; my $pdlogJdV = $this->{pdlogJdV}; my $pW = $this->{pW}; my $pDiodeFactor = $this->{pDiodeFactor}; my $out = new JFile; print("Write to [$path]\n"); $out->Open($path, "w") or return undef; $out->print("V(V),I(A),J(A/cm2),|J|(A/cm2),W(mW/cm2),dJ/dV(S/cm),dlog(|J|)/dV,n\n"); for(my $i = 0 ; $i < $nData ; $i++) { my $absJ = abs($pJ->[$i]); $out->print("$pV->[$i],$pI->[$i],$pJ->[$i],$absJ,$pW->[$i]," ."$pdJdV->[$i],$pdlogJdV->[$i],$pDiodeFactor->[$i]\n"); } $out->Close(); return 1; } 1;