Calculation of sound level in dB - delphi

I was never good in math, so I need help how to convert linear value to dB.
First I show you how I calculated the linear value from -24dB.
var dB, linearLevel: integer;
begin
dB := -24;
linearLevel := Round( 1/exp( 2.30258509299 * (abs(dB)/20) ) *32767);
end;
Where 1/exp( 2.30258509299 * (abs(-24)/20) ) ; is normalized value.
For conversion to sample value I use 1/exp(...)*32767
My problem is here: conversion back
I was told to use formula 20*log10(linearLevel). So I tried to create it but my result is 18 instead 24 (or -24) dB.
linearValue := 2067; // the result of the formula above
db := round( exp( 20*2.30258509299*(linearLevel / 32767) ) );
How to calculate the dB?

If
linearLevel := Round( 1/exp( 2.30258509299 * (abs(dB)/20) ) * 32767);
we lose information due to the rounding (in the language of mathematics, the Round function is not injective). So given a linearLevel value, it is impossible to get back the original dB value. Therefore, let us consider
linearLevel := 1/exp( 2.30258509299 * (abs(dB)/20) ) * 32767;
instead. This implies
linearLevel / 32767 := 1/exp( 2.30258509299 * (abs(dB)/20) )
and
32767 / linearLevel := exp( 2.30258509299 * (abs(dB)/20) )
and
ln(32767 / linearLevel) := 2.30258509299 * (abs(dB)/20)
and
ln(32767 / linearLevel) / 2.30258509299 := abs(dB)/20
and
20 * ln(32767 / linearLevel) / 2.30258509299 := abs(dB).
Here we again have an issue, since the absolute value function is not injective. If abs(dB) is 7, we cannot possibly tell if dB is 7 or -7.
But if we assume that dB is non-positive, we finally have
dB = -20 * ln(32767 / linearLevel) / 2.30258509299.
Simplifications
Since 2.30258509299 is ln(10), this is
dB = -20 * ln(32767 / linearLevel) / ln(10).
But log10(x) = ln(x) / ln(10), so we can write
dB = -20 * Log10(32767 / linearLevel)
where the Log10 function is found in the Math unit.
Also, using the law a log(b) = log(b^a) in the case a = -1, we can even write
dB = 20 * Log10(linearLevel / 32767).

Related

Mathematica's ListLinePlot in wxMaxima

I have the following functions:
P[t_] := P[t] = P[t-1] +a*ED[t-1];
ED[t_] := ED[t] = DF[t] + DC[t];
DF[t_] := DF[t] = b (F - P[t]);
DC[t_] := DC[t] = c (P[t] - F);
And the following parameters:
a=1;
c=0.2;
b = 0.75;
F=100;
In Mathematica I use the function "ListLinePlot" in order to plot P[t] and F:
ListLinePlot[{Table[P[t], {t, 0, 25}], Table[F, {t, 0, 25}]}, PlotStyle → {Black, Red},Frame → True, FrameLabel → {"time", "price"}, AspectRatio → 0.4, PlotRange → All]
How can I do this in wxMaxima? Is there a similar function or an alternative to ListLinePlot?
This is my attempt in wxMaxima:
P[t] := P[t-1] + a * ED[t-1];
ED[t] := DF[t] + DC[t];
DF[t] := b*[F-P[t]];
DC[t] := c*[P[t]-F];
a=1;
c=0.2;
b=0.75;
F=100;
And then I tried:
draw2d(points(P[t], [t,0,25]))
The plotted function should look like this:
OK, I've adapted the code you showed above. This works for me. I'm working with Maxima 5.44 on macOS.
P[t] := P[t-1] + a * ED[t-1];
ED[t] := DF[t] + DC[t];
DF[t] := b*(F-P[t]);
DC[t] := c*(P[t]-F);
a:1;
c:0.2;
b:0.75;
F:100;
P[0]: F + 1;
Pt_list: makelist (P[t], t, 0, 25);
load (draw);
set_draw_defaults (terminal = qt);
draw2d (points_joined = true, points(Pt_list));
Notes. (1) There needs to be a base case for the recursion on P. I put P[0]: F + 1. (2) Assignments are : instead of =. Note that x = y is a symbolic equation instead of an assignment. (3) Square brackets [ ] are only for subscripts and lists. Use parentheses ( ) for grouping expressions. (4) Syntax for draw2d is a little different, I fixed it up. (I put a default for terminal since the built-in value is incorrect for Maxima on macOS; if you are working on Linux or Windows, you can omit that.)
EDIT: Try this to draw a horizontal line as well.
draw2d (points_joined = true, points(Pt_list),
color = red, points([[0, F], [25, F]]),
yrange = [F - 1, P[0] + 1]);

