commit 9c6fe6d76243606cdc88a4967c124474830debb6
parent e64ee92001449b9595d6847405aaa2f2621a18b5
Author: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Date: Mon, 25 Feb 2019 16:49:35 -0800
[skip travis] update paper
Diffstat:
4 files changed, 386 insertions(+), 19 deletions(-)
diff --git a/Paper/420_paper.pdf b/Paper/420_paper.pdf
Binary files differ.
diff --git a/Paper/420_paper.tex b/Paper/420_paper.tex
@@ -91,6 +91,11 @@
\usepackage[figure,table]{hypcap}
\fi
\usepackage{cleveref}
+\usepackage{tikz}
+\usetikzlibrary{dsp,chains}
+
+\DeclareMathAlphabet{\mathpzc}{OT1}{pzc}{m}{it}
+\newcommand{\z}{\mathpzc{z}}
\title{\papertitle}
@@ -138,11 +143,11 @@ the tape ($y$). Using the Karlqvist medium field approximation, we find
\begin{multline}
H_x(x,y) = \frac{1}{\pi} H_0 \Big(\tan^{-1} \Big(\frac{(g/2) + x}{y} \Big) \\
+ \tan^{-1} \Big(\frac{(g/2) - x}{y} \Big) \Big)
- \label{eq1}
+ \label{eq:H_x}
\end{multline}
\begin{equation}
H_y(x,y) = \frac{1}{2 \pi} H_0 \ln \Big(\frac{((g/2) - x)^2 + y^2}{((g/2) + x)^2 + y^2} \Big)
- \label{eq2}
+ \label{eq:H_y}
\end{equation}
%
where $g$ is the head gap, and $H_0$ is the deep gap field, given by:
@@ -219,7 +224,7 @@ The ideal playback voltage as a function of tape magnetisation is given by
\begin{equation}
V(x) = NWEv \mu_0 \int_{-\infty}^{\infty} dx' \int_{-\delta/2}^{\delta/2} dy' \vec{h}(x' + x, y') \cdot \frac{\vec{M}(x', y')}{dx}
- \label{eq11}
+ \label{eq:Vx}
\end{equation}
%
where $N$ is the number of turns of wire, $W$ is the width of the playhead, $E$ is the playhead
@@ -231,7 +236,7 @@ Note that $V(x) = V(vt)$ for constant $v$. $\vec{h}(x, y)$ is defined as:
\label{eq12}
\end{equation}
%
-where $\vec{H} (x, y)$ can be calculated by \cref{eq1,eq2}.
+where $\vec{H} (x, y)$ can be calculated by \cref{eq:H_x,eq:H_y}.
\subsubsection{Loss Effects}
There are several frequency-dependent loss effects associated with playback,
@@ -258,6 +263,7 @@ where $f$ is the frequency and $v$ is the tape speed.
For simplicity, let us assume,
\begin{equation}
\vec{H}(x,y,t) = \vec{H}(0,0,t)
+ \label{eq:spatialApprox}
\end{equation}
%
In this case $H_y \equiv 0$, and $H_x \equiv H_0$. Thus,
@@ -312,6 +318,7 @@ for $\hat{M}(n)$:
k_3 &= T f \Big(n- \frac{1}{2}, \hat{M}(n-1) + \frac{k_2}{2}, \hat{\vec{u}} \Big(n-\frac{1}{2} \Big) \Big)\\
k_4 &= T f \Big(n, \hat{M}(n-1) + k_3, \hat{\vec{u}}(n) \Big)\\
\hat{M}(n) &= \hat{M}(n-1) + \frac{k_1}{6} + \frac{k_2}{3} + \frac{k_3}{3} + \frac{k_4}{6}
+ \label{eq:Mn}
\end{split}
\end{align}
%
@@ -347,7 +354,7 @@ meter, the following plot shows the Magnetisation output.
\end{figure}
%
\subsection{Play Head}
-By combining \cref{eq11} with \cref{eq12,eq15}, we get:
+By combining \cref{eq:Vx} with \cref{eq12,eq15}, we get:
\begin{equation}
V(t) = NWEv \mu_0 g M(t)
\end{equation}
@@ -486,7 +493,7 @@ the pitch of the output signal. To characterize these
timing imperfections, we use a method similar to \cite{tapeDelay}:
We recorded a pulse train of 1000 pulses through a TC-260,
then recorded the pulses back from the tape. \Cref{timingSim}
-below shows a section of a superimposed plot of the original
+shows a section of a superimposed plot of the original
pulse train against the pulse train recorded from the tape
machine. From this data, we were able to generate a periodic
function that accurately models the timing imperfections of
@@ -503,22 +510,122 @@ signature "wow" effect of an analog tape machine.
%
\section{Real-Time Implementation}
-@TODO
-\subsection{Oversampling} %@TODO; move this section somewhere else
+We implemented our physical model of the Sony TC-260 as a
+VST audio plugin using the JUCE framework. \Cref{flowchart}
+shows the signal flow of the system in detail. We allow the user
+to control ``normal'' parameters including the tape speed,
+oversampling factor, bias frequency and bias gain.
+Other ``unrealistic'' parameters were added, including
+real-time control of gap width, tape thickness, tape spacing,
+and flutter depth. C/C++ code for the real-time implementation
+is available on GitHub
+\footnote{\url{https://github.com/jatinchowdhury18/AnalogTapeModel}}.
+
+\begin{figure*}[ht]
+ \center
+ \begin{tikzpicture}
+ \matrix (m1) [row sep=10mm, column sep=7.5mm]
+ {
+ &
+ &
+ \node[dspnodeopen,dsp/label=above] (b0) {Bias Signal}; &
+ &
+ &
+ &
+ &
+ \node[dspnodeopen,dsp/label=above] (b1) {Flutter ($\tau$)}; &
+ \node[dspnodeopen,dsp/label=above] (b2) {Tape Speed ($v$)}; \\
+ %---------------------------------------------------------------
+ \node[dspnodeopen,dsp/label=left] (x0) {$x[n]$}; &
+ \node[dspsquare] (x1) {\upsamplertext{M}}; &
+ \node[dspadder] (x2) {}; &
+ \node[dspfilter] (x3) {$H_{record}$}; &
+ \node[dspfilter] (x4) {Hysteresis}; &
+ \node[dspfilter] (x5) {De-bias}; &
+ \node[dspsquare] (x6) {\downsamplertext{M}}; &
+ \node[dspsquare] (x7) {$z^{-\tau}$}; &
+ \node[dspfilter] (x8) {$H_{play}(v)$}; &
+ \node[dspnodeopen,dsp/label=right] (x9) {$y[n]$}; \\
+ };
+ \draw[dspconn] (b0) -- (x2);
+ \draw[dspconn] (b1) -- (x7);
+ \draw[dspconn] (b2) -- (x8);
+ \foreach \i [evaluate = \i as \j using int(\i+1)] in {0,1,...,8}
+ \draw[dspconn] (x\i) -- (x\j);
+ \end{tikzpicture}
+ \caption{\label{flowchart}{\it Flowchart of realtime system:
+ M is the oversampling factor,
+ $H_{record}$
+ is the transfer function of the record
+ head, and
+ $H_{play}$ is the play head transfer
+ function including loss effects, and a
+ de-biasing filter.}}
+\end{figure*}
+%
+\subsection{Oversampling}
If no oversampling is used, the system will be unstable
for input signal at the Nyquist frequency, due to limitations
of the trapezoid rule derivate approximation used in \cref{eq:hDeriv}.
-To avoid this, a lowpass filter with cutoff frequency below Nyquist
-should suffice. However, due to aliasing caused by the nonlinearity
-of the tape hysteresis model, oversampling is necessary to mitigate
-aliasing artifacts \cite{Yeh}. Further, the system must be able to
-faithfully recreate not only the frequencies in the audible range
-but the bias frequencies as well. Since the minimum standard audio sampling
-rate is 44.1 kHz, and the minimum standard biasing frequency is approximately
-50 kHz \cite{Camras:1987:MRH:27189}, a minimum oversampling factor of 3x is
-required. In the real-time implementation, we use a minimum
-oversampling factor of 4x, with options to oversample at 8x or 16x
-if the user desires.
+To avoid this instability, early versions of the real-time
+implementation used a lowpass filter with cutoff frequency
+just below Nyquist. However, due to aliasing caused by the
+nonlinearity of the tape hysteresis model, oversampling is
+necessary to mitigate aliasing artifacts \cite{Yeh}. Further,
+the system must be able to faithfully recreate not only the
+frequencies in the audible range but the bias frequencies as
+well. Since the minimum standard audio sampling rate is 44.1
+kHz, and the minimum standard biasing frequency is approximately
+50 kHz \cite{Camras:1987:MRH:27189}, a minimum oversampling
+factor of 3x is required. In the real-time implementation,
+we use a minimum oversampling factor of 4x, with options to
+oversample at 8x or 16x if the user desires.
+
+\subsection{Performance}
+The performance of the real time system is heavily
+dependent on the oversampling factor. At an oversampling
+factor of 2x or 4x, the system operates with a reasonable
+CPU cost. At higher oversampling rates, the CPU cost quickly
+becomes unreasonably large compared to a typical VST plugin.
+
+\subsection{Results}
+In subjective testing, our physical model sounds quite convincing,
+with warm, tape-like distortion, and realistic sounding
+flutter. The high-frequency loss and low-frequency
+``head bump'' change correctly at different tape speeds,
+and are approximately within the frequency response
+specifications of the TC-260 service manual \cite{RefManual}.
+The distortion and frequency response characteristics
+of our model are subjectivelyvery close when compared to
+the output of an actual TC-260.
+The largest difference between the model and the physical
+machine is the subtle electrical and mechanical noises
+and dropouts present in the physical machine, presumably
+caused by the age and wear-and-tear of the machine, which
+we did not attempt to characterize in our model.
+\newline\newline
+% TODO: Generate plots and sound examples from real-time system
+
+\section{Future Improvements}
+\subsection{Spatial Magnetic Effects}
+The most obvious improvement to be made for the physical model
+is the inclusion of spatial effects of the tape. In particular,
+the approximation made in \cref{eq:spatialApprox}, negate any
+effects caused by magnetisation along the longitudinal length
+of the tape, and into the depth of the tape. Including spatial
+effects would involve deriving digital analogues for
+\cref{eq:H_x,eq:H_y,eq:Vx}, and re-deriving \cref{eq:Mn}
+to take an 2-dimensional magnetic field input per timestep,
+rather than the zero-dimensional input. This change
+would greatly increase the computational complexity of the system,
+since solving \cref{eq:Mn} currently dominates the computational
+complexity part of the system. Using an oversampling rate of 4x,
+with just 100 spatial samples, would be 400x more
+computationally complex than the current system.
+
+\section{Acknowledgements}
+Many thanks to Julius Smith for guidance and support, and
+thanks to Irene Abosch for kindly donating her Sony TC-260.
%\newpage
\nocite{*}
diff --git a/Paper/tikz-dsp.sty b/Paper/tikz-dsp.sty
@@ -0,0 +1,22 @@
+% -------------------------------------------------------------------------
+% This library for block diagrams and signal flow graphs was inspired by
+% the library "signalflow" of Dr. Karlheinz Ochs, Ruhr-University of Bochum,
+% Germany. Furthermore, some ideas were taken from the library "circuitikz"
+% of Massimo A. Redaelli and from the PGF library itself.
+%
+% Copyright 2012 by Matthias Hotz
+%
+% This work is licensed under the Creative Commons Attribution 2.5 Generic
+% License. To view a copy of this license, visit
+% http://creativecommons.org/licenses/by/2.5/
+% or send a letter to Creative Commons, 444 Castro Street, Suite 900,
+% Mountain View, California, 94041, USA.
+% -------------------------------------------------------------------------
+
+\NeedsTeXFormat{LaTeX2e}
+\RequirePackage{tikz}
+
+\def\tikzdspversion{0.1}
+\ProvidesPackage{tikz-dsp}[2012/09/07 The digital signal processing drawing package \tikzdspversion]
+
+\input{tikzlibrarydsp.code.tex}
diff --git a/Paper/tikzlibrarydsp.code.tex b/Paper/tikzlibrarydsp.code.tex
@@ -0,0 +1,238 @@
+% -------------------------------------------------------------------------
+% This library for block diagrams and signal flow graphs was inspired by
+% the library "signalflow" of Dr. Karlheinz Ochs, Ruhr-University of Bochum,
+% Germany. Furthermore, some ideas were taken from the library "circuitikz"
+% of Massimo A. Redaelli and from the PGF library itself.
+%
+% Copyright 2012 by Matthias Hotz
+%
+% This work is licensed under the Creative Commons Attribution 2.5 Generic
+% License. To view a copy of this license, visit
+% http://creativecommons.org/licenses/by/2.5/
+% or send a letter to Creative Commons, 444 Castro Street, Suite 900,
+% Mountain View, California, 94041, USA.
+% -------------------------------------------------------------------------
+
+\usetikzlibrary{arrows, calc, positioning, decorations.markings}
+
+% -------------------------------------------------------------------------
+% Parameters for the library
+
+\newcommand{\dsplinewidth}{0.25mm} % Line width for connections
+\newcommand{\dspblocklinewidth}{0.3mm} % Line width for blocks
+\newcommand{\dspoperatordiameter}{4mm} % Diameter for adder, multiplier, mixer
+\newcommand{\dspoperatorlabelspacing}{2mm} % Distance from symbol to label for adder, multiplier, mixer
+\newcommand{\dspnoderadius}{1mm} % Filled and empty node
+\newcommand{\dspsquareblocksize}{8mm} % Size for square blocks, e.g. for delay elements, decimator, expander
+\newcommand{\dspfilterwidth}{14mm} % Width of a filter block
+
+% -------------------------------------------------------------------------
+% Define new arrow heads
+
+\pgfarrowsdeclare{dsparrow}{dsparrow}
+{
+ \arrowsize=0.25pt
+ \advance\arrowsize by .5\pgflinewidth
+ \pgfarrowsleftextend{-4\arrowsize}
+ \pgfarrowsrightextend{4\arrowsize}
+}
+{
+ \arrowsize=0.25pt
+ \advance\arrowsize by .5\pgflinewidth
+ \pgfsetdash{}{0pt} % Solid line (do not dash)
+ \pgfsetmiterjoin % Fixed miter join of line
+ \pgfsetbuttcap % Fixed butt cap of line
+ \pgfpathmoveto{\pgfpoint{-4\arrowsize}{2.5\arrowsize}}
+ \pgfpathlineto{\pgfpoint{4\arrowsize}{0pt}}
+ \pgfpathlineto{\pgfpoint{-4\arrowsize}{-2.5\arrowsize}}
+ \pgfpathclose
+ \pgfusepathqfill
+}
+
+\pgfarrowsdeclare{dsparrowmid}{dsparrowmid}
+{
+ \arrowsize=0.25pt
+ \advance\arrowsize by .5\pgflinewidth
+ \pgfarrowsleftextend{-4\arrowsize}
+ \pgfarrowsrightextend{4\arrowsize}
+}
+{
+ \arrowsize=0.25pt
+ \advance\arrowsize by .5\pgflinewidth
+ \pgfsetdash{}{0pt}
+ \pgfsetmiterjoin
+ \pgfsetbuttcap
+ \pgfpathmoveto{\pgfpoint{0}{2.5\arrowsize}}
+ \pgfpathlineto{\pgfpoint{8\arrowsize}{0pt}}
+ \pgfpathlineto{\pgfpoint{0}{-2.5\arrowsize}}
+ \pgfpathclose
+ \pgfusepathqfill
+}
+
+% -------------------------------------------------------------------------
+% Define new node shapes
+
+\makeatletter
+
+\pgfkeys{/tikz/dsp/label/.initial=above}
+
+% Generic shape generator for operators, i.e. nodes with a circular
+% shape with an additional customizable drawing and a text label
+\long\def\dspdeclareoperator#1#2{
+ \pgfdeclareshape{#1}
+ {
+ % Saved anchors, macros and dimensions
+ \savedanchor\centerpoint{\pgfpointorigin}
+ \savedmacro\label{\def\label{\pgfkeysvalueof{/tikz/dsp/label}}}
+ \saveddimen\radius
+ {
+ \pgfmathsetlength\pgf@xa{\pgfshapeminwidth}
+ \pgfmathsetlength\pgf@ya{\pgfshapeminheight}
+ \ifdim\pgf@xa>\pgf@ya
+ \pgf@x=.5\pgf@xa
+ \else
+ \pgf@x=.5\pgf@ya
+ \fi
+ }
+
+ % Inherit all anchors from the 'circle'-shape:
+ \inheritanchor[from={circle}]{center}
+ \inheritanchor[from={circle}]{mid}
+ \inheritanchor[from={circle}]{base}
+ \inheritanchor[from={circle}]{north}
+ \inheritanchor[from={circle}]{south}
+ \inheritanchor[from={circle}]{west}
+ \inheritanchor[from={circle}]{east}
+ \inheritanchor[from={circle}]{mid west}
+ \inheritanchor[from={circle}]{mid east}
+ \inheritanchor[from={circle}]{base west}
+ \inheritanchor[from={circle}]{base east}
+ \inheritanchor[from={circle}]{north west}
+ \inheritanchor[from={circle}]{south west}
+ \inheritanchor[from={circle}]{north east}
+ \inheritanchor[from={circle}]{south east}
+ \inheritanchorborder[from={circle}]
+
+ % Draw circle and embed additional code
+ \backgroundpath
+ {
+ % Draw circle
+ \pgfpathcircle{\centerpoint}{\radius}
+
+ % Embed additional code
+ % (Note that this code must call e.g. \pgfusepathqstroke
+ #2
+ }
+
+ % Define anchor parametrized by the PGF key /tikz/dsp/label
+ \anchor{text}
+ {
+ \centerpoint
+ %
+ \def\templabelabove{above}
+ \def\templabelbelow{below}
+ \def\templabelleft{left}
+ \def\templabelright{right}
+ \pgfutil@tempdima=\dspoperatorlabelspacing
+ %
+ \ifx\label\templabelabove
+ \advance\pgf@x by -0.5\wd\pgfnodeparttextbox
+ \advance\pgf@y by \radius
+ \advance\pgf@y by \pgfutil@tempdima
+ \fi
+ %
+ \ifx\label\templabelbelow
+ \advance\pgf@x by -0.5\wd\pgfnodeparttextbox
+ \advance\pgf@y by -\radius
+ \advance\pgf@y by -\pgfutil@tempdima
+ \advance\pgf@y by -\ht\pgfnodeparttextbox
+ \fi
+ %
+ \ifx\label\templabelleft
+ \advance\pgf@x by -\radius
+ \advance\pgf@x by -\pgfutil@tempdima
+ \advance\pgf@x by -\wd\pgfnodeparttextbox
+ \advance\pgf@y by -0.5\ht\pgfnodeparttextbox
+ \advance\pgf@y by +0.5\dp\pgfnodeparttextbox
+ \fi
+ %
+ \ifx\label\templabelright
+ \advance\pgf@x by \radius
+ \advance\pgf@x by \pgfutil@tempdima
+ \advance\pgf@y by -0.5\ht\pgfnodeparttextbox
+ \advance\pgf@y by +0.5\dp\pgfnodeparttextbox
+ \fi
+ }
+ }
+}
+
+\dspdeclareoperator{dspshapecircle}{\pgfusepathqstroke}
+
+\dspdeclareoperator{dspshapecirclefull}{\pgfusepathqfillstroke}
+
+\dspdeclareoperator{dspshapeadder}{
+ % Coordinate offset for the plus
+ \pgfutil@tempdima=\radius
+ \pgfutil@tempdima=0.55\pgfutil@tempdima
+
+ % Draw plus
+ \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{0pt}{-\pgfutil@tempdima}}}
+ \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{0pt}{ \pgfutil@tempdima}}}
+
+ \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{-\pgfutil@tempdima}{0pt}}}
+ \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{ \pgfutil@tempdima}{0pt}}}
+
+ \pgfusepathqstroke
+}
+
+\dspdeclareoperator{dspshapemixer}{
+ % Coordinate offset for the cross
+ \pgfutil@tempdima=\radius
+ \pgfutil@tempdima=0.707106781\pgfutil@tempdima
+
+ % Draw cross
+ \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{-\pgfutil@tempdima}{-\pgfutil@tempdima}}}
+ \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{ \pgfutil@tempdima}{ \pgfutil@tempdima}}}
+
+ \pgfmoveto{\pgfpointadd{\centerpoint}{\pgfpoint{-\pgfutil@tempdima}{ \pgfutil@tempdima}}}
+ \pgflineto{\pgfpointadd{\centerpoint}{\pgfpoint{ \pgfutil@tempdima}{-\pgfutil@tempdima}}}
+
+ \pgfusepathqstroke
+}
+
+\makeatother
+
+% -------------------------------------------------------------------------
+% Define node styles
+
+\tikzset{dspadder/.style={shape=dspshapeadder,line cap=rect,line join=rect,
+ line width=\dspblocklinewidth,minimum size=\dspoperatordiameter}}
+\tikzset{dspmultiplier/.style={shape=dspshapecircle,line cap=rect,line join=rect,
+ line width=\dspblocklinewidth,minimum size=\dspoperatordiameter}}
+\tikzset{dspmixer/.style={shape=dspshapemixer,line cap=rect,line join=rect,
+ line width=\dspblocklinewidth,minimum size=\dspoperatordiameter}}
+
+\tikzset{dspnodeopen/.style={shape=dspshapecircle,line width=\dsplinewidth,minimum size=\dspnoderadius}}
+\tikzset{dspnodefull/.style={shape=dspshapecirclefull,line width=\dsplinewidth,fill,minimum size=\dspnoderadius}}
+
+% The fixed specification of text height and text depth is the somewhat
+% unaesthetic workaround to align the text in different node at the same
+% baseline. See the PGF/TikZ manual, ch. 5.1.
+\tikzset{dspsquare/.style={shape=rectangle,draw,align=center,text depth=0.3em,text height=1em,inner sep=0pt,
+ line cap=round,line join=round,line width=\dsplinewidth,minimum size=\dspsquareblocksize}}
+\tikzset{dspfilter/.style={shape=rectangle,draw,align=center,text depth=0.3em,text height=1em,inner sep=0pt,
+ line cap=round,line join=round,line width=\dsplinewidth,minimum height=\dspsquareblocksize,minimum width=\dspfilterwidth}}
+
+% -------------------------------------------------------------------------
+% Define "signal flow" lines
+
+\tikzset{dspline/.style={line width=\dsplinewidth},line cap=round,line join=round}
+\tikzset{dspconn/.style={->,>=dsparrow,line width=\dsplinewidth},line cap=round,line join=round}%line cap=rect,line join=miter}
+\tikzset{dspflow/.style={line width=\dsplinewidth,line cap=round,line join=round,
+ decoration={markings,mark=at position 0.5 with {\arrow{dsparrowmid}}},postaction={decorate}}}
+
+% -------------------------------------------------------------------------
+% Define various utility macros
+
+\newcommand{\downsamplertext}[1]{\raisebox{0.1em}{$\big\downarrow$}#1}
+\newcommand{\upsamplertext}[1]{\raisebox{0.1em}{$\big\uparrow$}#1}