Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Numpyless #1

Merged
merged 4 commits into from
Oct 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ pip install .
Note that on some systems the command is `pip3` instead of `pip`.

## Requirements
This library requires Python 3.6 or newer, and both `numpy` and `matplotlib`.
This library requires Python 3.6 or newer. For plotting configurations with the commandline tool `plotcamillaconf`, it also requires `numpy` and `matplotlib`. These are not required for using only with the web interface.

These are the names of the packages needed:
| Distribution | python | numpy | matplotlib |
| Distribution | python | numpy (optional) | matplotlib (optional) |
|--------------|--------|-------|------------|
| Fedora | python3 | python3-numpy | python3-matplotlib |
| Debian/Raspbian | python3 | python3-numpy | python3-matplotlib |
Expand All @@ -30,8 +30,11 @@ On macOS use either Anaconda or Homebrew. The Anaconda procedure is the same as

For Homebrew, install Python with `brew install python`, after which you can install the needed packages with pip, `pip3 install numpy` etc.

## Plotting a configuration
This library provides the console command `plotcamillaconf`. Once the library is installed, the command should be available in your terminal.



## Plotting a configuration from the command line
This library provides the console command `plotcamillaconf`. Once the library is installed, togehter with the optional dependencies numpy and matplotlib, the command should be available in your terminal.
To use it type:
```sh
plotcamillaconf /path/to/some/config.yml
Expand All @@ -40,7 +43,7 @@ plotcamillaconf /path/to/some/config.yml
This will plot the frequency response of all the defined filters, and show a block diagram of the pipeline.


## Evaluating filters
## Plotting filters
To plot the frequency response of a filter, use the function `plot_filter`. This is mostly meant for internal use by the `plotcamillaconf` command.
```python
plot_filter(filterconf, name=None, samplerate=44100, npoints=1000, toimage=False)
Expand All @@ -51,7 +54,7 @@ It's also possible to plot the combined frequency response of a Filter step in t
```python
plot_filterstep(conf, pipelineindex, name="filterstep", npoints=1000, toimage=False)
```
This command takes the full configuration as `conf` must be provided. This will plot the step with index `pipelineindex` in the pipeline where 0 is the first step. The `name` is used for the plot title. The number of points in the plot is set with `npoints`. If `toimage` is set to True, then it will instead return the plot as an svg image.
This command takes a full configuration as `conf`. It will then plot the step with index `pipelineindex` in the pipeline where 0 is the first step. The `name` is used for the plot title. The number of points in the plot is set with `npoints`. If `toimage` is set to True, then it will instead return the plot as an svg image.

