Module:Harmonics in equal: Difference between revisions
Jump to navigation
Jump to search
Default number of columns set to 11. Cut off is now at 31 for prime, 23 for odd, and 12 for integer |
Enable collapsing |
||
| Line 18: | Line 18: | ||
end | end | ||
local function approx(steps, num, denom, intervals, title, prec, reduction) | local function approx(steps, num, denom, intervals, title, prec, reduction, collapsed) | ||
local thead | |||
if collapsed then | |||
thead = '{| class="wikitable center-all mw-collapsible mw-collapsed"\n' | |||
else | |||
thead = '{| class="wikitable center-all"\n' | |||
end | |||
local tpri = {'! colspan="2" | Harmonic '} | local tpri = {'! colspan="2" | Harmonic '} | ||
local tabs = {'! rowspan="2" | Error \n! absolute ([[cent|¢]]) '} | local tabs = {'! rowspan="2" | Error \n! absolute ([[cent|¢]]) '} | ||
local trel = {'! [[Relative interval error|relative]] (%) '} | local trel = {'! [[Relative interval error|relative]] (%) '} | ||
local tdeg | local tdeg | ||
if reduction then | if reduction then | ||
tdeg = {'! colspan="2" | Steps<br>([[ | tdeg = {'! colspan="2" | Steps<br>([[Octave reduction|reduced]])'} | ||
else | |||
tdeg = {'! colspan="2" | Step'} | |||
end | end | ||
local fmt_abs = string.format(' %%+.%df', prec) | local fmt_abs = string.format(' %%+.%df', prec) | ||
| Line 44: | Line 52: | ||
local titleMarkup = '' | local titleMarkup = '' | ||
if title then | if title then | ||
titleMarkup = '|-\n|+ ' .. title .. '\n' | titleMarkup = '|-\n|+style=white-space:nowrap| ' .. title .. '\n' | ||
end | end | ||
return | return thead .. | ||
titleMarkup .. | titleMarkup .. | ||
'|-\n' .. | '|-\n' .. | ||
| Line 99: | Line 107: | ||
-- option intervals | -- option intervals | ||
local select_intervals = "integer" | local select_intervals = "integer" | ||
local name = steps .. 'ed' .. num .. '/' .. denom | local name = steps .. 'ed' .. num .. '/' .. denom | ||
| Line 142: | Line 150: | ||
reduction = false | reduction = false | ||
end | end | ||
return approx( steps, num, denom, {unpack(intervals[select_intervals], start, start+columns-1)}, title, prec, reduction) | local collapsed = frame.args['collapsed'] | ||
return approx( steps, num, denom, {unpack(intervals[select_intervals], start, start+columns-1)}, title, prec, reduction, collapsed) | |||
end | end | ||
return p; | return p; | ||
Revision as of 11:01, 7 April 2023
- This module should not be invoked directly; use its corresponding template instead: Template:Harmonics in equal.
Calculates approximations for harmonics in equal-step tunings and present them in form of a table.
| Introspection summary for Module:Harmonics in equal | ||||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
| |||||||||
No function descriptions were provided. The Lua code may have further information.
local p = {}
-- direct mapping
local function map(p, steps, num, denom)
local s = math.log(p) / math.log(num/denom)
return math.floor(s*steps + .5)
end
-- check consistency for 9, 15 and 21
local function check_consistency(steps, num, denom)
local p3 = map(3, steps, num, denom)
local p5 = map(5, steps, num, denom)
local p7 = map(7, steps, num, denom)
local p9 = map(9, steps, num, denom)
local p15 = map(15, steps, num, denom)
local p21 = map(21, steps, num, denom)
return (p9 == 2*p3) and (p15 == p3+p5) and (p21 == p3+p7)
end
local function approx(steps, num, denom, intervals, title, prec, reduction, collapsed)
local thead
if collapsed then
thead = '{| class="wikitable center-all mw-collapsible mw-collapsed"\n'
else
thead = '{| class="wikitable center-all"\n'
end
local tpri = {'! colspan="2" | Harmonic '}
local tabs = {'! rowspan="2" | Error \n! absolute ([[cent|¢]]) '}
local trel = {'! [[Relative interval error|relative]] (%) '}
local tdeg
if reduction then
tdeg = {'! colspan="2" | Steps<br>([[Octave reduction|reduced]])'}
else
tdeg = {'! colspan="2" | Step'}
end
local fmt_abs = string.format(' %%+.%df', prec)
local fmt_rel = ' %+.0f'
local equave = math.log(num/denom) / math.log(2)
for _, p in pairs(intervals) do
s = math.log(p) / math.log(num/denom)
v = s*steps
ev = math.floor(v + .5)
table.insert(tpri, '' .. p)
table.insert(tabs, string.format(fmt_abs, 1200 * equave * (ev - v ) / steps))
table.insert(trel, string.format(fmt_rel, 100 * (ev - v)))
if reduction then
table.insert(tdeg, '' .. ev .. '<br>('.. ev % steps .. ')')
else
table.insert(tdeg, '' .. ev)
end
end
local titleMarkup = ''
if title then
titleMarkup = '|-\n|+style=white-space:nowrap| ' .. title .. '\n'
end
return thead ..
titleMarkup ..
'|-\n' ..
table.concat(tpri, '\n!') .. '\n' ..
'|-\n' ..
table.concat(tabs, '\n|') .. '\n' ..
'|-\n' ..
table.concat(trel, '\n|') .. '\n' ..
'|-\n' ..
table.concat(tdeg, '\n|') .. '\n' ..
'|}'
end
local intervals = {}
intervals.prime = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97 }
intervals.odd = {3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53 }
intervals.integer = {2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27}
-- evaluate input on error use default
local function eval_num_arg(input, def_value)
local result = input
if type(input) ~= 'number' then
result = def_value
if type(input) == 'string' then
input = input:match("^%s*(.-)%s*$")
if string.len(input) > 0 then
result = tonumber(input)
end
end
end
return result
end
-- calculate default precision
local function prec_by_equal(steps, num, denom)
return math.floor(math.log(steps*1.9*math.log(2)/math.log(num/denom))/math.log(10))
end
function p.harmonics_in_equal (frame)
-- optional number of steps, default: 12
local steps = eval_num_arg(frame.args['steps'], 12)
-- numerator, default: 2
local num = eval_num_arg(frame.args['num'], 2)
-- denominator, default: 1
local denom = eval_num_arg(frame.args['denom'], 1)
-- optional number of columns, default: 11
local columns = eval_num_arg(frame.args['columns'], 11)
-- optional start column, default: start with prime 2
local start = eval_num_arg(frame.args['start'], 1)
-- option intervals
local select_intervals = "integer"
local name = steps .. 'ed' .. num .. '/' .. denom
if denom == 1 then
if num == 2 then
name = steps .. 'edo'
select_intervals = "odd"
if check_consistency(steps, num, denom) then
-- select_intervals = "prime_no2"
select_intervals = "prime"
end
elseif num == 3 then
name = steps .. 'edt'
else
name = steps .. 'ed' .. num
end
end
if num == 3 and denom == 2 then
name = steps .. 'edf'
end
-- override default intervals
if frame.args['intervals'] and string.len(frame.args['intervals']) > 0 then
select_intervals = frame.args['intervals']
end
title_intervals = "prime harmonics"
if select_intervals == "odd" then
title_intervals = "odd harmonics"
elseif select_intervals == "integer" then
title_intervals = "harmonics"
end
local title = frame.args['title']
if title == nil or string.len(title) == 0 then
title = "Approximation of ".. title_intervals .. " in " .. name
end
-- optional precision for abs error, default about 3 digits
local prec = eval_num_arg(frame.args['prec'], prec_by_equal(steps, num, denom))
local reduction = true
if steps == 1 then
reduction = false
end
local collapsed = frame.args['collapsed']
return approx( steps, num, denom, {unpack(intervals[select_intervals], start, start+columns-1)}, title, prec, reduction, collapsed)
end
return p;