Try to input data on a specific row of an Array - vba

I have crated an Array with 500 rows and 10 columns. I am trying to generate an array of Signal strength using the radar range equation. I want to detect two targets at two ranges and I am putting them in the array at a specific point. I have 2 If statements nested within 2 for loops. The for loops work properly, I can't figure out where my If statements are wrong though. All of the values are correct (Hence the msgboxs for the values)
I have tried moving the Signal(i, j) = 0 into an If statement but I wasn't sure how to set the bounds since it is at every other points besides row 50 and 250.
Sub Generate_Power_Amplitude()
'/////////////////////Basic Parameters////////////////////////////
'/////////////////////Step 1//////////////////////////////////////
' Input the parameters of the Radar Range Equation
TotalPower = 10000 '(Watts)
Gain = 3162.27766 '(35 dB of gain)
Wavelength = 0.3 '(meters)
RCS = 15 '(meters^2)
RangeToTarget = 35000 '(meters)
PulseWidth = 1.67 * 10 ^ -6 '(seconds)
Bandwidth = 6 * 10 ^ 5 '(Hertz)
RangeBins = 1 * 10 ^ 3 '(meters)
PRI = 1 * 10 ^ -4 '(seconds)
PRF = 1 * 10 ^ 4 '(Hertz)
PRIDistance = 60000 '(meters)
'//////////////////Targets/////////////////////////////////////////////
'//////////////////Step 2//////////////////////////////////////////////
' Define how many targets and their distance
Target1 = 25000 '(meters)
Target2 = 125000 '(meters)
'/////////////////Operations//////////////////////////////////////////
RadarRangeNumerator = TotalPower * Gain ^ 2 * Wavelength ^ 2 * RCS
RadarRangeDenomenator = (4 * 3.1415926) ^ 3 * RangeToTarget ^ 4
RelativePower = RadarRangeNumerator / RadarRangeDenomenator
PowerAmplitude = RelativePower ^ 0.5
RelativePower1 = RadarRangeNumerator / ((4 * 3.1415926) ^ 3 * Target1 ^ 4)
RelativePower2 = RadarRangeNumerator / ((4 * 3.1415926) ^ 3 * Target2 ^ 4)
PowerAmp1 = RelativePower1 ^ 0.5
PowerAmp2 = RelativePower2 ^ 0.5
Dim Signal(500, 10)
For i = 1 To 500
For j = 1 To 10
If i = 50 Then
Signal(50, j) = PowerAmp1
ElseIf i = 250 Then
Signal(250, j) = PowerAmp2
End If
Signal(i, j) = 0
Next j
Next i
MsgBox Signal(50, 1)
MsgBox Signal(250, 1)
End Sub
I got the msgboxes to give the right values and this is the new For Loop, there is a comment below, as I said I feel this will eventually break and if there is a right way to do this let me know.
Dim Signal(500, 10)
For i = 1 To 500
For j = 1 To 10
If i = 500 Then
Signal(50, j) = PowerAmp1
Signal(250, j) = PowerAmp2
End If
Signal(i, j) = 0
Next j
Next i

This may be too simple of an answer but it seems like you just need to loop using the Ubound and Lbound tools. Here's an example with your code where you set the limits based on the Array size:
Dim Signal(500, 10)
For i = Lbound(Signal,1) To Ubound(Signal,1)
For j = LBound(Signal,2) To UBound(Signal,2)
If i = Ubound(Signal,1) Then
'This part confuses me:
Signal(50, j) = PowerAmp1
Signal(250, j) = PowerAmp2
End If
Signal(i, j) = 0
Next j
Next i

