napisał: Cyberek postów: 11
umieszczony: 22 czerwca 2006 11:43
|
|
Wciąż mam problem.
y=(2/pi)*calka_od_zera_do_nieskonczonosci[(x*Z''(x)-w*Z''(w))/(x^2-w^2) dx]
Sposób w jaki to liczę:
Function rr_r(input_col As Range, output_col As Range, Zjw As Double, w As Double) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer, Zjx As Double, Zjxa As Double, Zjxb As Double, calka As Double, a As Double, b As Double, n As Integer
Const Pi As Double = 3.14159265358979
a = 0#
b = 1000000000#
n = 1000
rr_r = 0#
calka = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
Zjx = cubic_spline(input_col, output_col, x)
Zjxa = cubic_spline(input_col, output_col, x + delta)
Zjxb = cubic_spline(input_col, output_col, x + 2 * delta)
wyraz = yr(Zjw, Zjx, w, x) + 4 * yr(Zjw, Zjxa, w, x + delta) + yr(Zjw, Zjxb, w, x + 2 * delta)
calka = calka + wyraz
x = x + 2 * delta
Next i
rr_r = ((2 / Pi) * calka) * delta / 3
End Function
Function yr(Zjw As Double, Zjx As Double, w As Double, x As Double) As Double
yr = (x * Zjx - w * Zjw) / (x ^ 2 - w ^ 2)
End Function
Moje pytanie brzmi: czy gdzieś w tym kodzie jest błąd.
Wyjaśnienie symboli:
x - zmienna po któej całkujemy,
w - częstotliwość brana z serii pomiarowej
Z''(x) - wartosc urojona impedancji zespolonej dla punktu x wyliczana metodą interpolacji: Cublic Spline (funkcja rowniez napisana w VBA - dziala prawidlowo)
Z''(w) - wartosc urojona impedancji zespolonej dla czestotliwosci w (z serii pomiarowej)
Odnocze wrazenie, iz gdzies popelnilem banalny blad gdyz wartosci wynikowe troszke roznia sie od tych, jakich oczekuje. |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 19:19
|
|
Ok. Wlasnie brakowalo mi wiedzy jak bezposrednio zdebugowac dzialanie wszystkich funkcji.
Rozumiem ze sugerujesz ze gdzies pomylilem sie przy definicji funkcji. Pozniej jeszcze raz ja przejze (ale jesli chodzi Ci o to ze brakuje 2/pi oraz const na koncu - to beda one dodane juz w arkuszu gdyz nie znajduja sie one "pod całką") |
|
napisał: admin postów: 613
umieszczony: 18 czerwca 2006 19:07
|
|
Wstaw do któregokolwiek modułu kod:
Sub Wypisz()
MsgBox rr_r(0.1, 1000000, 1000, Range("B2:B63"), Range("D2:D63"), -43.631, 0.1)
End Sub
Jeśli uruchomisz tę funkcję w edytorze VBA to zobaczysz, że przyczyną błędu jest dzielenie przez 0 w funkcji yr.
Musisz zabezpieczyć tę funkcję przed wystapieniem tego błędu.
I taka uwaga natury ogólnej...
Pamiętaj, ze poprawne wyniki otrzymasz tylko wówczas, gdy funkcje będą napisane poprawnie, to znaczy będą realizowały założony przez Ciebie algorytm.
Powodzenia:) |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 15:53
|
|
Update.2
Zmienilem funkcje na:
Function rr_r(a As Double, b As Double, n As Integer, input_col As Range, output_col As Range, Zjw As Double, w As Double) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer, Zjx As Double, calka As Double
rr_r = 0#
calka = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
Zjx = cubic_spline(input_col, output_col, x)
wyraz = yr(Zjw, Zjx, w, x) + 4 * yr(Zjw, Zjx, w, x + delta) + yr(Zjw, Zjx, w, x + 2 * delta)
calka = calka + wyraz
x = x + 2 * delta
Next i
rr_r = calka * delta / 3
End Function
Poprawiłem też w funkcji cubic_spline wartosc wejsciowa x z Range na Double by nie miec problemu z zgodnoscia typow. Teraz dostaje tylko blad:
#ARG!.
Aktualna wersja:
http://redrose.lap.pl/kk-transformata4.xls |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 15:32
|
|
Update.1
Błąd nazwy zaistaniał w wyniku nazwania modułu tak samo jak funkcji wewnątrz.
Poprawiony xls pod adresem:
http://redrose.lap.pl/kk-transformata3.xls
Teraz już nie jest błędem nazwa funkcji a właśnie rekurencja.
Czy ktoś może pomóc z problemem zasugerowanym przez admina w Uwadze trzeciej? |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 15:17
|
|
Wywołanie funkcji faktycznie było złe w arkuszu, poprawiłem ale to i tak kończe z tym samym błędem #NAZWA?
Błędne działanie funkcji yr również poprawiłem.
Natomiast nie rozumiem w czym tkwi problem z rekurencją. W wcześniejszych przykładach była ona wykonywana dokładnie w ten sam sposób:
tutaj kod z postu Rycha data: 06.06.2006 01:01:01:
Function Integral(F As String, a As Double, b As Double, n As Integer) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer
Integral = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
wyraz = y(F, x) + 4 * y(F, x + delta) + y(F, x + 2 * delta)
Integral = Integral + wyraz
x = x + 2 * delta
Next i
Integral = Integral * delta / 3
End Function
Wygląda na to, iż w tym kodzie jest popełniany dokładnie ten sam błąd (rekurencja bez parametrów).
Niestety nie jestem zbyt biegły w VBA i jedyne co mogę zrobić to przeanalizować jakiś podobny kod do problemu który potrzebuję rozwiązać i zmodyfikować go do swoich potrzeb. Niestety tutaj nadal jestem w polu ;).
Adres do poprawionego arkusza:
http://redrose.lap.pl/kk-transformata2.xls
Mam nadzieje ze w niedlugim czasie z Wasza pomoca bede w stanie zrozumiec gdzie nadal tkwi błąd. |
|
napisał: admin postów: 613
umieszczony: 18 czerwca 2006 13:50
|
|
Cytat:
Oj znielubicie mnie za pisanie zbyt często. Otóż trochę powalczyłem i nic mi nie wyszło.
Nie, wręcz przeciwnie:)
Wywołujesz funkcję tak:
=rreal(J2;J3;J1;B2:B63;D2:D63;D2;B2)
Niestety w projekcie VBA zwiazanym z tym arkuszem nie ma takiej funkcji.
Jest za to funcja rr_r. Powinieś napisać ww. formułę tak:
=rr_r(J2;J3;J1;B2:B63;D2:D63;D2;B2)
Uwaga trzecia:
Wiesz co robisz używając rekurencji w kodzie tej funkcji?
Function rr_r(a As Double, b As Double, n As Integer, input_col As Range, output_col As Range, Zjw As Double, w As Double) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer
rr_r = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
Zjx = cubic_spline(input_col, output_col, x)
wyraz = yr(Zjw, Zjx, w, x) + 4 * yr(Zjw, Zjx, w, x + delta) + yr(Zjw, Zjx, w, x + 2 * delta)
'w poniższej linii masz wywołanie rekurencyjne funkcji rr_r, ale ono
'nie zadziała, bo nie podałeś argumentów dla funcji rr_r!!!!!
rr_r = rr_r + wyraz
x = x + 2 * delta
Next i
'w poniższej linii masz wywołanie rekurencyjne funkcji rr_r, ale ono
'nie zadziała, bo nie podałeś argumentów dla funcji rr_r!!!!!
rr_r = rr_r * delta / 3
End Function
Trzeci błąd:
Funkcja rr_r wykorystuje funkcję yr.
Oto kod tej funkcji:
Function yr(Zjw As Double, Zjx As Double, w As Double, x As Double) As Double
y = (x * Zjx - w * Zjw) / (x ^ 2 - w ^ 2)
End Function
Niestety to nie bedzie działać, bo nie ma tutaj zwracania wartości funkcji.
Może tak:
Function yr(Zjw As Double, Zjx As Double, w As Double, x As Double) As Double
yr = (x * Zjx - w * Zjw) / (x ^ 2 - w ^ 2)
End Function |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 13:14
|
|
Update2.
Oj znielubicie mnie za pisanie zbyt często. Otóż trochę powalczyłem i nic mi nie wyszło.
Napisałem funkcje:
Function yr(Zjw As Double, Zjx As Double, w As Double, x As Double) As Double
y = (x * Zjx - w * Zjw) / (x ^ 2 - w ^ 2)
End Function
Function rr_r(a As Double, b As Double, n As Integer, input_col As Range, output_col As Range, Zjw As Double, w As Double) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer
rr_r = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
Zjx = cubic_spline(input_col, output_col, x)
wyraz = yr(Zjw, Zjx, w, x) + 4 * yr(Zjw, Zjx, w, x + delta) + yr(Zjw, Zjx, w, x + 2 * delta)
rr_r = rr_r + wyraz
x = x + 2 * delta
Next i
rr_r = rr_r * delta / 3
End Function
do jej wywolania podaje: dolny zakres calkowania, gorny zakres calkowania, liczbe krokow, serie x'ow dla funkcji cubic_spline, serie y'kow dla funkcji cubic spline, wartosc impedancji urojonej w czestotliwosci dla ktorej licze wartosc rzeczywista, wartosc owej czestotliwosci
Niestety dostaje blad #NAZWA? przy probie zastosowania w/w funkcji w arkuszu.
Ponizej link do arkusza demonstrujacego problem:
http://redrose.lap.pl/kk-transformata.xls
Pozdrawiam i przepraszam za spamiemienie... ale problem musze rozwiazac na dniach. |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 12:13
|
|
Update. Wklejony nize jkod funkcji cubic_spline dziala gdy dane sa posortowane rosnaco. |
|
napisał: Cyberek postów: 11
umieszczony: 18 czerwca 2006 01:24
|
|
Chciałbym trochę rozwinąć problem.
Mam serię danych X oraz Y będących wynikami pomiaru.
Dla tej serii danych wykonuję funkcję dostępną w postaci pluginu (plik .xll): Cubic Spline. Funkcja ta jest wywolywana:
Spline(A,B,C,D,E), gdzie A i B okresla zakres danych X'ów; C,D - zkres Yków, E - dowolny (z zakresu A,B) X dla ktorego funkcja oblicza Y.
(Na końcu zamieszczam znaleziony kod tej funkcji w postaci VBA)
Wykonaniue funkcji Spline jest niezbędne do całkowania po dowolnych wartościach (dowolnym zakresie/dowolnych x'ach) nastepujacych funkcji:
A=[(2/PI)*calka_w_zakresie( (x*Z''(x)-w*Z''(w)) / (x^2-w^2) dx]+stala
B=-(2*w/PI)*calka_w_zakresie( (Z'(x)-Z'(w) / (x^2-w^2) )dx
Przy czym:
- zakres calkowania determinuje jakie otrzymamy x'y (dla ktorych wyliczamy odpowiednie wartosci opisane ponizej przy pomocy Spline)
- Z'(x) (oraz Z''(x)) jest wartoscia otrzymana z funkcji Spline dla danego x'a
- Z'(w) (oraz Z'' (w)) jest wartością w danym punkcie w z początkowej serii danych (z których później obliczany wartosci Z' i Z'' dla dowolnego (a nie tylko danego z pomiarow) punktu x).
- stala = dana liczba wprowadzana do funkcji z arkusza
Funkcje podcalkowe nie ulegaja zmianie, zatem moga byc zaimplementowane wewnatrz modulu VBA.
Czy zgodnie z powyższymi danymi któryś z programistów VBA mógłby zmodyfikować dla mnie powyższy kod całkowania metodą simpsona?
Pozdrawiam i z góry dziękuję za pomoc.
Wspomniana powyzej kod VBA funkcji Spline:
'******************** Cubic_Spline by SRS1 Software ****************
'
'
' Version 1.01
Function cubic_spline(input_column As Range, _
output_column As Range, _
x As Range)
'Purpose: Given a data set consisting of a list of x values
' and y values, this function will smoothly interpolate
' a resulting output (y) value from a given input (x) value
' This counts how many points are in "input" and "output" set of data
Dim input_count As Integer
Dim output_count As Integer
input_count = input_column.Rows.Count
output_count = output_column.Rows.Count
' Next check to be sure that "input" # points = "output" # points
If input_count <> output_count Then
cubic_spline = "Something's messed up! The number of indeces number of output_columnues don't match!"
GoTo out
End If
ReDim xin(input_count) As Single
ReDim yin(input_count) As Single
Dim c As Integer
For c = 1 To input_count
xin(c) = input_column(c)
yin(c) = output_column(c)
Next c
'''''''''''''''''''''''''''''''''''''''
' values are populated
'''''''''''''''''''''''''''''''''''''''
Dim n As Integer 'n=input_count
Dim i, k As Integer 'these are loop counting integers
Dim p, qn, sig, un As Single
ReDim u(input_count - 1) As Single
ReDim yt(input_count) As Single 'these are the 2nd deriv values
n = input_count
yt(1) = 0
u(1) = 0
For i = 2 To n - 1
sig = (xin(i) - xin(i - 1)) / (xin(i + 1) - xin(i - 1))
p = sig * yt(i - 1) + 2
yt(i) = (sig - 1) / p
u(i) = (yin(i + 1) - yin(i)) / (xin(i + 1) - xin(i)) - (yin(i) - yin(i - 1)) / (xin(i) - xin(i - 1))
u(i) = (6 * u(i) / (xin(i + 1) - xin(i - 1)) - sig * u(i - 1)) / p
Next i
qn = 0
un = 0
yt(n) = (un - qn * u(n - 1)) / (qn * yt(n - 1) + 1)
For k = n - 1 To 1 Step -1
yt(k) = yt(k) * yt(k + 1) + u(k)
Next k
''''''''''''''''''''
'now eval spline at one point
'''''''''''''''''''''
Dim klo, khi As Integer
Dim h, b, a As Single
' first find correct interval
klo = 1
khi = n
Do
k = khi - klo
If xin(k) > x Then
khi = k
Else
klo = k
End If
k = khi - klo
Loop While k > 1
h = xin(khi) - xin(klo)
a = (xin(khi) - x) / h
b = (x - xin(klo)) / h
y = a * yin(klo) + b * yin(khi) + ((a ^ 3 - a) * yt(klo) + (b ^ 3 - b) * yt(khi)) * (h ^ 2) / 6
cubic_spline = y
out:
End Function |
|
napisał: Rycho postów: 291
umieszczony: 7 czerwca 2006 01:13
|
|
Sub test()
Dim w As Double, w1 As Double
w = y1("x*y", 2, 3)
w = Cos(0.5) * Exp(0.7)
w1 = y1("cos(x)*exp(y)", 0.5, 0.7)
End Sub
Function y1(funkcja As String, x As Double, y As Double) As Double
Dim xF As String
If InStr(1, funkcja, "exp") > 0 Then
xF = Replace(funkcja, "exp", "egze_begze")
xF = Replace(Replace(xF, "x", _
Replace(x, ",", ".")), "y", Replace(y, ",", "."))
y1 = Evaluate(Replace(xF, "egze_begze", "exp"))
Else
y1 = Evaluate(Replace(Replace(funkcja, "x", _
Replace(x, ",", ".")), "y", Replace(y, ",", ".")))
End If
End Function |
|
napisał: th3rion postów: 6
umieszczony: 6 czerwca 2006 14:15
|
|
A dajmy na to jesli chcialbym zrozniczkowac funkcje? Nie chodzi mi o to jak napisac kod do rozniczkowania tylko, jak sie zmieni kod do zamiany funkcji dla 2 zmiennych, na przyklad dla funkcji y'=x*y |
|
napisał: th3rion postów: 6
umieszczony: 6 czerwca 2006 07:53
|
|
Bardzo dziekuje za pomoc. Artik i Rycho |
|
napisał: Rycho postów: 291
umieszczony: 6 czerwca 2006 01:01
|
|
Hej.
Odrobinę bym to zmienił.
Kod do modułu:
Function y(funkcja As String, x As Double) As Double
Dim xF As String
If InStr(1, funkcja, "exp") > 0 Then
xF = Replace(funkcja, "exp", "egze_begze")
xF = Replace(xF, "x", Replace(x, ",", "."))
xF = Replace(xF, "egze_begze", "exp")
y = Evaluate(xF)
Else
y = Evaluate(Replace(funkcja, "x", Replace(x, ",", ".")))
End If
End Function
Function Integral(F As String, a As Double, b As Double, n As Integer) As Double
Dim delta As Double, x As Double, wyraz As Double, i As Integer
Integral = 0#
delta = (b - a) / n
x = a
For i = 1 To n Step 2
wyraz = y(F, x) + 4 * y(F, x + delta) + y(F, x + 2 * delta)
Integral = Integral + wyraz
x = x + 2 * delta
Next i
Integral = Integral * delta / 3
End Function
Wykorzystanie w VBA:
Sub test()
Dim a As Double, pole As Double, P1 As Double
P1 = WorksheetFunction.pi()
'wartość funkcji dla Pi
a = y("x*SIN(x)", P1)
'pole powierzchni
pole = Integral("x*sin(x)", 0, P1, 100)
End Sub
Wykorzystanie bezpośrednio w arkuszu jako funkcji użytkownika:
A1 x*sin(x)
A2 0
A3 =PI()
A4 100
A5 =Integral(A1;A2;A3;A4)
lub
=Integral("x*sin(x)";0;Pi();100)
Rycho |
|
napisał: th3rion postów: 6
umieszczony: 5 czerwca 2006 23:54
|
|
Hmm ja sie dopiero ucze i nie bardzo wiem jak to poskladac wszystko do kupy, to co napisal Rycho, zeby to dzialalo. Chcialbym wiedziec bo moze sie kiedys przyda :/ |
|
napisał: Rycho postów: 291
umieszczony: 5 czerwca 2006 23:20
|
|
Witaj.
To nie tak :) Wpukanie tego kodu to faktycznie kilkanaście sekund ale siedziałem nad nim z półtorej godziny. :(
Jeszcze poprawka bo dla podstawowej funcji ten kod nie działa.
Function y(funkcja As String, x As Double) As Double
Dim xF As String
If InStr(1, funkcja, "exp") > 0 Then
xF = Replace(funkcja, "exp", "egze_begze")
xF = Replace(xF, "x", Replace(x, ",", "."))
xF = Replace(xF, "egze_begze", "exp")
y = Evaluate(xF)
Else
y = Evaluate(Replace(funkcja, "x", Replace(x, ",", ".")))
End If
End Function |
|
napisał: Rycho postów: 291
umieszczony: 5 czerwca 2006 01:54
|
|
Witam.
Też mnie to męczyło i wykombinowalem coś takiego:
Sub test()
Dim a As Double
a = y("x*SIN(x)", 1.43)
End Sub
Function y(funkcja As String, x As Double) As Double
y = Evaluate(Replace(funkcja, "x", Replace(x, ",", ".")))
End Function |
|
napisał: th3rion postów: 6
umieszczony: 4 czerwca 2006 23:48
|
|
Heh dziala wspaniale o to chodzilo. Dziekuje bardzo. Zeby tylko antywir nie szalal przy zapisywaniu byloby wogole wspaniale :) ale to juz mniejsza z tym. |
|
napisał: th3rion postów: 6
umieszczony: 31 maja 2006 00:48
|
|
Nie da sie tego zrobic za pomoca Cell lub Value. Prawde mowiac nie wiem jak sie do tego zabrac. Prosze o pomoc. |
|
wszystkich stron: 2
|
|