Integ()
,
die direkt in einer Zelle aufgerufen wird und den Integralwert ausgibt.
Parameter dieser Funktion sind Bereiche der x- und y-Werte in einer beliebig langen Abfolge, so dass beliebig viele Spektren miteinander durchmultipliziert werden können.
Wenn die ersten beiden Parameter nur einfache Zahlen sind, dann werden sie als Obergrenze und Untergrenze interpretiert.
Ist der dritte Parameter "SER"
, dann wird jeder Wert mit der errechneten erythemwirksamen Wirkung multipliziert. Das hat speziell beim Erythem
den Vorteil, dass gar nicht interpoliert werden muss.
Um die Spektren zu sortiert zu halten ist übrigens noch der Quicksortalgorithmus angefügt.
Zur Installation einfach eine Exceldatei mit Makros, erkennbar an der Endung *.xlsm, erstellen und dort in der Visual Basic Umgebung, die man durch Alt + F11 aufruft,
das Modul Integrale_VBA_excel.bas
laden. Abbildung =Integ(B23;C23;"Ser";'80041106'!$A$9:$A$609;'80041106'!$B$9:$B$609)*10000hat folgende Bedeutung. In den Zellen B23 und C23 stehen die Ober und Intergrenzen des Integrals. Der folgende Text
"Ser"
bewirkt dass im Integral gleich die Bewertung als Erythem erfolgt.
in dem Bereich '80041106 OH M 3URO 160 R 06'!$A$9:$A$609
stehen die Wellenlängen und in
'80041106 OH M 3URO 160 R 06'!$B$9:$B$609
die zugehörigen Messwerte des zu integrierenden Spektrums.
der Faktor *10000
kommt daher, dass die Spektralwerte in mW/cm=Integ(B23;C23;'80041106'!$A$9:$A$609;'80041106'!$B$9:$B$609;Wirk!B16:DA16;Wirk!B17:DA17)*10000Der Unterschied ist, dass jetzt nicht zu jedem Messwert der
"Ser"
-Wert hinzugerechnet wird, sondern die tabellenbasierte
Erythemfunktion im Bereich Wirk!B16:DA16;Wirk!B17:DA17
mittels Interpolation dazumultipliziert wird.
Im Ergebnis gibt es ganz geringfügige Unterschiede. Die erste Methode ist prinzipiell genauer und praktischer in der Umsetzung.
In Abbildung Man kann beliebig viele Spektren aneinanderreihen und die werden alle durchmultipliziert und integriert. Man spart sich damit eine Menge Platz, da die Messwerte nicht mehr kopiert werden müssen und das leidige Problem mit nicht aufeinander liegenden Stützstellen taucht auch nicht mehr auf. Hier noch der komlette Quelltext:
1 Attribute VB_Name = "Integrale_VBA_excel" 2 Option Explicit 3 Public Function Integ(ParamArray inranges() As Variant) As Double 4 Dim Ncell As Range, x As Range, y As Range 5 Dim Spektren() As Variant, Spektrum() As Variant, Multipliziert() As Variant 6 Dim Untergrenze As Double, Obergrenze As Double 7 Dim i As Long, j As Long, F As Long, imin As Long 8 Dim Wirkungsfunktion As String 9 Wirkungsfunktion = "" 10 imin = LBound(inranges) 11 '************ Hier werden die geprüft ob die ersten beiden Parameter Untergrenze oder Obergrenze sind **************** 12 Untergrenze = 0: Obergrenze = 0 13 If IsNumeric(inranges(0)) And IsNumeric(inranges(1)) Then 14 If inranges(1) > inranges(0) Then 15 Untergrenze = inranges(0): Obergrenze = inranges(1) 16 ElseIf inranges(1) < inranges(0) Then 17 Untergrenze = inranges(1): Obergrenze = inranges(0) 18 End If 19 imin = imin + 2 ' Die weiteren Parameter sind dann die Spektren, wir zählen sie deshalb statt von Null von zwei ab. 20 End If 21 '************ Hier werden die geprüft ob der anstehende Parameter ein Schlüsselwort ist **************** 22 If VarType(inranges(imin)) = vbString Then 23 Wirkungsfunktion = inranges(imin) 24 imin = imin + 1 25 End If 26 '************ Hier werden die Anzahle der verbliebenen Bereiche geprüft ob sie paarweise angegeben wurden. **************** 27 If (UBound(inranges) - imin) Mod 2 = 0 Then MsgBox "Bereiche für xy-Paarbildung immer paarweise (und jeweils gleich groß) angeben!" & vbCrLf & "Berechnung abgebrochen.": Exit Function 28 '************ Hier werden die Bereichsgrößen geprüft **************** 29 For i = imin To UBound(inranges) Step 2 30 If inranges(i).Count <> inranges(i + 1).Count Then MsgBox "Bereichepaar Nr. " & i + 1 & " unterschiedlich groß !" & vbCrLf & "( " & inranges(i).Address & " hat weniger Elemente als " & inranges(i + 1).Address & " )" & vbCrLf & "xy Paarbildung unmöglich." & vbCrLf & "Berechnung abgebrochen.": Exit Function 31 Next 32 '************ Hier werden die Einträge geprüft, ob sie alle Numerisch sind**************** 33 For i = imin To UBound(inranges) 34 For Each Ncell In inranges(i) 35 If Not IsNumeric(Ncell) Then MsgBox "Nichtnumerisch in Zelle" & Ncell.Address & " !": Exit Function 36 Next Ncell 37 Next i 38 '************ Jetzt erst werden die Werte eingelesen **************** 39 ReDim Spektren((UBound(inranges) - imin + 1) / 2) 40 'ReDim Spektren(((UBound(inranges) - imin) + 1) / 2 - 1) 41 For i = imin To UBound(inranges) Step 2 42 ReDim Spektrum(1, 0): j = 1 ' j=1 Markiert, dass Spektrum(1, 0) noch nicht beschrieben ist 43 Set x = inranges(i): Set y = inranges(i + 1) 44 For F = 1 To x.Count 45 If Not CStr(x(F)) = "" And Not CStr(y(F)) = "" Then ' x und y dürfen nicht leer sein und werden sonst übersprungen. 46 If j = 0 Then 47 ReDim Preserve Spektrum(1, UBound(Spektrum, 2) + 1) 48 End If 49 j = 0 ' wird jetzt auf Null gesetzt damit anschließend das Array erweitert wird 50 Spektrum(0, UBound(Spektrum, 2)) = x(F): Spektrum(1, UBound(Spektrum, 2)) = y(F) 51 End If 52 Next F 53 Set x = Nothing: Set y = Nothing 54 Spektren((i - imin) / 2) = Spektrum 55 Next i 56 Erase Spektrum ' brauchen wir nicht mehr 57 '************ Spektren Sortieren *************** 58 For i = LBound(Spektren) To UBound(Spektren) - 1 59 Call SpektrenQuickSort(Spektren(i), LBound(Spektren(i), 2), UBound(Spektren(i), 2)) 60 Next i 61 '************ Grenzen herausfinden *************** 62 If Untergrenze = 0 And Obergrenze = 0 Then ' Dann wurden keine sinnvollen Werte angegeben 63 Untergrenze = Spektren(LBound(Spektren))(0, LBound(Spektren(LBound(Spektren)), 2)) ' Untergrenze von erstem Spektrum 64 Obergrenze = Spektren(LBound(Spektren))(0, UBound(Spektren(LBound(Spektren)), 2)) ' Obergrenze von erstem Spektrum 65 Else 66 Untergrenze = IIf(Spektren(LBound(Spektren))(0, LBound(Spektren(LBound(Spektren)), 2)) > Untergrenze, Spektren(LBound(Spektren))(0, LBound(Spektren(LBound(Spektren)), 2)), Untergrenze) 67 Obergrenze = IIf(Spektren(LBound(Spektren))(0, UBound(Spektren(LBound(Spektren)), 2)) < Obergrenze, Spektren(LBound(Spektren))(0, UBound(Spektren(LBound(Spektren)), 2)), Obergrenze) 68 End If 69 For i = LBound(Spektren) + 1 To UBound(Spektren) - 1 70 Untergrenze = IIf(Untergrenze > Spektren(i)(0, LBound(Spektren(i), 2)), Untergrenze, Spektren(i)(0, LBound(Spektren(i), 2))) 71 Obergrenze = IIf(Obergrenze < Spektren(i)(0, UBound(Spektren(i), 2)), Obergrenze, Spektren(i)(0, UBound(Spektren(i), 2))) 72 Next i 73 ''Debug.Print Untergrenze, ">>>", Obergrenze 74 '************ Jetzt werden die Spektren durchmultipliziert **************** 75 ReDim Multipliziert(1, 1): Multipliziert(0, 0) = Untergrenze: Multipliziert(1, 0) = 1: Multipliziert(0, 1) = Obergrenze: Multipliziert(1, 1) = 1 'Erst mal ein Element Multipliziert auf Untergrenze setzen 76 For i = 0 To UBound(Spektren) - 1 ' Über alle Spektren 77 Multipliziert = Durchmultiplizieren(Multipliziert, Spektren(i)) 78 ''Debug.Print "Multipliziert: "; UBound(Multipliziert, 2) 79 'Call PrintSpektren(Multipliziert) 80 Next i 81 'Call SpektrenQuickSort(Multipliziert, LBound(Multipliziert, 2), UBound(Multipliziert, 2) - 0) 82 '************ Integration **************** 83 Integ = 0 84 Select Case Wirkungsfunktion 85 Case "Ser" 86 For F = LBound(Multipliziert, 2) To UBound(Multipliziert, 2) - 1 87 Integ = Integ + 0.5 * (Multipliziert(1, F + 1) * Ser(Multipliziert(0, F + 1)) + Multipliziert(1, F) * Ser(Multipliziert(0, F))) * (Multipliziert(0, F + 1) - Multipliziert(0, F)) 88 Next F 89 Case Else 90 For F = LBound(Multipliziert, 2) To UBound(Multipliziert, 2) - 1 91 Integ = Integ + 0.5 * (Multipliziert(1, F + 1) + Multipliziert(1, F)) * (Multipliziert(0, F + 1) - Multipliziert(0, F)) 92 Next F 93 End Select 94 Erase Spektren, Multipliziert 95 End Function 96 Public Function Durchmultiplizieren(ByRef U As Variant, ByRef V As Variant) As Variant() 97 Dim F() As Variant: ReDim F(1, 0) 98 Dim i As Long, j As Long: i = 0: j = 0 99 Do While i < UBound(V, 2) And j < UBound(U, 2) 100 If V(0, i) >= U(0, j + 1) Then j = j + 1: GoTo ContinueLoop 101 If U(0, j) >= V(0, i + 1) Then i = i + 1: GoTo ContinueLoop 102 If U(0, j) = V(0, i) Then 103 If Not IsEmpty(F(1, UBound(F, 2))) Then ReDim Preserve F(1, UBound(F, 2) + 1) 104 F(0, UBound(F, 2)) = V(0, i) 105 F(1, UBound(F, 2)) = U(1, j) * V(1, i) 106 'Debug.Print i; j, F(0, UBound(F, 2)); F(1, UBound(F, 2)); "= "; U(1, j); "*"; V(1, i) 107 GoTo Weiter 108 End If 109 If U(0, j) < V(0, i) Then 110 If Not IsEmpty(F(1, UBound(F, 2))) Then ReDim Preserve F(1, UBound(F, 2) + 1) 111 F(0, UBound(F, 2)) = V(0, i) 112 F(1, UBound(F, 2)) = (U(1, j) + (U(1, j + 1) - U(1, j)) / (U(0, j + 1) - U(0, j)) * (V(0, i) - U(0, j))) * V(1, i) 113 'Debug.Print i; j, F(0, UBound(F, 2)); F(1, UBound(F, 2)); "= ("; U(1, j); "+("; U(1, j + 1); "-"; U(1, j); ")/("; U(0, j + 1); "-"; U(0, j); ")*("; V(0, i); "-"; U(0, j); "))*"; V(1, i) 114 GoTo Weiter 115 End If 116 If U(0, j) > V(0, i) Then 117 If Not IsEmpty(F(1, UBound(F, 2))) Then ReDim Preserve F(1, UBound(F, 2) + 1) 118 F(0, UBound(F, 2)) = U(0, j) 119 F(1, UBound(F, 2)) = (V(1, i) + (V(1, i + 1) - V(1, i)) / (V(0, i + 1) - V(0, i)) * (U(0, j) - V(0, i))) * U(1, j) 120 'Debug.Print i; j, F(0, UBound(F, 2)); F(1, UBound(F, 2)); "= ("; V(1, i); "+("; V(1, i + 1); "-"; V(1, i); ")/("; V(0, i + 1); "-"; V(0, i); ")*("; U(0, j); "-"; V(0, i); "))*"; U(1, j) 121 GoTo Weiter 122 End If 123 Weiter: 124 If V(0, i + 1) = U(0, j + 1) Then i = i + 1: j = j + 1: GoTo ContinueLoop 125 If V(0, i + 1) < U(0, j + 1) Then i = i + 1: GoTo ContinueLoop 126 If V(0, i + 1) > U(0, j + 1) Then j = j + 1: GoTo ContinueLoop 127 ContinueLoop: 128 Loop 129 '***************letztes Element****************** 130 If j = UBound(U, 2) Then 131 i = IIf(i = 0, 1, i) 132 'Debug.Print ; ; , V(0, i); (U(1, j - 1) + (U(1, j) - U(1, j - 1)) / (U(0, j) - U(0, j - 1)) * (V(0, i) - U(0, j - 1))) * V(1, i); 133 'Debug.Print "= ("; U(1, j - 1); "+("; U(1, j); "-"; U(1, j - 1); ")/("; U(0, j); "-"; U(0, j - 1); ")*("; V(0, i); "-"; U(0, j - 1); "))*"; V(1, i) 134 If Not IsEmpty(F(1, UBound(F, 2))) Then ReDim Preserve F(1, UBound(F, 2) + 1) 135 F(0, UBound(F, 2)) = U(0, j) 136 F(1, UBound(F, 2)) = (V(1, i - 1) + (V(1, i) - V(1, i - 1)) / (V(0, i) - V(0, i - 1)) * (U(0, j) - V(0, i - 1))) * U(1, j) 137 'Debug.Print "X" 138 ElseIf i = UBound(V, 2) Then 139 j = IIf(j = 0, 1, j) 140 'Debug.Print ; ; , V(0, i); (U(1, j - 1) + (U(1, j) - U(1, j - 1)) / (U(0, j) - U(0, j - 1)) * (V(0, i) - U(0, j - 1))) * V(1, i); 141 'Debug.Print "= ("; U(1, j - 1); "+("; U(1, j); "-"; U(1, j - 1); ")/("; U(0, j); "-"; U(0, j - 1); ")*("; V(0, i); "-"; U(0, j - 1); "))*"; V(1, i) 142 If Not IsEmpty(F(1, UBound(F, 2))) Then ReDim Preserve F(1, UBound(F, 2) + 1) 143 F(0, UBound(F, 2)) = V(0, i) 144 F(1, UBound(F, 2)) = (U(1, j - 1) + (U(1, j) - U(1, j - 1)) / (U(0, j) - U(0, j - 1)) * (V(0, i) - U(0, j - 1))) * V(1, i) 145 End If 146 Durchmultiplizieren = F 147 End Function 148 Private Sub SpektrenQuickSort(ByRef ArrayToSort As Variant, ByVal Low As Long, ByVal High As Long) 149 Dim vPartition As Variant, vTemp As Variant, vTempwith As Variant, i As Long, j As Long 150 If Low > High Then Exit Sub ' Rekursions-Abbruchbedingung 151 vPartition = ArrayToSort(0, (Low + High) \ 2) 152 i = Low: j = High 153 Do 154 Do While ArrayToSort(0, i) < vPartition 155 i = i + 1 156 Loop 157 Do While ArrayToSort(0, j) > vPartition 158 j = j - 1 159 Loop 160 If i <= j Then 161 vTemp = ArrayToSort(0, j): vTempwith = ArrayToSort(1, j) 162 ArrayToSort(0, j) = ArrayToSort(0, i): ArrayToSort(1, j) = ArrayToSort(1, i) 163 ArrayToSort(0, i) = vTemp: ArrayToSort(1, i) = vTempwith 164 i = i + 1 165 j = j - 1 166 End If 167 Loop Until i > j 168 If (j - Low) < (High - i) Then 169 SpektrenQuickSort ArrayToSort, Low, j 170 SpektrenQuickSort ArrayToSort, i, High 171 Else 172 SpektrenQuickSort ArrayToSort, i, High 173 SpektrenQuickSort ArrayToSort, Low, j 174 End If 175 End Sub 176 Function Ser(x) 177 If x <= 298 Then 178 Ser = 1# 179 ElseIf x <= 328 Then 180 Ser = 10 ^ (0.094 * (298# - x)) 181 ElseIf x <= 400 Then 182 Ser = 10 ^ (0.015 * (140# - x)) 183 ElseIf x > 400 Then 184 Ser = 0# 185 End If 186 'Definition aus DIN 5050 Teil 1: 187 'ser = 1 für lambda <= 298 nm 188 'ser = 10^(0,094*(298-lambda)) für 298 nm < lambda <= 328 nm 189 'ser = 10^(0,015*(140-lambda)) für 328 nm < lambda <= 400 nm 190 End Function 191 Sub PrintSpektren(Spektren As Variant) 192 Dim i As Long 193 For i = 1 To UBound(Spektren, 2) 194 Debug.Print i, Spektren(0, i), Spektren(1, i) 195 Next i 196 End Sub 197 198 |