Related
I have a function T which I'm wanting to maximise:
T = (B((A + 1.646) + 0.583 w) + 311)((1 + ((R + 0.553) + 0.0389 x)((D) + 0.0389 y)
with the constraints
w + x + y + z = 25
w >= 0
x >= 0
y >= 0
z >= 0
B, A, R, D are all constants.
How would I go about doing this?
I am a beginner in VB. I wrote a little program to simulate dosing regimens of antibiotics using some exponential equations and pharmacokinetic data.
The problem I have is that I want to display on a graph the following mathematical function:
That simulates the concentration variation at different intervals of time:
Where:
b(t) is the concentration at time t that will be plotted as Y axis, t is time (plotted on the x-axis).
b(0) is the concentration at time 0 and it is a known variable.
u(t-a1) is a function that has the value u(t-a1)=b(o) if t=a1 or 0 if t<>a1
a1 is the time at which a next dose is given.
alpha is the elimination rate constant, a variable that is known.
What I have so far:
Dim y, x As Double
For x = 0 To 24 Step 1
For n As Double = 1 To 24 / tau
y = (1 - test_condition(n * tau, x)) * css * Math.Exp(-ke * x) + test_condition(n * tau, x) * css * Math.Exp(-ke * (x - n * tau))
Chart1.Series("Concentratie1").Points.AddXY(x, y)
Next
Next
The test_condition:
if x=tau then test_condition= 1 else 0
It is close but I don't get an exponential decay after a dose ... don't know how to make that happen.
This works!! for tau (dosing interval) every 4 hours. Can it be rearranged somehow because the tau (dosing interval) will vary (sometimes 4 hours, sometimes every 6 hours)?:
Dim y, x, y2, x2, y3, x3, y4, x4, x5, x6, y5, y6 As Double
For x = 0 To tau Step 1
y = exponential_decay(css, ke, x) + test_condition(tau, x) * (css - Val(mic))
Chart1.Series("Bolus 1").Points.AddXY(x, y)
Next
For x2 = tau To 2 * tau Step 1
y2 = exponential_decay(css, ke, x2 - tau) + test_condition(2 * tau, x2) * (css - Val(mic))
Chart1.Series("Bolus 2").Points.AddXY(x2, y2)
Next
For x3 = 2 * tau To 3 * tau Step 1
y3 = exponential_decay(css, ke, x3 - 2 * tau) + test_condition(3 * tau, x3) * (css - Val(mic))
Chart1.Series("Bolus 3").Points.AddXY(x3, y3)
Next
For x4 = 3 * tau To 4 * tau Step 1
y4 = exponential_decay(css, ke, x4 - 3 * tau) + test_condition(4 * tau, x4) * (css - Val(mic))
Chart1.Series("Bolus 4").Points.AddXY(x4, y4)
Next
For x5 = 4 * tau To 5 * tau Step 1
y5 = exponential_decay(css, ke, x5 - 4 * tau) + test_condition(5 * tau, x5) * (css - Val(mic))
Chart1.Series("Bolus 4").Points.AddXY(x5, y5)
Next
For x6 = 5 * tau To 32 Step 1
y6 = exponential_decay(css, ke, x6 - 5 * tau)
Chart1.Series("Bolus 4").Points.AddXY(x6, y6)
Next
End Sub
I managed to solve the problem:
this function f relates time (t) to dosing interval (tau)
Private Function f(ByVal t As Double, ByVal tau As Double)
Dim n As Integer
For n = 0 To 24 / tau
If t = n * tau Then
f = n * tau
ElseIf t < tau Then
f = 0
ElseIf t > n * tau And t < (n + 1) * tau Then
f = n * tau
ElseIf t >= (n + 1) * tau Then
f = n * tau
End If
Next
End Function
And this is what I draw on the chart:
For x = 0 To 36 Step 0.5
y = exponential_decay(css, ke, x - f(x, tau))
Chart1.Series("Intermitent Dosage").Points.AddXY(x, y)
Next
I have a for loop (the last loop in the code below) which fills some arrays with values through some computations.
However, for some reason, once i=5 it jumps back up to the top of the loop (the x+h part) without going through the rest of the loop.
While x < xmax
If x + h < xmax Then 'If the step is going to overshoot the desired xmax
x = x + h 'make h adequately smalller
Else
h = xmax - x
x = xmax
End If
'k(Order #, equation #)
For j = 1 To 6 'First to 6th order
'temp=riddersmethodT(temp) 'Calculate temperature of mixture
FT = 0
rho(0) = 0 'Setting FT and rho_av to 0 to be re-calculated
For i = 1 To 7
rho(0) = rho(0) + rho(i) * Y4(i) 'Calculate average density of mixture
FT = FT + Y4(i)
vol_F = vol_F + Y4(i) * MW(i) / rho(i) 'Calculating the total volumetric flowrate (m^3/s)
Next i
rho(0) = rho(0) / FT
For i = 1 To 8 'Calculating all of the k(1) values for eq 1 to 8
k(j, i) = AllODES(x, Y4, i, j, k, h, temp, diameter, vol_F, rho(0))
Next i
Next j
For i = 1 To 8
Y4Old(i) = Y4(i) 'Saving old y4 values to calc delta0
Y4(i) = Y4(i) + h * (k(1, i) * (37 / 378) + k(3, i) * (250 / 621) + k(4, i) * (125 / 594) + k(6, i) * (512 / 1771))
Y5(i) = Y4(i) + h * (k(1, i) * (2825 / 27648) + k(3, i) * (18575 / 48384) + k(4, i) * (13525 / 55296) + k(5, i) * (277 / 14336) + k(6, i) * (0.25))
delta0(i) = error
delta1(i) = Abs(Y5(i) - Y4(i))
delRatio(i) = Abs(delta0(i) / delta1(i)) 'Ratio of errors; careful of getting zeroes!
Next i
I don't understand how this can be possible seeing as i is not being manipulated within that loop. If you have any insight, please let me know!
My guess is that your final loop over i has a divide by zero somewhere. You could handle errors in your loop using something like the following:
Sub yourSub()
For i = 1 To 8
On Error GoTo ErrorHandler:
Y4Old(i) = Y4(i)
'Saving old y4 values to calc delta0
Y4(i) = Y4(i) + h * (k(1, i) * (37 / 378) + k(3, i) * (250 / 621) + k(4, i) * (125 / 594) + k(6, i) * (512 / 1771))
Y5(i) = Y4(i) + h * (k(1, i) * (2825 / 27648) + k(3, i) * (18575 / 48384) + k(4, i) * (13525 / 55296) + k(5, i) * (277 / 14336) + k(6, i) * (0.25))
delta0(i) = error
delta1(i) = Abs(Y5(i) - Y4(i))
delRatio(i) = Abs(delta0(i) / delta1(i)
Next i
Cleanup:
' do cleanup here
Exit Sub
ErrorHandler:
' handle error here
Resume Cleanup
End Sub
But it would be best to fix your match which is allowing a division by zero in the first place.
So I have a "main" function (SolveSixODES) that calls a secondary function (AllODEs). And when it does this, the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable.
Here is the code, my inputs I used are as follows:
x=0, xmax=3, y=0-6, h=0.1, error=0.1
Public Function SolveSixODE(x As Double, xmax As Double, Y As Range, h As Double, error As Double) 'Weird bug: You must leave the first y4 value blank
Dim i As Integer, k(7, 7) As Double, j As Integer, m As Integer 'k(Order #, equation #)
Dim Y5(7) As Double, Y4(7) As Double, Y4Old(7) As Double
Dim delta0(7) As Double, delta1(7) As Double, delRatio(7) As Double, Rmin As Double
For i = 1 To 6 'Moving the input data so it can acutally be used
Y4(i) = Y(i)
Next i
While x < xmax
If x + h < xmax Then
x = x + h
Else
h = xmax - x
x = xmax
End If
For j = 1 To 6 'j is the order i is equation number
For i = 1 To 6 'Calculating all of the k(1) values for eq 1 to 6
k(j, i) = AllODES(x, Y4, i, j, k, h) '!!!!!SOME HOW THIS LOOP MAKES X negative...!!!!!!!
Next i
Next j
For i = 1 To 6
Y4Old(i) = Y4(i) 'Saving old y4 value to calc delta0
Y4(i) = Y4(i) + h * (k(1, i) * (37 / 378) + k(3, i) * (250 / 621) + k(4, i) * (125 / 594) + k(6, i) * (512 / 1771))
Y5(i) = Y4(i) + h * (k(1, i) * (2825 / 27648) + k(3, i) * (18575 / 48384) + k(4, i) * (13525 / 55296) + k(5, i) * (277 / 14336) + k(6, i) * (0.25))
delta0(i) = error * (Abs(Y4Old(i)) + Abs(h * AllODES(x, Y4Old, i, 1, k, h))) 'First order because we don't want to use the k vals
delta1(i) = Abs(Y5(i) - Y4(i))
delRatio(i) = Abs(delta0(i) / delta1(i)) 'Ratio of errors
Next i
Rmin = delRatio(1)
For i = 2 To 6
If delRatio(i) < Rmin Then
Rmin = delRatio(i) 'Determine the smallest error ratio
End If
Next i
If Rmin < 1 Then 'If this is true then the step size was too big must repeat step
x = x - h 'Set x and y's back to previous values
For i = 1 To 6
Y4(i) = Y4Old(i)
Next i
h = 0.9 * h * Rmin ^ 0.25 'adjust h value; 0.9 is a safety factor
Else
h = 0.9 * h * Rmin ^ 0.2 'Otherwise, we march on
End If
m = m + 1
Wend
SolveSixODE = Y4
End Function
Public Function AllODES(x As Double, Y() As Double, EqNumber As Integer, order As Integer, k() As Double, h As Double) As Double
Dim conc(7) As Double, i As Integer, j As Integer
If order = 1 Then
x = x - h
For i = 1 To 6 'Movin the data so I can use it
conc(i) = Y(i) 'also adjusting the x and y values for RK4 (Cash Karp values)
Next i
ElseIf order = 2 Then
x = x - h + h * 0.2
For i = 1 To 6
conc(i) = Y(i) + h * k(1, i) * 0.2
Next i
ElseIf order = 3 Then
x = x - h + 0.3 * h
For i = 1 To 6
conc(i) = Y(i) + h * (0.075 * k(1, i) + 0.225 * k(2, i))
Next i
ElseIf order = 4 Then
x = x - h + 0.6 * h
For i = 1 To 6
conc(i) = Y(i) + h * (0.3 * k(1, i) - 0.9 * k(2, i) + 1.2 * k(3, i))
Next i
ElseIf order = 5 Then
x = x - h + h
For i = 1 To 6
conc(i) = Y(i) + h * ((-11 / 54) * k(1, i) + 2.5 * k(2, i) - (70 / 27) * k(3, i) + (35 / 27) * k(4, i))
Next i
ElseIf order = 6 Then
x = x - h + 0.875 * h
For i = 1 To 6
conc(i) = Y(i) + h * ((1631 / 55296) * k(1, i) + (175 / 512) * k(2, i) + (575 / 13824) * k(3, i) + (44275 / (110592) * k(4, i) + (253 / 4096) * k(5, i)))
Next i
Else
MsgBox ("error")
End If
If EqNumber = 1 Then 'These are the actual equations
AllODES = x + Y(1)
ElseIf EqNumber = 2 Then
AllODES = x
ElseIf EqNumber = 3 Then
AllODES = Y(3)
ElseIf EqNumber = 4 Then
AllODES = 2 * x
ElseIf EqNumber = 5 Then
AllODES = 2 * Y(2)
ElseIf EqNumber = 6 Then
AllODES = 3 * x
Else
MsgBox ("You entered an Eq Number that was dumb")
End If
End Function
It's possible that it is something really trivial that I missed but this seems to contradict my knowledge of how variables work. So if you understand how the function is able to manipulate a variable from another function in this case, I would appreciate any advice and/or explanation!
Thanks in advance!
the x value in the main function gets modified. I don't understand how this can be possible, seeing as it is not a global variable
This is normal because you are passing x by reference to the function AllODES and you do change it there. When the keyword ByVal is not explicitly specified in the function/sub prototype, the default passing mechanism is ByRef, that is, by reference.
Public Function AllODES(x As Double, ...
means
Public Function AllODES(ByRef x As Double, ....
We observe that x is manipulated in this function, so the change will appear in the caller. If you want that the change of x does not report back in the caller's scope, pass x by value:
Public Function AllODES(ByVal x As Double, ....
' ^^^^^
Only in this case the x of the caller and the x of the callee will be two different variables.
I'm trying to make a function in Lua or VB based code to
draw / plot an ellipse and also a filled ellipse.
I don't have much knowledge about this math and I can use some help.
I googled everything there is to google about drawing ellipses with code but I can't find a good simple working example that i can code into my Lua / VB code.
here are a few websites i visited but couldn't make the code work or couldn't convert the code to Lua or VB properly...
https://sites.google.com/site/ruslancray/lab/projects/bresenhamscircleellipsedrawingalgorithm/bresenham-s-circle-ellipse-drawing-algorithm
http://groups.csail.mit.edu/graphics/classes/6.837/F98/Lecture6/circle.html
http://www.blitzbasic.com/codearcs/codearcs.php?code=2817
http://hackipedia.org/Algorithms/Graphics/pdf/A%20Fast%20Bresenham%20Type%20Algorithm%20For%20Drawing%20Ellipses%20by%20John%20Kennedy.pdf
https://scratch.mit.edu/projects/49873666/
http://www.sourcecodesworld.com/source/show.asp?ScriptID=112
How do I draw an ellipse with arbitrary orientation pixel by pixel?
Can anyone help me make code that can draw an ellipse and a filled ellipse?
here is some code I tried to convert to Lua from here:
https://gist.github.com/Wollw/3291916
this code has some problems (missing pixels) and I think it's not converted properly but I don't know how to do it otherwise.
function plotEllipseRect(x0, y0, x1, y1)
-- values of diameter
a = math.abs(x1-x0)
b = math.abs(y1-y0)
b1 = 2.5
-- error increment
dx = 4*(1-a)*b*b
dy = 4*(b1+1)*a*a
-- error of 1.step
err = dx+dy+b1*a*a
-- e2 = 0
if (x0 > x1) then -- if called with swapped points
x0 = x1
x1 = x1 + a
end
if (y0 > y1) then -- .. exchange them
y0 = y1
end
-- starting pixel
y0 = y0 + (b+1)/2
y1 = y0-b1
a = a * 8*a
b1 = 8*b*b
repeat
dot(x1, y0) -- I. Quadrant
dot(x0, y0) -- II. Quadrant
dot(x0, y1) -- III. Quadrant
dot(x1, y1) -- IV. Quadrant
e2 = 2*err
if (e2 <= dy) then -- y step
y0 = y0 + 1
y1 = y1 - 1
dy = dy + a
err = err + dy
end
if (e2 >= dx or 2*err > dy) then -- x step
x0 = x0 + 1
x1 = x1 - 1
dx = dx + b1
err = err + dx
end
until (x0 >= x1)
while (y0-y1 < b) do -- too early stop of flat ellipses a=1
dot(x0-1, y0) -- -> finish tip of ellipse
y0 = y0 + 1
dot(x1+1, y0)
dot(x0-1, y1)
y1 = y1 - 1
dot(x1+1, y1)
end
end
[EDIT:]
I almost got it for the filled one!
see the comments in this code below to know what the problem is...
I use EGSL to test this Lua code:
http://www.egsl.retrogamecoding.org//pages/downloads.php
function DrawEllipse(xc,yc,w,h)
local w2 = w * w
local h2 = h * h
local fw2 = 4 * w2
local fh2 = 4 * h2
xc = xc + w
yc = yc + h
local x = 0
local y = h
local s = 2 * h2 + w2 * (1 - h)
while h2 * x <= w2 * y do
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255)) --random color to see changes
if s >= 0 then
s = s + fw2 * (1 - y)
y = y - 1
color(255,0,255)
line(xc + x, yc + y, xc - x, yc + y)
line(xc + x, yc - y, xc - x, yc - y)
end
s = s + h2 * ((4 * x) + 6)
x = x + 1
end
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
line(xc + x, yc + y, xc - x, yc + y) --to prevent the first line to be drawn twice
redraw()
inkey()
s = s + w2 * ((4 * y) + 6)
y = y + 1
while w2 * y < h2 * (x-2) do
line(xc + x, yc + y, xc - x, yc + y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
line(xc + x, yc - y, xc - x, yc - y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
if s >= 0 then
s = s + fh2 * (1 - x)
x = x - 1
end
s = s + w2 * ((4 * y) + 6)
y = y + 1
end
dot(xc + x, yc + y)
dot(xc - x, yc + y)
redraw()
inkey()
color(int(rnd()*255),int(rnd()*255),int(rnd()*255))
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()
inkey()
end
openwindow (70,70,32,"Resize Window")
color(255,255,0)
DrawEllipse(10,10,20,20) --works perfect!
inkey()
cls()
DrawEllipse(10,10,10,20) --problems with last 2 horizontal lines between the pixels!
inkey()
cls()
DrawEllipse(10,10,20,10) --works perfect to!
closewindow()
The following VB works for me, based on the first link provided; the only difference between mine here and the code at your link is I move xc and yc over, since you cannot can't have negative x or y values for the pixels in a bitmap.
Public Shared Function DrawEllipse(ByVal xc As Integer, ByVal yc As Integer, ByVal w As Integer, ByVal h As Integer, ByVal doFill As Boolean) As Drawing.Bitmap
Dim w2 As Integer = w * w
Dim h2 As Integer = h * h
Dim fw2 As Integer = 4 * w2
Dim fh2 As Integer = 4 * h2
// cheat by moving xc and yc so that we can handle quadrants
xc = w
yc = h
Dim bm As New Drawing.Bitmap(w2, h2)
// first half
Dim x As Integer = 0
Dim y As Integer = h
Dim s As Integer = 2 * h2 + w2 * (1 - h)
While h2 * x <= w2 * y
If doFill Then
For i As Integer = -y To y
bm.SetPixel(xc + x, yc + i, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + i, Drawing.Color.Red)
Next
Else
bm.SetPixel(xc + x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + x, yc - y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc - y, Drawing.Color.Red)
End If
If s >= 0 Then
s += fw2 * (1 - y)
y -= 1
End If
s += h2 * ((4 * x) + 6)
x += 1
End While
// second half
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
While w2 * y <= h2 * x
If doFill Then
For i As Integer = -x To x
bm.SetPixel(xc + i, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + i, yc - y, Drawing.Color.Red)
Next
Else
bm.SetPixel(xc + x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc + y, Drawing.Color.Red)
bm.SetPixel(xc + x, yc - y, Drawing.Color.Red)
bm.SetPixel(xc - x, yc - y, Drawing.Color.Red)
End If
If s >= 0 Then
s += fh2 * (1 - x)
x -= 1
End If
s += w2 * ((4 * y) + 6)
y += 1
End While
Return bm
End Function
(Aside: I used // instead of ' for the comments... just for readability here. If you copy to Visual Studio you'll have to fix that)
Ok, I managed to find a solution for the filled ellipse by checking
if the pixel from the second half is gonna be drawn in the x-range of the first half of the ellipse.
function drawellipse(xc, yc, w, h, dofill)
--trouble with the size, 1 pixel to large on x and y to...
w=w/2 --good solution for making it the right size?
h=h/2 --good solution for making it the right size?
local w2 = w * w
local h2 = h * h
local fw2 = 4 * w2
local fh2 = 4 * h2
-- cheat by moving xc and yc so that we can handle quadrants
xc = xc + w
yc = yc + h
-- first half
local x = 0
local y = h
local s = 2 * h2 + w2 * (1 - h)
while h2 * x <= w2 * y do
if dofill then
for i = -y , y do
color(0,255,0)
dot(xc + x, yc + i)
dot(xc - x, yc + i)
--redraw()inkey()
end
else
color(255,0,255)
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
--redraw()inkey()
end
if s >= 0 then
s =s+ fw2 * (1 - y)
y =y- 1
end
s =s+ h2 * ((4 * x) + 6)
x =x+ 1
end
color(255,0,255)
line(xc + x,0,xc - x,0)
test1 = xc + x
test2 = xc - x
print(test1 .. '/' .. test2)
redraw()inkey()
-- second half
x = w
y = 0
s = 2 * w2 + h2 * (1 - w)
while w2 * y <= h2 * x do
if dofill then
for i = -x , x do
if not(xc + i > test2 and xc + i < test1) then
color(255,255,0)
dot(xc + i, yc + y)
dot(xc + i, yc - y)
redraw()inkey()
end
end
else
color(0,255,255)
dot(xc + x, yc + y)
dot(xc - x, yc + y)
dot(xc + x, yc - y)
dot(xc - x, yc - y)
redraw()inkey()
end
if s >= 0 then
s =s+ fh2 * (1 - x)
x =x- 1
end
s =s+ w2 * ((4 * y) + 6)
y =y+ 1
end
end
In vb.net you have both Graphics.DrawEllipse and Graphics.DrawArc. In Lua you may be able to use Cairo which I know has a arc function.
If you where to make a ellipse in a GraphicsPath in .Net and where to reverse engineer how it is stored in memory, you would find out that it is stored as four bezier curves. I implemented my own graphics library in vb.net once, and that was how I did it. The best resource I found at the time where a implementation in Actionscript, that I unfortunately was unable to locate aswell as that graphics library I was talking about.
TLDR; You should have a look at bezier curves.
A completely different, and very simple take on this, although the ellipse doesn't seem as "pretty" as the other algorithms; this just uses the mathematical definition of an ellipse and, looping over x calculates the y coordinate given x, w, and h.
Public Shared Function DrawEllipse2(ByVal xc As Integer, ByVal yc As Integer, ByVal w As Integer, ByVal h As Integer, ByVal doFill As Boolean) As Drawing.Bitmap
Dim bm As New Drawing.Bitmap(w * w, h * h)
For x As Integer = xc - w To xc + w
Dim y As Integer = CInt((Math.Sqrt(1 - ((x * x) / (w * w)))) * h)
If doFill Then
For j As Integer = -y To y
bm.SetPixel(w + x, h + j, Drawing.Color.Red)
Next
Else
bm.SetPixel(w + x, h + y, Drawing.Color.Red)
bm.SetPixel(w + x, h - y, Drawing.Color.Red)
End If
Next
Return bm
End Function