## Plotting the pipeline
To plot a block diagram of the pipeline, use the function `plot_pipeline`. This is mostly meant for internal use by the `plotcamillaconf` command.
Expand All @@ -60,3 +63,16 @@ plot_pipeline(conf, toimage=False)
```
This takes a full CamillaDSP configuration, `conf`. It will then plot the pipeline using PyPlot. If `toimage` is set to True, then it will instead return the plot as an svg image.

## Evaluating filters
To evaluate the frequency response of a filter, use the function `eval_filter`. This is mostly meant for internal use by the `plotcamillaconf` command as well as the web gui.
```python
eval_filter(filterconf, name=None, samplerate=44100, npoints=1000)
```
This will evaluate the filter and return the result as a dictionary. The filter configuration `filterconf` must be provided. The `samplerate` defaults to 44100 if not given. The filter `name` is used for labels. The number of points in the plot is set with `npoints`. The contents of the returned dictionary depends on the filter type. A Biquad returns `name`, `samplerate`, `f`, `magnitude` and `phase`. A Conv filter additionally return the impulse response in `time` and `impulse`.

It's also possible to evaluate the combined frequency response of a Filter step in the pipeline.
```python
eval_filterstep(conf, pipelineindex, name="filterstep", npoints=1000)
```
This command takes a full configuration as `conf`. It will evaluate the step with index `pipelineindex` in the pipeline where 0 is the first step. As for eval_filter, the result is returned as a dictionary with the same fields as for a Biquad.

1 change: 1 addition & 0 deletions camilladsp_plot/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from camilladsp_plot.plot_filters import plot_filters, plot_filter, plot_filterstep, plot_all_filtersteps
from camilladsp_plot.plot_pipeline import plot_pipeline
from camilladsp_plot.eval_filterconfig import eval_filter, eval_filterstep
29 changes: 29 additions & 0 deletions camilladsp_plot/cooley_tukey.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Adapted from https://jeremykun.com/2012/07/18/the-fast-fourier-transform/
import cmath
import math

def omega(p, q):
return cmath.exp((2.0 * cmath.pi * 1j * q) / p)

def _fft(signal):
n = len(signal)
if n == 1:
return signal
else:
Feven = _fft([signal[i] for i in range(0, n, 2)])
Fodd = _fft([signal[i] for i in range(1, n, 2)])

combined = [0] * n
for m in range(int(n/2)):
combined[m] = Feven[m] + omega(n, -m) * Fodd[m]
combined[m + int(n/2)] = Feven[m] - omega(n, -m) * Fodd[m]

return combined

def fft(signal):
orig_len = len(signal)
fft_len = 2**(math.ceil(math.log2(orig_len)))
for _n in range(fft_len-orig_len):
signal.append(0.0)
fftsig = _fft(signal)
return fftsig
72 changes: 72 additions & 0 deletions camilladsp_plot/eval_filterconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import math
import cmath
from camilladsp_plot.filters import Biquad, BiquadCombo, Conv, DiffEq, Gain


def logspace(minval, maxval, npoints):
logmin = math.log10(minval)
logmax = math.log10(maxval)
perstep = (logmax-logmin)/npoints
values = [10.0**(logmin+n*perstep) for n in range(npoints)]
return values

def eval_filter(filterconf, name=None, samplerate=44100, npoints=1000):
fvect = logspace(1.0, samplerate*0.95/2.0, npoints)
if name is None:
name = "unnamed {}".format(filterconf['type'])
result = {"name": name, "samplerate": samplerate, "f": fvect }
if filterconf['type'] in ('Biquad', 'DiffEq', 'BiquadCombo'):
if filterconf['type'] == 'DiffEq':
currfilt = DiffEq(filterconf['parameters'], samplerate)
elif filterconf['type'] == 'BiquadCombo':
currfilt = BiquadCombo(filterconf['parameters'], samplerate)
else:
currfilt = Biquad(filterconf['parameters'], samplerate)

_fplot, magn, phase = currfilt.gain_and_phase(fvect)
result["magnitude"] = magn
result["phase"] = phase
elif filterconf['type'] == 'Conv':
if 'parameters' in filterconf:
currfilt = Conv(filterconf['parameters'], samplerate)
else:
currfilt = Conv(None, samplerate)
_ftemp, magn, phase = currfilt.gain_and_phase(fvect)
t, impulse = currfilt.get_impulse()
result["magnitude"] = magn
result["phase"] = phase
result["time"] = t
result["impulse"] = impulse
return result

def eval_filterstep(conf, pipelineindex, name="filterstep", npoints=1000, toimage=False):

samplerate = conf['devices']['samplerate']
fvect = logspace(1.0, samplerate*0.95/2.0, npoints)
pipelinestep = conf['pipeline'][pipelineindex]
totcgain=[1.0 for n in range(npoints)]
for filt in pipelinestep['names']:
filterconf = conf['filters'][filt]
if filterconf['type'] == 'DiffEq':
currfilt = DiffEq(filterconf['parameters'], samplerate)
elif filterconf['type'] == 'BiquadCombo':
currfilt = BiquadCombo(filterconf['parameters'], samplerate)
elif filterconf['type'] == "Biquad":
currfilt = Biquad(filterconf['parameters'], samplerate)
elif filterconf['type'] == "Conv":
currfilt = Conv(filterconf['parameters'], samplerate)
elif filterconf['type'] == "Gain":
currfilt = Gain(filterconf['parameters'])
else:
continue
_, cgainstep = currfilt.complex_gain(fvect)
totcgain = [cg * cgstep for (cg, cgstep) in zip(totcgain, cgainstep)]
gain = [20.0 * math.log10(abs(cg) + 1e-15) for cg in totcgain]
phase = [180 / math.pi * cmath.phase(cg) for cg in totcgain]
result = {"name": name, "samplerate": samplerate, "f": fvect, "magnitude": gain, "phase": phase}
return result





Loading