how to fetch from PROCEDURE call in joomla

I am working in joomla. And I have huge amount of data in mySql table. I need a calculation for the project with all this data. As the result will vary every time, I am using MySql PROCEDURE to execute the calculation.
In the PROCEDURE I am first working the calculation, then inserting the data in a temporary table (tmp_zipcode), then fetching it. Its all working fine. But I need to fetch it directly after calculation. I do not want to insert the data to temporary table then fetch it every time.
The following is a procedure call in mySql. However, I think, you don't need to go through below whole PROCEDURE code to answer this question.
DELIMITER $$
DROP FUNCTION IF EXISTS `GetDistance`$$
CREATE FUNCTION `GetDistance`(
lat1 numeric (9,6),
lon1 numeric (9,6),
lat2 numeric (9,6),
lon2 numeric (9,6)
) RETURNS decimal (10,5)
BEGIN
DECLARE x decimal (20,10);
DECLARE pi decimal (21,20);
SET pi = 3.14159265358979323846;
SET x = sin( lat1 * pi/180 ) * sin( lat2 * pi/180 ) + cos(
lat1 *pi/180 ) * cos( lat2 * pi/180 ) * cos( abs ( (lon2 * pi/180) -
(lon1 *pi/180) ) );
SET x = atan( ( sqrt( 1- power( x, 2 ) ) ) / x );
RETURN ( 1.852 * 60.0 * ((x/pi)*180) ) / 1.609344;
END $$
DELIMITER ;
DELIMITER $$
DROP PROCEDURE IF EXISTS `GetNearbyZipCodes`$$
CREATE PROCEDURE `GetNearbyZipCodes`(
zipbase varchar (6),
rang numeric (15)
)
BEGIN
DECLARE lat1 decimal (5,2);
DECLARE long1 decimal (5,2);
DECLARE rangeFactor decimal (7,6);
SET rangeFactor = 0.014457;
SELECT Latitude,Longitude into lat1,long1 FROM ZIPCodes WHERE ZipCode = zipbase;
Insert into tmp_zipcode(zipcode,radius) SELECT B.ZipCode,GetDistance(lat1,long1,B.Latitude,B.Longitude) FROM ZIPCodes AS B WHERE B.Latitude BETWEEN lat1-(rang*rangeFactor) AND lat1+(rang*rangeFactor) AND B.Longitude BETWEEN long1-(rang*rangeFactor) AND long1+(rang*rangeFactor) AND GetDistance(lat1,long1,B.Latitude,B.Longitude) <= rang;
END $$
DELIMITER ;
The following is joomla code which I am using to call the PROCEDURE. Here first I am truncating the temp table and then calling the PROCEDURE in which it inserts data. Then I fetch it again.
$truncate="truncate table tmp_zipcode";
$db->setquery($truncate);
$db->query();
$test="CALL GetNearbyZipCodes( $zipcode ,$miles)";
$db->setquery($test);
$re=$db->query();
$result_codes_query="select zipcode,radius from tmp_zipcode";
$db->setquery($result_codes_query);
$db->query();
$codes=$db->loadAssocList();
So I need to fetch the calculation part directly, without inserting to, and fetching from temp table. I do not want to use a temp table at all. How I can fetch data from MySql PROCEDURE in joomla ?

Chart of function exponential

I am trying to create a line graph of an exponential function:
j:=IWcmbxCriterionName.ItemIndex;
p1a:=(-5000)*0.001;
p1c:= -(Exp(P1a * Min[j])) / (Exp(P1a * Max[j]) - Exp(P1a * Min[j]));
p1b := (1 - P1c) / Exp(P1a * Max[j]);
k1 := Max[j];
i1 := Min[j];
while i1 <= k1 do
begin
Serie1.AddXY(i1, P1b * Exp(p1a * (i1)) + p1c,'',clWebBLUE);
i1 := i1 + 0.01;
end;
chart1.BottomAxis.Maximum:=k1;
chart1.BottomAxis.Minimum:= min[j];
chart1.UndoZoom;
but the serie1 not appear on the graph! Can someone can help me?
Remove the lines where you set bottom axis min. and max. and try to set i to automatic just in case those values are wrong:
Chart1.BottomAxis.Automatic:=True;
If the problem persists please send us a simple example project we can run "as-is" to reproduce the problem here. You can post your files at our upload page.

