diff options
Diffstat (limited to 'notebooks/signal_gen.ipynb')
-rw-r--r-- | notebooks/signal_gen.ipynb | 298 |
1 files changed, 298 insertions, 0 deletions
diff --git a/notebooks/signal_gen.ipynb b/notebooks/signal_gen.ipynb new file mode 100644 index 0000000..ea11ab0 --- /dev/null +++ b/notebooks/signal_gen.ipynb @@ -0,0 +1,298 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import struct\n", + "import random\n", + "import itertools\n", + "import datetime\n", + "import multiprocessing\n", + "from collections import defaultdict\n", + "import json\n", + "\n", + "from matplotlib import pyplot as plt\n", + "import matplotlib\n", + "import numpy as np\n", + "from scipy import signal as sig\n", + "from scipy import fftpack as fftpack\n", + "import ipywidgets\n", + "\n", + "import pydub\n", + "\n", + "from tqdm.notebook import tqdm\n", + "import colorednoise\n", + "\n", + "np.set_printoptions(linewidth=240)" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# From https://github.com/mubeta06/python/blob/master/signal_processing/sp/gold.py\n", + "preferred_pairs = {5:[[2],[1,2,3]], 6:[[5],[1,4,5]], 7:[[4],[4,5,6]],\n", + " 8:[[1,2,3,6,7],[1,2,7]], 9:[[5],[3,5,6]], \n", + " 10:[[2,5,9],[3,4,6,8,9]], 11:[[9],[3,6,9]]}\n", + "\n", + "def gen_gold(seq1, seq2):\n", + " gold = [seq1, seq2]\n", + " for shift in range(len(seq1)):\n", + " gold.append(seq1 ^ np.roll(seq2, -shift))\n", + " return gold\n", + "\n", + "def gold(n):\n", + " n = int(n)\n", + " if not n in preferred_pairs:\n", + " raise KeyError('preferred pairs for %s bits unknown' % str(n))\n", + " t0, t1 = preferred_pairs[n]\n", + " (seq0, _st0), (seq1, _st1) = sig.max_len_seq(n, taps=t0), sig.max_len_seq(n, taps=t1)\n", + " return gen_gold(seq0, seq1)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [], + "source": [ + "def modulate(data, nbits=5, pad=True):\n", + " # 0, 1 -> -1, 1\n", + " mask = np.array(gold(nbits))*2 - 1\n", + " \n", + " sel = mask[data>>1]\n", + " data_lsb_centered = ((data&1)*2 - 1)\n", + "\n", + " signal = (np.multiply(sel, np.tile(data_lsb_centered, (2**nbits-1, 1)).T).flatten() + 1) // 2\n", + " if pad:\n", + " return np.hstack([ np.zeros(len(mask)), signal, np.zeros(len(mask)) ])\n", + " else:\n", + " return signal" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [], + "source": [ + "def generate_noisy_signal(\n", + " test_duration=32,\n", + " test_nbits=5,\n", + " test_decimation=10,\n", + " test_signal_amplitude=200e-3,\n", + " noise_level=10e-3):\n", + "\n", + " #test_data = np.random.RandomState(seed=0).randint(0, 2 * (2**test_nbits), test_duration)\n", + " #test_data = np.array([0, 1, 2, 3] * 50)\n", + " test_data = np.array(range(test_duration))\n", + " signal = np.repeat(modulate(test_data, test_nbits, pad=False) * 2.0 - 1, test_decimation) * test_signal_amplitude\n", + " noise = colorednoise.powerlaw_psd_gaussian(1, len(signal)*2) * noise_level\n", + " noise[-int(1.5*len(signal)):][:len(signal)] += signal\n", + "\n", + " return noise+50\n", + " #with open(f'mains_sim_signals/dsss_test_noisy_padded.bin', 'wb') as f:\n", + " # for e in noise:\n", + " # f.write(struct.pack('<f', e))" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "c778037402024206b195a27591dc0b40", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7f2ab8cabca0>]" + ] + }, + "execution_count": 54, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(generate_noisy_signal())" + ] + }, + { + "cell_type": "code", + "execution_count": 58, + "metadata": {}, + "outputs": [], + "source": [ + "with open('data/ref_sig_audio_test3.bin', 'wb') as f:\n", + " for x in generate_noisy_signal():\n", + " f.write(struct.pack('f', x))" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "def synthesize_sine(freqs, freqs_sampling_rate=10.0, output_sampling_rate=44100):\n", + " duration = len(freqs) / freqs_sampling_rate # seconds\n", + " afreq_out = np.interp(np.linspace(0, duration, int(duration*output_sampling_rate)), np.linspace(0, duration, len(freqs)), freqs)\n", + " return np.sin(np.cumsum(2*np.pi * afreq_out / output_sampling_rate))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "test_sig = synthesize_sine(generate_noisy_signal())" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "5171d9dbbe5048e2b32c3cf7f7d03744", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "[<matplotlib.lines.Line2D at 0x7f2a90476bb0>]" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "fig, ax = plt.subplots()\n", + "ax.plot(test_sig[:44100])" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "metadata": {}, + "outputs": [], + "source": [ + "def save_signal_flac(filename, signal, sampling_rate=44100):\n", + " signal -= np.min(signal)\n", + " signal /= np.max(signal)\n", + " signal -= 0.5\n", + " signal *= 2**16 - 1\n", + " le_bytes = signal.astype(np.int16).tobytes()\n", + " seg = pydub.AudioSegment(data=le_bytes, sample_width=2, frame_rate=sampling_rate, channels=1)\n", + " seg.export(filename, format='flac')" + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [], + "source": [ + "save_signal_flac('synth_sig_test_0123_02.flac', synthesize_sine(generate_noisy_signal(), freqs_sampling_rate=10.0 * 100/128, output_sampling_rate=44100))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def emulate_adc_signal(adc_bits=12, adc_offset=0.4, adc_amplitude=0.25, freq_sampling_rate=10.0, output_sampling_rate=1000, **kwargs):\n", + " signal = synthesize_sine(generate_noisy_signal(), freq_sampling_rate, output_sampling_rate)\n", + " signal = signal*adc_amplitude + adc_offset\n", + " smin, smax = np.min(signal), np.max(signal)\n", + " if smin < 0.0 or smax > 1.0:\n", + " raise UserWarning('Amplitude or offset too large: Signal out of bounds with min/max [{smin}, {smax}] of ADC range')\n", + " signal *= 2**adc_bits -1\n", + " return signal" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "def save_adc_signal(fn, signal, dtype=np.uint16):\n", + " with open(fn, 'wb') as f:\n", + " f.write(signal.astype(dtype).tobytes())" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "save_adc_signal('emulated_adc_readings_01.bin', emulate_adc_signal(freq_sampling_rate=10.0 * 100/128))" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "labenv", + "language": "python", + "name": "labenv" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.3" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} |