If all you ever want to do is insert the values for 50 and 250 into an array, then you don't need to set all the values to zero. In VBA, all variable values are initialized to zero including elements of an array. So this will produce the exact same result as your code:
Dim Signal(1 To 500, 1 To 10)
Signal(50, j) = PowerAmp1
Signal(250, j) = PowerAmp2
And, by the way, notice that I'm specifically stating the dimension range of the array. VBA will default to a zero-based array -- meaning your definition produced an array from 0 to 500, i.e. 501 elements.
#PGSystemTester is exactly correct in relating your loop bounds directly to the array bounds. This is a very common practice and can save you lots of heartache later on.
Dim Signal(1 To 500, 1 To 10)
For i = LBound(Signal, 1) To UBound(Signal, 1)
For j = LBound(Signal, 2) To UBound(Signal, 2)
If i = 500 Then
Signal(50, j) = PowerAmp1
Signal(250, j) = PowerAmp2
End If
Signal(i, j) = 0
Next j
Next i
Your next step may be to calculate the power at a series of stepped ranges to each target. Keep in mind that to define a variable number of steps -- array elements in this case -- you'll have to use ReDim
Const RANGE_STEPS As Long = 1000
Dim Signal As Variant
ReDim Signal(1 To RANGE_STEPS, 1 To 10)
If you're using the UBound and LBound functions, your loop remains exactly the same.

Related

Test if a permutation of a number exists in a collection

I'm trying to list all numbers with 3 digits where the individual digits sum to a given number.
So far I can return a list of all numbers using this Visual Basic code:
target = 17
i = 1
j = 1
k = 1
Do While i < 10
Do While j < 10
Do While k < 10
r = i + j + k
If r = target Then
If i <> j And j <> k And k <> i Then
lsNumbers.Add(i & j & k )
End If
End If
k += 1
Loop
If k = 10 Then k = 1
j += 1
Loop
If j = 10 Then j = 1
i += 1
Loop
But I want only unique, non repeating combinations.
For example for the target number 17:
179, 197, 269, 278, 287...
I want to be able to test the current number before I add it to the list, to check if it is a combination of a number already in the list - so 197 would fail because of 179, and 287 would fail because of 278
Observations
Just curious, is excluding the 0 digit on purpose?
To iterate through the possible digits, a well suited instruction pair is FOR NEXT. Definitely simpler than the DO WHILE that you used.
Loop
If k = 10 Then k = 1
Loop
If j = 10 Then j = 1
Upon loop completion, the iterator is sure to contain 10. The IF is redundant.
Solution
In order to check if a number, that obeys the condition, is unique in the sense that it is not composed of the same 3 digits as an already validated number, you could consult a 3-D array. If the new number corresponds to a non-zero element in this array, it means that the new number would be using the same digits as an earlier number. That's reason to reject it.
Next code runs in QBasic. You'll have no trouble rewriting it for Visual BASIC.
DIM r%(1 TO 9, 1 TO 9, 1 TO 9)
FOR i% = 1 TO 9
FOR j% = 1 TO 9
FOR k% = 1 TO 9
r%(i%, j%, k%) = 0
NEXT
NEXT
NEXT
target% = 17
FOR i% = 1 TO 9
FOR j% = 1 TO 9
FOR k% = 1 TO 9
IF i% + j% + k% = target% THEN
IF r%(i%, j%, k%) = 0 THEN
PRINT i% * 100 + j% * 10 + k%; " ";
r%(i%, j%, k%) = 1 ' Could do without this one because of the ascending order
r%(i%, k%, j%) = 1
r%(j%, i%, k%) = 1
r%(j%, k%, i%) = 1
r%(k%, i%, j%) = 1
r%(k%, j%, i%) = 1
END IF
END IF
NEXT
NEXT
NEXT
This is my output of valid numbers:
179 188 269 278 359 368 377 449 458 467 557 566

EXPLAIN what this VB CODE means