Generate random number in a float range

How we can generate randomize number between a range in the Float numbers (in delphi xe3) ?
For example, randomize number between [0.10 to 0.90].
I need give results like:
[ 0.20 , 0.32 , 0.10 , 0.50 ]
Thanks for solutions....
Another option is to use RandomRange (returns: AFrom <= r < ATo) as follow:
RandomRange(10, 90 + 1) / 100
or
RandomRange(10, 90 + 1) * 0.01
will return numbers in the range of 0.10 to 0.90 (including 0.90)
var
float : Double;
float := Random; // Random float in range: 0 <= float < 1
float := 0.1 + float*0.8 // 0.1 <= float < 0.9
To initialize the Random number generator, make a single call to Randomizeor set the RandSeed parameter before calling the Random function for the first time.
Not doing so, generates the same sequence every time you run the program. Note however, that this sequence is not guaranteed when recompiling for another compiler version.
Try this:
function RandomRangeF(min, max: single): single;
begin
result := min + Random * (max - min);
end;
This is a bit cheeky but here goes: Depends how many numbers you want after the floating point. For example, if you want 1 number, you could generate in the 100 - 999 range and then divide by 10. Or 1000 - 9999 and divide by 100.

How can I know why my program calculations and output is incorrect?

I'm working on a programming problem.
Note: This is not a student project. I am working on this for a new Quest for the website Try My Quest Dot Com, for which i am the admin.
Problem:
Jenny just started work as a programmer for Justine's Java Workshop. She is paid $10
an hour, with a few exceptions. She earns an extra $1.50 an hour for any part of a day where she works more than 8 hours, and an extra $2.50 an hour for hours beyond 40 in any one week. Also, she earns a 125% bonus for working on Saturday, and a 50% bonus for working on Sunday. The bonuses for Saturday and Sunday are computed based on the hours worked those days; they are not used to calculate any bonus for working more than 40 hours in a week. You'll be given the number of hours Jenny worked each day in a week (Sunday, Monday, etc ), and you need to compute her salary for the week. The input will be positive integers, less than or equal to 24. The output must be formatted with a dollar sign and rounded up to the nearest penny. For example, $2" and $2.136666" are wrong answers; the correct versions are $2.00" and $2.14", respectively.
Anyway, i am trying to write this in Delphi (No form project). I pass the program a command line argument - timecard.dat
input
0, 8, 8, 8, 8, 8, 0
0, 10, 10, 10, 10, 10, 0
0, 0, 8, 8, 8, 8, 8
0, 0, 0, 10, 10, 10, 10
10, 10, 10, 9, 9, 9, 9
Output
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $540.75
Output #5: $905.88
My Out put however is:
Output #1: $400.00
Output #2: $540.00
Output #3: $500.00
Output #4: $537.00
Output #5: $902.50
The last two output values of mine are different from the actual results. Not sure why, and the more i stare at the code, the less i see it
Can anyone tell me what i have done wrong?
program ACSL_Time_Cards;
{assumes Sunday = 1, Monday 3, etc}
uses
SysUtils,
Dialogs;
const
HourlyWage = 10.00;
OverEightWage = 1.50;
OverFortyWage = 2.50;
var
F: TextFile;
I, ArrayIndex: Integer;
WeeklyHours: Array[0..6] of Integer; //weekly hours
HourStr, LineStr: String;
TotalHours, TotalOverFortyHours, TotalOverEightHours, TotalSatHours, TotalSunHours: Integer;
TotalWages: Real;
begin
//initialize variables
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
TotalWages:= 0.00;
ArrayIndex:= 0;
//open file "timecard.dat" for input
if FileExists(ParamStr(1)) then
begin
AssignFile(F, ParamStr(1));
Reset(F);
//step through file and extract each line and store in hoursStr
while not EOF(F) do
begin
Readln(F, LineStr);
//step through hours string and fill Array with weekly hours
for I:= 1 to length(LineStr) do
begin
//if character is not a ',' then add it to hourStr
if LineStr[I] <> ',' then
HourStr:= HourStr + LineStr[I]
else
begin
//add HourStr to Array
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//reset the variable
HourStr:= '';
//increment Variable
Inc(ArrayIndex);
end; //else
end; //for I:= 1 to length(HoursStr) do
//clean up by adding the last remaining one
WeeklyHours[ArrayIndex]:= StrToInt(HourStr);
//step through array and figure out overtime Daily and Weekly
for I:= Low(WeeklyHours) to High(WeeklyHours) do
begin
TotalHours:= TotalHours + WeeklyHours[I];
if WeeklyHours[I] > 8 then
TotalOverEightHours:= TotalOverEightHours + WeeklyHours[I]-8;
//get sunday hours
if I + 1 = 1 then
TotalSunHours:= TotalSunHours + WeeklyHours[I];
//get saturday hours
if I + 1 = 7 then
TotalSatHours:= TotalSatHours + WeeklyHours[I];
end;
//get total over 40 hours
if TotalHours > 40 then
TotalOverFortyHours:= TotalHours-40;
//compute Regular Hours
TotalWages:= TotalWages + TotalHours * 10.00;
//compute overtime hours
TotalWages:= TotalWages + TotalOverEightHours * 1.50;
TotalWages:= TotalWages + TotalOverFortyHours * 2.50;
//compute bonuses
TotalWages:= TotalWages + (TotalSatHours * 10.00) * 1.25;
TotalWages:= TotalWages + (TotalSunHours * 10.00) * 0.50;
ShowMessage('TotalWages: ' + FormatFloat('$0.00', TotalWages));
//reset variables
TotalWages:= 0.00;
TotalHours:= 0;
TotalOverEightHours:= 0;
TotalOverFortyHours:= 0;
TotalSatHours:= 0;
TotalSunHours:= 0;
HourStr:= '';
ArrayIndex:= 0;
end; //while not EOF(F) do
CloseFile(F);
end
else
ShowMessage('File does not exist!');
end.
I'm sure there are many ways that this could have been written better. I really am just interested in why my values different from the expected values. Thanks!
For a simple problem like this, you might want to write it out by hand and then see if your code follows the same steps you did.
For Output 4, the 125% bonus for Saturday is not including the $1.50 per hour extra after 8:
she should earn
Wed: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Thu: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Fri: $103 | $100 for 10 hours plus $3 for 2 hours over 8
Sat: $231.75 | ($100 for 10 hours, $3 for 2 hours over 8), $128.75 for 125% bonus
for a total of 540.75
The code would benefit from the I/O and the calculation being separated. You problems are with the calculation. I'd write it something like this:
uses
Math;
type
TDay = (
daySunday,
dayMonday,
dayTuesday,
dayWednesday,
dayThursday,
dayFriday,
daySaturday
);
TDayArray = array [TDay] of Integer;
function Wage(const Hours: TDayArray): Double;
const
BasicRate = 10.0;
DailyOvertimeRate = 1.5;
WeeklyOvertimeRate = 2.5;
DailyOvertimeThreshold = 8;
WeeklyOvertimeThreshold = 40;
DailyBonus: array [TDay] of Double = (1.5, 1.0, 1.0, 1.0, 1.0, 1.0, 2.25);
var
Day: TDay;
DailyOvertimeHours, WeeklyOvertimeHours, TotalHours: Double;
DailyPay: array [TDay] of Double;
begin
TotalHours := 0.0;
for Day := low(Day) to high(Day) do begin
TotalHours := TotalHours + Hours[Day];
DailyOvertimeHours := Max(Hours[Day]-DailyOvertimeThreshold, 0.0);
DailyPay[Day] := Hours[Day]*BasicRate;
DailyPay[Day] := DailyPay[Day] + DailyOvertimeHours*DailyOvertimeRate;
DailyPay[Day] := DailyPay[Day]*DailyBonus[Day];
end;
WeeklyOvertimeHours := Max(TotalHours-WeeklyOvertimeThreshold, 0.0);
Result := Sum(DailyPay) + WeeklyOvertimeHours*WeeklyOvertimeRate;
end;
This is still a little unpolished and I'm not very happy with the variable names for pay rates, overtime etc.
Once have such a utility function available, then putting it together with the rest of your program becomes a lot easier.
The biggest weakness in your current program is that everything is housed in one giant routine. Break it down into small pieces and you'll be able to verify those small pieces more readily than hunting for problems in a single large routine.
Find this by yourself by learning How to debug a Delphi program.
Pay atention to this parts:
Watches - you add a watch to track the values of program variables or expressions as you step over or trace into code.
Breakpoints - when pressing the F5 button or clicking on the left bar in your editor you can add a red line to your source. This line of source will have a breakpoint. When running the program, the execution will stop when it passes the source line. Now you can trace into your source by using some function keys.

Resources