Search code examples
pythonnumpymathscipylogarithm

How to create spacing of points per decade for logarithmic plot


Intro

I have some range of frequencies that goes from freq_start_hz = X to freq_stop_hz = Y.

I am trying to logarithmically (base 10) space out samples between the range [freq_start_hz, freq_stop_hz], based on a number of samples per decade (num_samp_per_decade), inclusive of the endpoint.

I noticed numpy has a method logspace (link) which enables you to create logarithmic divisions of some range base ** start to base ** stop based on a total number of samples, num.

Can you help me create Python code that will create even logarithmic spacing per decade?

Example

freq_start_hz = 10, freq_stop_hz = 100, num_samp_per_decade = 5

This is easy, since it's just one decade. So one could create it using the following:

import numpy as np
from math import log10


freq_start_hz = 10
freq_stop_hz = 100
num_samp_per_decade = 5

freq_list = np.logspace(
    start=log10(freq_start_hz), 
    stop=log10(freq_stop_hz), 
    num=num_samp_per_decade, 
    endpoint=False,
    base=10,
)
freq_list = np.append(freq_list, freq_stop_hz)  # Appending end
print(freq_list.tolist())

Output is [10.0, 17.78279410038923, 31.622776601683793, 56.23413251903491, 100.0]

Note: this worked nicely because I designed it this way. If freq_start_hz = 8, this method no longer works since it now spans multiple decades.

Conclusion

I am hoping somewhere out there, there's a premade method in math, numpy, another scipy library, or some other library that my internet searching hasn't turned up.


Solution

  • Calculate the number of points based on the number of decades in the range.

    from math import log10
    import numpy as np
    
    start = 10
    end = 1500
    samples_per_decade = 5
    
    ndecades = log10(end) - log10(start)
    npoints = int(ndecades) * samples_per_decade
    #a = np.linspace(log10(start), log10(end), num = npoints)
    #points = np.power(10, a)
    points = np.logspace(log10(start), log10(end), num=npoints, endpoint=True, base=10)
    print(points)