Function convertToText(ByVal data As String) As String
Dim result As String = Nothing
Dim i As Integer = 0
Dim j As Integer = 0
For Each c As Char In data.ToCharArray
j *= 2
If c = "1"c Then j += 1
i += 1
If i = 8 Then
i = 0
result &= Chr(j)
j = 0
End If
Next
Return result
End Function
It converts binary to text but its a bit difficult for me to understand the logic behind it.
Someone please help.
The code seems to convert a text containing a binary number representing 8 bit character codes to a string containing these characters.
The for each loop loops over all binary digits ("0" or "1") of the input. The code of each result character is computed and after every 8 input characters the code is considered to be complete and the new character whose code was determined is added to the result (result &= Chr(j) is the same as result = result & Chr(j). Chr(j) converts an Integer containing a character code into a character). The variable i counts the bits.
The variable j holds the character code. If a bit is "1", then 1 is added to j (j += 1 is the same as j = j + 1), but not if it is "0".
A "1" in the right most bit position has a (decimal) value of 1. The next to its left a value of 2. The next 4 and so on. The value doubles for each position until it reaches 128 for the left most bit of an 8 bit number. Therefore j is doubled on each loop (j *= 2 is the same as j = j * 2).
Example with just 4 bits:
data = "1010"
The binary number 1010 means
1 * 8 + 0 * 4 + 1 * 2 + 0 * 1 = (decimal)10
The code does this
j = 0 => 0
j *= 2 => 0
j += 1 => 1 'since c = "1"
j *= 2 => 2
'no += 1 since c = "0"
j *= 2 => 4
j += 1 => 5 'since c = "1"
j *= 2 => 10
'no += 1 since c = "0"
The first 1 we added is doubled 3 times and becomes 8. The second 1 we added is doubled only once and becomes 2. 8 + 2 = 10.

How to point at single values within top 10 % Excel VBA function

