I have Terz-spectra data from acoustic measurements and I want to calculate the overall level. The values for each Terz-band are in decibel. Therefor the calculation formula is a bit lengthy. It would be L_overall=10*log10(10^(L_a/10)+10^(L_b/10)+10^(L_c/10)+10^(L_d/10)...).
As there are many frequencies, I don't want to write the whole formula by hand. I also don't want to use another column to do the inner calculation (10^(x/10)) before doing the outer calculation (10*log10(x+y+z+...)). So I wonder if there is a function in Excel that allows to apply a calculation on each cell like there is in Matlab for instance (cellfun, arrayfun).
I hope to end up with something similar like L_overall=10*log10(10^(B10:B80/10) which would allow me to do all the calculation in simply one cell.
Addition:
I have forgotten to say that I want the terz-data unaltered. I don't want to change that as I have to use it to plot that spectrum. So ideally I want all the work done in only one cell. I could do that by the lengthy formula, but it would take quite some time to type that for all frequencies.
Of course I could simply use another column and do the math there but that seems also inconvenient.
Actually the formula would be something like this:
=10*LOG(SUM(INDEX(10^(B10:B80/10),)),10)
Or this:
=10*LOG(SUMPRODUCT(10^(B10:B80/10)),10)
It's a bit clunky, but you could do 10^(L_a/10) for one cell, then click and drag the lower right corner to make that run for all cells.
Then create another cell which takes 10*log10 of the SUM of those cells.
If your goal is only to insert a specific formula in a bunch of cells you could use this:
For Each rCell In Application.Selection
rCell.Formula = "=10*log10(10^(L_a/10)+10^(L_b/10)+10^(L_c/10)+10^(L_d/10)...)"
Next rCell
Simply select all the cells in which you want to insert the formula and then run the sub. Make sure your formula is valid.
Related
I am trying to produce a count of the number of times different strings come up in an Excel table. An example table, currently in SHEET1, would be this:
I have another table in another spreadsheet where I want to indicate, for each letter on the left in Table 1, how many entries for "za", "zc" or "zd" come up on the right. However, I would only like to only consider one entry of each.
The end result, on row B of SHEET2, would have to be something like this:
At the moment I am using a combination of SUM and COUNTIFS to do the job.
More specifically, applied to the example, I am using the following formula:
=SUM(COUNTIFS(Sheet1!A1:A18,Sheet2!$A1,Sheet1!B1:B18,{"za","zc","zd"}))
The formula is doing some of what is intended. However, it is not counting each entry just one time. Instead, its is counting, for each letter on the left, every entry of "za","zc" or "zd". The table that the formula is returning is as follows:
How can I change the formula so that it does what I intend?
Thank you.
My initial thought would be:
=SUM(MIN (1,COUNTIFS(Sheet1!A1:A18,Sheet2!$A1,Sheet1!B1:B18,{"za","zc","zd"}))
but I’m not where I can test if the MIN will apply properly to the COUNTIFS array of results. ;-)
EDITED: The MIN function is taking minimum of 1 or all of the items in the COUNTIFS array, rather than minimum of 1 and each item in the COUNTIFS array, which is what I was afraid of. Using
=MIN(COUNTIFS(Sheet1!A$1:A$18,Sheet2!$A1,Sheet1!B$1:B$18,"za"),1)+MIN(COUNTIFS(Sheet1!A$1:A$18,Sheet2!$A1,Sheet1!B$1:B$18,"zc"),1)+MIN(COUNTIFS(Sheet1!A$1:A$18,Sheet2!$A1,Sheet1!B$1:B$18,"zd"),1)
will gain the desired results. It is a little clunky, but simpler than an array formula. If you want an array formula, you can use:
=SUM(FREQUENCY(IFERROR(MATCH({"za","zc","zd"},(IF(Sheet1!$A$1:$A$18=$A5,Sheet1!$B$1:$B$18)),0),""),IFERROR(MATCH({"za","zc","zd"},(IF(Sheet1!$A$1:$A$18=$A5,Sheet1!$B$1:$B$18)),0),"")))
This uses the FREQUENCY function to take a set of values and see how many items in another set of values fall within each of the data ranges. Since you need text instead of numbers, we use the MATCH function to find out the first time the value occurs in your list, returning "" with the IFERROR function if it doesn't. (We only need the first occurrence since you don't want to know how many occurrences there are). Since it is text, we use the same input for both arguments for FREQUENCY.
Therefore, if you need to change the values you are looking for or the ranges in which you are searching, make sure to change both! Alternately, you could list the values out somewhere, say in F1:F3, and make a named range for this, another one for A1:A18, and another for B1:B18. Your formula would then look something like this:
=SUM(FREQUENCY(IFERROR(MATCH(SearchValues,(IF(colA=$A2,colB)),0),""),IFERROR(MATCH(SearchValues,(IF(colA=$A2,colB)),0),"")))
Then you need only change your named range definitions and your formulas would update. :-)
NOTE: Since this is an array formula, you must close out of the cell by pressing CTRL+SHIFT+ENTER rather than only ENTER. When you look at the formula bar, you should see
{=SUM(FREQUENCY(IFERROR(MATCH(SearchValues,(IF(colA=$A2,colB)),0),""),IFERROR(MATCH(SearchValues,(IF(colA=$A2,colB)),0),"")))}
It does NOT work to enter the curly braces yourself. ;-)
You can use this formula at B1 and fill down:
B1:
=SUMPRODUCT(((Sheet1!$A$1:$A$18=A1)*(Sheet1!$B$1:$B$18= {"za","zc","zd"}))/
COUNTIFS(Sheet1!$A$1:$A$18,Sheet1!$A$1:$A$18,Sheet1!$B$1:$B$18,Sheet1!$B$1:$B$18))
I'm looking to make a bunch of my complicated formulas more readable. For example:
I know about Alt+Enter to add newlines within the formula itself. This makes the formula a little bit more manageable, but it's still not as readable as I'd like it. What else can I do to make big formulas like this one more readable?
I'm going to answer this myself as Excel 2013 doesn't have any truly good ways of doing what I want with formulae.
In my research I have found three ways of making formulae more readable. The first is something I mentioned in my question: Alt + Enter. This will insert a newline into the formula so that you can break up the wall of text. As an example you can change this:
into this:
The second method is to add a sort of comment to your formula. Personally I don't like this solution as it doesn't make formulae more readable to me, but others may like it. The method involves using the function N(). This function will return zero if given a string. For example:
Will give a result of 42 as N() returns zero.
The third method (shoutout to user shawnt00 for suggesting this in the comments) is to use named ranges. This can really help with readability as the user can convert something like A8:C14 to whatever name the user desires. To define a named range go to the Formulas table and click on "Define Name". Give the named range a name (preferably something that makes sense and not just "foo") and select the range of cells. Once done you can change something like this:
into a formula that is much more easily read:
The last method is to create extra columns and hide them (Thank you to user Quintin Balsdon for suggesting this). If, for example, you need the same value multiple times in one formula you can put the formula used to get that value into a separate cell that you hide and reference that cell. Take this formula for example:
On its own this formula isn't too bad, but if you take a close look at the formula in my question you'd see I do a very similar thing. Simply taking the index/match out and putting that into another cell and changing the above formula to
will make a complicated formula much smaller and much easier to quickly check what the value of J1 represents.
I have few formulas in a row and I want to drag them down. Formulas are complex and I don't have them in R1C1 format and I don't want to convert them into R1C1, but I would like to do something like:
Range(A2:B10).Formula = Range.(A1:B1).Formula
I know this would put the same formula into the whole range, I need a "drag effect" - so it's changes relatively to each row but without copy-pasting.
P.S. I don't want to copy-paste, as it eats more CPU, I'd like to have something
Define the range that you want to fill with the formula and use Range.FillDown.
Range("A1:B10").FillDown
Note: The first Row(s) of the range must include the original formulas
A tiny trick !:
Sub KopyFormulas()
Range("A1:B1").Copy Range("A2:B10")
End Sub
will copy the formulas downward and adjust them as well !
For single cells, you don't need to explicitly convert formulas to R1C1 format to use FormulaR1C1.
Even if you are using the standard A1 style of referencing, you can still use
Range("B2:B10").FormulaR1C1 = Range("B1").FormulaR1C1
And this will have the effect of copying down the formula in B1. It doesn't change the default format -- they will still display in the A1 format.
There does seem to be an issue with doing this with a block of two or more cells. You could do it column by column (in a loop if desired):
Range("A2:A10").FormulaR1C1 = Range("A1").FormulaR1C1
Range("B2:B10").FormulaR1C1 = Range("B1").FormulaR1C1
Whether or not this is worth the hassle (compared to the simple .FillDown) is another question. You could time it.
By the way -- I wouldn't think that .FillDown is particularly inefficient. Did you do the usual optimizations of turning off of screen-updating, setting calculation to manual, etc.?
I've been trying to get to grips with SUMIF & COUNTIF functions in Excel recently, with limited success. I've realised the crux of the problem is that help pages give far too specific examples, including the official Office support.
I already know how to put together complex tests with multiple criteria already, using IF statements. What I really need is a guide to how to convert IF statements for use in such functions.
The real issue for me is what happens to cell references? I have a column of cells, each with some value for a given property. With an IF function I can go into the adjacent column, test the neighbouring cell using some criterion or set of criteria to find its value for a given property, and return an appropriate answer. I click and drag my formula down to check all the cells.
Eg. A1:A10 are the cells I'm testing. The property I'm checking is their length, whose value will be the number of characters. The appropriate answer will be whether the number of characters is above or below a threshold.
Put together; IF(LEN(A1)>50,"above","below")
Pasted into B1 and dragged down to B10 I get an array of answers.
Suppose I want to count all the cells which meet the condition, that's where I'm stumped. COUNTIF looks like I could just specify the range (A1:A10) and condition LEN(A1)>50 and get my answers. But what do I put inside LEN()? I want to go through and check for each cell in the range, how can I specify just one? Specifying none: LEN() or the range LEN(A1:A10) won't work.
For highlighting cells (conditional formatting), it's easy, just put the top left cell of the array, so LEN(A1), but that doesn't work either!
I hope that's made the problem clear. Obviously I could just have
IF(LEN(A1)>50,1,0) in B1:B10, and SUM(B1:B10) in C1 or something, thus counting all the cells which match the criteria in the if statement. But that seems like a totally retrograde step which negates the benefits of COUNTIF entirely. Namely that it saves space and reduces complexity in the sheet by doing away with intermediate steps.
And I have at least 1 sheet for which that definitely won't work owing to the volatile nature of my array sizes; I wouldn't be able to fit the additional intermediate columns if I wanted to!
SO, can any IF-statement-style check be converted to work with COUNTIF/SUMIF, if so then how, and are there any other tips you could include in case someone with a similar problem comes searching? Thanks so much for answers and help!
Use SUMPRODUCT:
=SUMPRODUCT(1*(LEN(A1:A10)>50))
COUNTIF/SUMIF do not like it when you try to modify the range to be tested. You can do a lot with the criteria, but not the range. It is what is given up to use it in a non array form.
Is it possible to prevent calculations happening to a single cell in Excel sheet? Let's say I have 1001 cells that are very fast to calculate, but 1 cell slows sheet down, is it possible to disable calculations for that 1 cell only?
What I'm NOT trying to do:
Disabling all of cell calculation programically
Calculating specific cells programically while global calculation is set to manual
Use Excel's =IF() function. It is set up to "short-circuit" -- it only evaluates the second parameter if the first parameter is true, oppositely for the third parameter.
So, if the cell is C1, and the cell's formula is currently
=LOOKUP(2,1/(A1:A100000=666),B1:B100000)
and you want it to only be calculated when D1 is true, use
=IF(D1,LOOKUP(2,1/(A1:A100000=666),B1:B100000),C1)
Notice it's a circular reference -- it's how you keep the value the same when D1 is false. Turn on iteration if you want to get rid of the warning message.
Another way is to use one of the third-party Add-Ins out there that lets you store a global variable off-sheet and then retrieve it, which would use syntax like this:
=IF(D1,SetGlobal("C1StoredCalculation",LOOKUP(2,1/(A1:A100000=666),B1:B100000)),GetGlobal("C1StoredCalculation"))
SetGlobal() and GetGlobal() can also be written in VBA, though they'll be a tiny bit slower than an XLL, and they'll lose the value if you reset your VBA project.
Excel does not have a method to disable calculation for a single cell.
You could move the slow formula to a separate sheet and use worksheet.enablecalculation to disable calculation for that sheet.
Or you could store the formula somewhere as text, store the result as a value in the cell, then restore the formula when you want to calculate it.
You can use a replacement UDF and take advantage of a lack of volatility.
Say we have a formula like:
=LOOKUP(2,1/(A1:A100000=666),B1:B100000)
Excel will re-calculate this if any cell in cols A or B change, but the UDF
Public Function myudf(r As Range) As Variant
myudf = Evaluate("LOOKUP(2,1/(A1:A100000=666),B1:B100000)")
End Function
will only be re-calculated when its argument changes. So pick a cell and enter:
=myudf(Z100)
make any changes you want to cells in cols A or B and myudf will remain un-re-calculated until you change Z100
You can use the same tiny trick to make "quasi-volatile" versions of =TODAY() or =NOW() for =RAND()
I don't think this can be done. You can turn off automatic calculation in entire workbooks (as you mentioned), but I don't think there is a way to do this on an individual cell.