I have a column in excel full of numbers, like this:
1
A 100
B 200
C 300
D 400
E 500
F 600
G 700
H 800
I 900
J 1000
K 1100
etc
etc
I formatted the column with a macro so that it highlights the top 10 %. Unfortunately, I have to work with it now, as in I have to have a piece of code that says: ok, grab the first cell that is in the top 10 % (say it's K1). Get K1 and copy it somewhere else.
Question:
How do I point to an element in the top 10 %? How do I tell VBA "Grab the first top 10% value (K1), then grab that second top 10% value?
Many thanks
Copy Top 10% of values from each Column to a different Worksheet
Sub ProcessColumns()
Dim i As Integer, j As Integer, rowCount As Long
Dim minvalue As Double, largeValue As Double
Dim arr
With Worksheets("Source")
arr = Sheet1.UsedRange.Value
For j = 1 To UBound(arr, 2)
minvalue = WorksheetFunction.Percentile(.Columns(j), 0.9)
For i = 2 To UBound(arr, 1)
largeValue = WorksheetFunction.Large(.Columns(j), i - 1)
If largeValue >= minvalue Then
arr(i, j) = largeValue
rowCount = i
Else
Exit For
End If
Next
Next
End With
Worksheets("Target").Range("A1").Resize(rowCount, UBound(arr, 2)).Value = arr
End Sub

run time error 5 in VBA excel when working with array

I use vba on excel 2007, OS: windows vista, to make calculation using kinematic wave equation in finite difference scheme. But, when it runs the run-time 5 (invalid procedure call or arguments) message appears. I really don't what is going wrong. Anyone can help?
Sub kwave()
Dim u(500, 500), yy(500, 500), alpha, dt, dx, m, n, so, r, f, X, L, K As Single
Dim i, j As Integer
dx = 0.1
dt = 0.01
L = 10
m = 5 / 3
r = 1
f = 0.5
n = 0.025
so = 0.1 'this is slope
alpha = 1 / n * so ^ 0.5
X = 0
For i = 0 To 100
Cells(i + 1, 1) = X
u(i, 1) = L - so * X
X = X + dx
Cells(i + 1, 2) = u(i, 1)
Next i
For j = 0 To 100
For i = 1 To 100
'predictor step
u(i, j + 1) = u(i, j) - alpha * dt / dx * (u(i + 1, j) ^ m - u(i, j) ^ m) + (r - f) * dt
'corrector step
K = u(i, j + 1) ^ m - u(i - 1, j + 1) ^ m '<<<<----- RUNTIME ERROR 5 HAPPENS AT THIS LINE
yy(i, j + 1) = 0.5 * ((yy(i, j) + u(i, j + 1)) - alpha * dt / dx * K + (r - f) * dt)
Next i
Next j
End Sub
You are declaring the variables wrong- the array should store a double/single but it is defaulting to a variant. See this article.
http://www.cpearson.com/excel/declaringvariables.aspx -
"Pay Attention To Variables Declared With One Dim Statement
VBA allows declaring more than one variable with a single Dim
statement. I don't like this for stylistic reasons, but others do
prefer it. However, it is important to remember how variables will be
typed. Consider the following code:
Dim J, K, L As Long You may think that all three variables are
declared as Long types. This is not the case. Only L is typed as a
Long. The variables J and K are typed as Variant. This declaration is
functionally equivalent to the following:
Dim J As Variant, K As Variant, L As Long You should use the As Type
modifier for each variable declared with the Dim statement:
Dim J As Long, K As Long, L As Long "
Additionally, when i = 99 and j = 10, u(99,11), which is j+1, produces a negative number. Note that this does not fully cause the problem though, because you can raise negative numbers to exponents. Ex, -5^3 = -125

Simulation runs fine # 10k cycles, but gets error 13 (type mismatch) # 100k cycles

First off, here's my code:
Sub SimulatePortfolio()
Dim lambda As Double
Dim num As Integer
Dim cycles As Long
Column = 12
q = 1.5
lambda = 0.05
cycles = 100000
Dim data(1 To 100000, 1 To 10) As Integer
Dim values(1 To 10) As Double
For i = 1 To 10
values(i) = 0
Next i
temp = lambda
For i = 1 To cycles
lambda = temp
num = 10
t = 0
Dim temps(1 To 10) As Integer
For k = 1 To 10
temps(k) = 1000
Next k
Do While (t < 10 And num > 0)
t = t + tsim(lambda, num)
For j = 1 To 10
If (j > t) Then
temps(j) = temps(j) - 50
End If
Next j
num = num - 1
If (num <= 0) Then
Exit Do
End If
lambda = lambda * q
Loop
For l = 1 To 10
values(l) = values(l) + temps(l)
data(i, l) = temps(l)
Next l
Next i
For i = 1 To 10
Cells(i + 1, Column) = values(i) / cycles
'Problem occurs on this line:
Cells(i + 1, Column + 1).Value = Application.WorksheetFunction.Var(Application.WorksheetFunction.Index(data, i, 0))
Next i
End Sub
Function tsim(lambda As Double, num As Integer) As Double
Dim v As Double
Dim min As Double
Randomize
min = (-1 / lambda) * Log(Rnd)
For i = 1 To (num - 1)
Randomize
v = (-1 / lambda) * Log(Rnd)
If (min > v) Then
min = v
End If
Next i
tsim = min
End Function
When I set the value for cycles to 10000, it runs fine without a hitch. When I go to 100000 cycles, it gets an Error 13 at the indicated line of code.
Having been aware that Application.Tranpose is limited to 65536 rows with variants (throwing the same error) I tested the same issue with Index
It appears that Application.WorksheetFunction.Index also has a limit of 65536 rows when working with variants - but standard ranges are fine
So you will need to either need to dump data to a range and work on the range with Index, or work with two arrays
Sub Test()
Dim Y
Dim Z
'works in xl07/10
Debug.Print Application.WorksheetFunction.Index(Range("A1:A100000"), 1, 1)
Y = Range("A1:A65536")
`works
Debug.Print Application.WorksheetFunction.Index(Y, 1, 1)
'fails in xl07/10
Z = Range("A1:A65537")
Debug.Print Application.WorksheetFunction.Index(Z, 1, 1)
End Sub