AnalogTapeModel

Physical modelling signal processing for analog tape recording
Log | Files | Refs | Submodules | README | LICENSE

commit bd4576d6e9bc32a279c60756c97c3b6d358720f8
parent 838348f9cd78b3e6a0d3649a910ad04b3f4547cf
Author: jatinchowdhury18 <jatinchowdhury18@gmail.com>
Date:   Sun, 15 Nov 2020 12:39:25 -0800

Add official user manual (#108)

* Update manual

* Update manual with screenshots

Co-authored-by: jatinchowdhury18 <jatinchowdhury18@users.noreply.github.com>
Diffstat:
M.gitignore | 2+-
MManual/ChowTapeManual.pdf | 0
MManual/ChowTapeManual.tex | 208++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
MManual/manual.cls | 7++++---
MPlugin/CHOWTapeModel.jucer | 4++++
APlugin/Screenshots/CHEW.png | 0
APlugin/Screenshots/Degrade.png | 0
APlugin/Screenshots/Filters.png | 0
APlugin/Screenshots/Flutter.png | 0
APlugin/Screenshots/Gain.png | 0
APlugin/Screenshots/Loss.png | 0
APlugin/Screenshots/Tape.png | 0
APlugin/Screenshots/Tone.png | 0
APlugin/Screenshots/Wow.png | 0
APlugin/Screenshots/full_gui.png | 0
APlugin/Source/GUI/ScreenshotHelper.cpp | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
APlugin/Source/GUI/ScreenshotHelper.h | 27+++++++++++++++++++++++++++
MPlugin/Source/PluginProcessor.cpp | 5+++++
DPlugin/screenshot.png | 0
ASimulations/Hysteresis/bias.png | 0
ASimulations/Hysteresis/drive.png | 0
ASimulations/Hysteresis/hysteresis2.py | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
ASimulations/Hysteresis/sat.png | 0
ASimulations/Hysteresis/space_loss.png | 0
ASimulations/Hysteresis/speed_thickness.png | 0
MSimulations/LossEffects/loss_effects2.py | 60+++++++++++++++++++++++++++++++++++++-----------------------
ASimulations/LossEffects/space_loss.png | 0
ASimulations/LossEffects/speed_thickness.png | 0
28 files changed, 415 insertions(+), 56 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -2,7 +2,7 @@ Refs # Tex artifacts -*.synctex.gz* +*.synctex* *.aux *.bbl *.blg diff --git a/Manual/ChowTapeManual.pdf b/Manual/ChowTapeManual.pdf Binary files differ. diff --git a/Manual/ChowTapeManual.tex b/Manual/ChowTapeManual.tex @@ -38,11 +38,15 @@ Linux users may download builds from the \begin{figure}[ht] \center - \includegraphics[width=0.55\columnwidth]{../Refs/Pictures/sony_tc-260.jpg} + \includegraphics[width=0.45\columnwidth]{../Refs/Pictures/sony_tc-260.jpg} \caption{\label{TapeMachine}{\it A Sony TC 260 reel-to-reel tape machine}} \end{figure} -% @TODO: figures for controls... +\begin{figure}[ht] + \center + \includegraphics[width=0.6\columnwidth]{../Plugin/Screenshots/full_gui.png} + \caption{\label{h_bias}{\it ChowTape User Interface}} +\end{figure} \subsection{Controls} ChowTape contains a wide range of controls allowing the @@ -55,9 +59,8 @@ results than would be possible with a physical tape machine. \boldtheme{Input Gain} controls the gain level going into the rest of the plugin. Note that abnormally large levels can cause the plugin to become unstable, so it is recommended -that your levels are below unity gain going into the plugin, -and any extra gain you wish to add should come from the input -gain control. %@TODO: more notes on stability +that sound levels are below unity gain going into the plugin, +and any extra gain should come from the input gain control. %@TODO: more notes on stability \newpar \boldtheme{Dry/Wet} allows the user to choose how much of the signal they want to the plugin's processing to affect. @@ -68,21 +71,105 @@ signal they want to the plugin's processing to affect. being done internally within the plugin. More oversampling will result in a higher quality sound with fewer aliasing artifacts and better noise characteristics, but will also -use more of your CPU. It is recommended to use as much -oversampling as your CPU will allow. +use more CPU. It is recommended to use as much oversampling +as your CPU will allow. \newpar \boldtheme{Mix Group}: When using ChowTape on multiple channels -in your mix, you can synchronize parameters between plugin +in a mix, you can synchronize parameters between plugin instances belonging to the same mix group. Essentially, all the plugin instances in the same mix group will share the same parameters. +\begin{figure}[ht] + \center + \includegraphics[height=0.32\paperheight]{../Plugin/Screenshots/Filters.png} + \caption{\label{h_bias}{\it Input filter controls}} +\end{figure} + +\subsubsection{Input Filter Controls} +The ChowTape input filters apply a low-cut and high-cut filter +to the input signal before it is passed on to the rest of the +plugin. The \boldtheme{Low Cut} and \boldtheme{High Cut} knobs +control the cutoff frequencies of the two filters. The +\boldtheme{Makeup} control allows the signal cut out by the +input filters to be added back to the output of the plugin. +This can be useful for allowing sub-bass frequencies to pass +through the plugin unaffected. + +\begin{figure}[ht] + \center + \includegraphics[height=0.35\paperheight]{../Plugin/Screenshots/Tape.png} + \caption{\label{h_bias}{\it Tape hysteresis controls}} +\end{figure} +% +% \begin{figure}[ht] +% \center +% \includegraphics[width=0.9\columnwidth]{../Simulations/Hysteresis/drive.png} +% \caption{\label{h_drive}{\it Hysteresis curves with varying drive}} +% \end{figure} +% +\begin{figure}[ht] + \center + \includegraphics[width=0.85\columnwidth]{../Simulations/Hysteresis/sat.png} + \caption{\label{h_sat}{\it Hysteresis curves with varying saturation}} +\end{figure} +% +\begin{figure}[] + \center + \includegraphics[width=0.85\columnwidth]{../Simulations/Hysteresis/bias.png} + \caption{\label{h_bias}{\it Hysteresis curves with varying bias}} +\end{figure} + \subsubsection{Hysteresis Controls} -@TODO -\boldtheme{Hysteresis Mode} -\boldtheme{Drive} -\boldtheme{Saturation} -\boldtheme{Bias} +The hysteresis processing is the most important section of the +plugin. \href{https://en.wikipedia.org/wiki/Hysteresis}{Hysteresis} +is a complex nonlinear phenomenon that describes many +natural processes in physics, biology, economics, and more. +In particular, magnetic hysteresis describes the process by +which tape becomes magnetised when subjected to a strong magnetic +field. ChowTape emulates magnetic hysteresis, using the +Jiles-Atherton\footnote{Jiles, D.C.; Atherton, D.L. (1984) ``Theory of ferromagnetic hysteresis'' \textit{Journal of Applied Physics}.} +model of magnetic hysteresis. Magnetic hysteresis is largely +responsible for the ``warm'' sound often associated with +analog tape distortion. +\newpar +\boldtheme{Drive} controls the level of amplification done by +the hysteresis process. This differs from the input gain in that +it affects the nonlinear characteristic of the hysteresis process. +\newpar +\boldtheme{Saturation} controls the level at which the hysteresis +function saturates. Higher values correspond to a lower Saturation +point, resulting in a more distorted sound. +\newpar +\boldtheme{Bias} controls the amount of bias used by the tape +recorder. Tape bias is the addition of an inaudible high-frequency +signal to the audio signal\footnote{\href{https://hccc.org.uk/acbias.html}{More information on tape biasing}}. +At lower bias levels, the hysteresis curve becomes ``wider'', +thus creating the ``deadzone'' effect often associated with +underbiased tape. +\newpar +\boldtheme{Hysteresis Mode} selects the equation solver used +to solve the Jiles-Atherton equation in real time. ChowTape +currently supports the following hysteresis modes: +\renewcommand{\labelitemi}{\textendash} +\begin{itemize} + \itemsep-1mm + \item 2nd-order Runge Kutta (RK2) + \item 4th-order Runge Kutta (RK4) + \item 4-iteration Newton Raphson (NR4) + \item 8-iteration Newton Raphson (NR8) + \item Version 1.0 processing (V1) +\end{itemize} +% +The Runge-Kutta solvers are computationally cheaper, but +somewhat less accurate than the Newton-Raphson solvers. +Similarly, the higher-order solvers will be more accurate, +but will also consume more compute resources. The V1 mode +reverts to a different parameterization of the hysteresis +equation that was used in earlier versions of the plugin. It +is recommended to use higher-order solvers for mix busses +and key tracks in a mix, while using lower-order solvers for +less important tracks. \subsubsection{Tone Controls} The tone section applies a set of pre-/post-emphasis filters @@ -98,6 +185,24 @@ post-emphasis filter will automatically adjust. The \boldtheme{Frequency} knob controls the transition frequency between the bass and treble sections of the filter. +\begin{figure}[ht] + \center + \includegraphics[height=0.32\paperheight]{../Plugin/Screenshots/Loss.png} + \caption{\label{h_bias}{\it Loss filter controls}} +\end{figure} +% +\begin{figure}[ht] + \center + \includegraphics[width=0.85\columnwidth]{../Simulations/LossEffects/space_loss.png} + \caption{\label{spacing_loss}{\it Spacing loss at 7.5 ips}} +\end{figure} +% +\begin{figure}[ht] + \center + \includegraphics[width=0.85\columnwidth]{../Simulations/LossEffects/speed_thickness.png} + \caption{\label{thick_loss}{\it Thickness loss for 5 micron tape}} +\end{figure} + \subsubsection{Playhead Controls} Physical tape machines also have a frequency response that is affected by the amount of space between the playhead and @@ -120,39 +225,84 @@ controls the tape speed as it effects the above loss effects, measured in inches per second (ips). While this control is continuous, standard tape speeds are 7.5, 15, and 30 ips. + \subsubsection{Tape Degradation Controls} The degradation parameters control a simulation of old, degraded -tape. -\newpar -\boldtheme{Depth} and \boldtheme{Amount} control the amount of -degradation that is added to the tape, while \boldtheme{Variance} +tape. \boldtheme{Depth} and \boldtheme{Amount} control the amount +of degradation that is added to the tape, while \boldtheme{Variance} adds a time-varying randomness to the degradatation. \subsubsection{Chew Controls} The chew parameters simulate tape that has been chewed up by -a broken tape machine. -\newpar -\boldtheme{Depth} controls how deep the tape is chewed; -\newpar -\boldtheme{Frequency} controls how much space there is between -bits of tape that have been chewed up. +a broken tape machine. \boldtheme{Depth} controls how deep the +tape is chewed, \boldtheme{Frequency} controls how much space +there is between bits of tape that have been chewed up, and +\boldtheme{Variance} determines how much randomness there is +in determining the amount of space between chewed up sections. \subsubsection{Wow and Flutter Controls} Tape machines also exhibit timing irregularities, often due to small imperfections in the mechanics of the machine causing the tape to subtly speed up and slow down while being played back. The flutter characteristic in this plugin was -measured from an original Sony TC-260 tape machine. +captured from an original Sony TC-260 tape machine. \newpar \boldtheme{Rate} controls the rate of flutter, with higher values -causing the flutter to occur faster. -\newpar -\boldtheme{Depth} controls the depth of the flutter, with 0 meaning -that no flutter is occuring, and higher values making the flutter -more noticeable. +causing the flutter to occur faster. \boldtheme{Depth} controls the +depth of the flutter, with 0 meaning that no flutter is occuring, and +higher values making the flutter more noticeable. \newpar "\boldtheme{Wow}" is similar to flutter but on a much longer time scale, and contains similar controls. +\subsection{Presets} +Presets provide a quick way to achieve a specific sound +with the plugin. ChowTape comes with a set of built-in +factory presets. To contribute your presets to be added +to the factory presets list for future releases, see the +\href{https://github.com/jatinchowdhury18/AnalogTapeModel/issues/30}{Presets GitHub issue}. + +\subsubsection{User Presets} +To save the current plugin state as a user preset, open +the presets menu, and select ``Save''. The first time a +preset is saved, you will be asked to choose a preset +folder. All future presets will be saved to this folder, +and when the plugin opens, it will search this folder, as +well as any subfolders, to load new user presets. +Presets located in subfolders will be placed in their +own groups in the preset menu. + +\subsection{Open Source} +ChowTape is open-source software that is free (as in ``free +beer''), and free (as in ``free speech''), under the +\href{https://www.gnu.org/licenses/gpl-3.0}{General Public License}. +As a research project, the goal of developing this plugin is +to help advance the body of knowledge of real-time audio +signal processing. Therefore, keeping any part of this project +behind a paywall, or licensing this software under a proprietary +license would be antithetical to that goal. As an open-source +project, ChowTape is open to outside contributors. For more +information, see our +\href{https://github.com/jatinchowdhury18/AnalogTapeModel/blob/master/CONTRIBUTING.md}{Contributing} +page. +\newpar + +\subsection{Feedback} +If you notice any bugs, or have any questions, feel free +to \href{mailto:jatin@ccrma.stanford.edu}{email me directly}, +or \href{https://github.com/jatinchowdhury18/AnalogTapeModel/issues}{create an issue ticket} +on GitHub. GitHub issues are preferred, since they are publicly +visible. + +\subsection{Acknowledgements} +Thanks to Yann for helping to write this user manual, +as well as all the users of ChowTape who have made +efforts to help improve the plugin. +\newpar +Enjoy! +\newpar +Jatin Chowdhury +\newpar +\href{https://github.com/jatinchowdhury18/AnalogTapeModel}{https://github.com/jatinchowdhury18/AnalogTapeModel} \end{document} diff --git a/Manual/manual.cls b/Manual/manual.cls @@ -12,6 +12,8 @@ % Manage spacing \def\newpar{\newline\newline} +\usepackage[skip=2.5pt]{caption} +\setlength{\belowcaptionskip}{-12pt} % Needed to manage fonts \RequirePackage[default,opentype]{sourcesanspro} @@ -46,13 +48,12 @@ % fancy footer \usepackage{fancyhdr} -\usepackage[bottom]{footmisc} +\usepackage[bottom,flushmargin]{footmisc} \pagestyle{fancy} \fancyhf{} -\fancyfoot[RO]{\color{gray}\textbf{\@pluginname} Plugin User Manual \textasciitilde \thepage/{\the\numexpr\value{page}+1\relax}} +\fancyfoot[RO]{\color{gray}\textbf{\@pluginname} Plugin User Manual \textasciitilde \ {\the\numexpr2*\value{page}-1\relax}/{\the\numexpr2*\value{page}\relax}} \renewcommand{\headrulewidth}{0pt} \renewcommand{\footrulewidth}{1pt} \def\footrule{{\if@fancyplain\let\footrulewidth\plainfootrulewidth\fi - % \vskip-\footruleskip\vskip-\footrulewidth \leavevmode\rlap{\color{theme}\rule{\textwidth}{\footrulewidth}} \vskip\footruleskip}} diff --git a/Plugin/CHOWTapeModel.jucer b/Plugin/CHOWTapeModel.jucer @@ -28,6 +28,10 @@ <FILE id="YzAgWK" name="MixGroupViz.h" compile="0" resource="0" file="Source/GUI/MixGroupViz.h"/> <FILE id="IgOtsG" name="MyLNF.cpp" compile="1" resource="0" file="Source/GUI/MyLNF.cpp"/> <FILE id="pj6eEc" name="MyLNF.h" compile="0" resource="0" file="Source/GUI/MyLNF.h"/> + <FILE id="Y0Fi0f" name="ScreenshotHelper.cpp" compile="1" resource="0" + file="Source/GUI/ScreenshotHelper.cpp"/> + <FILE id="Vw0Q80" name="ScreenshotHelper.h" compile="0" resource="0" + file="Source/GUI/ScreenshotHelper.h"/> <FILE id="yy3bQ7" name="TapeScope.cpp" compile="1" resource="0" file="Source/GUI/TapeScope.cpp"/> <FILE id="zDg8Lf" name="TapeScope.h" compile="0" resource="0" file="Source/GUI/TapeScope.h"/> <FILE id="WfCYvA" name="TitleComp.cpp" compile="1" resource="0" file="Source/GUI/TitleComp.cpp"/> diff --git a/Plugin/Screenshots/CHEW.png b/Plugin/Screenshots/CHEW.png Binary files differ. diff --git a/Plugin/Screenshots/Degrade.png b/Plugin/Screenshots/Degrade.png Binary files differ. diff --git a/Plugin/Screenshots/Filters.png b/Plugin/Screenshots/Filters.png Binary files differ. diff --git a/Plugin/Screenshots/Flutter.png b/Plugin/Screenshots/Flutter.png Binary files differ. diff --git a/Plugin/Screenshots/Gain.png b/Plugin/Screenshots/Gain.png Binary files differ. diff --git a/Plugin/Screenshots/Loss.png b/Plugin/Screenshots/Loss.png Binary files differ. diff --git a/Plugin/Screenshots/Tape.png b/Plugin/Screenshots/Tape.png Binary files differ. diff --git a/Plugin/Screenshots/Tone.png b/Plugin/Screenshots/Tone.png Binary files differ. diff --git a/Plugin/Screenshots/Wow.png b/Plugin/Screenshots/Wow.png Binary files differ. diff --git a/Plugin/Screenshots/full_gui.png b/Plugin/Screenshots/full_gui.png Binary files differ. diff --git a/Plugin/Source/GUI/ScreenshotHelper.cpp b/Plugin/Source/GUI/ScreenshotHelper.cpp @@ -0,0 +1,101 @@ +#include "ScreenshotHelper.h" + +#ifdef TAKE_SCREENSHOTS + +namespace ScreenshotHelper +{ + +/** + * Process audio through the plugin so the screenshots have + * some signal show up in the meters and scopes. + */ +void processAudio (ChowtapeModelAudioProcessor* plugin) +{ + constexpr double fs = 48000.0; + constexpr int blockSize = 1024; + constexpr float freq = 200.0f; + + AudioBuffer<float> buffer (2, blockSize); + for (int ch = 0; ch < 2; ++ch) + { + auto* data = buffer.getWritePointer (ch); + for (int n = 0; n < blockSize; ++n) + data[n] = -0.7f * std::cos (MathConstants<float>::twoPi * freq * (float) n / (float) fs); + } + + plugin->prepareToPlay (fs, blockSize); + + MidiBuffer midi; + plugin->processBlock (buffer, midi); +} + +void findTabbedComponents (Component* root, Array<foleys::Container*>& tabbedComps) +{ + if (root == nullptr) + return; + + for (auto child : root->getChildren()) + { + if (auto tabbedComponent = dynamic_cast<foleys::Container*> (child)) + { + if (tabbedComponent->layout == foleys::Container::Layout::Tabbed) + tabbedComps.add (tabbedComponent); + } + + findTabbedComponents (child, tabbedComps); + } +} + +void screenshotTab (foleys::Container* container, int tabIdx) +{ + container->tabbedButtons->setCurrentTabIndex (tabIdx); + auto name = container->tabbedButtons->getTabButton (tabIdx)->getName(); + + int index = 0; + for (auto& child : container->children) + child->setVisible (tabIdx == index++); + + screenshotForBounds (container, container->getLocalBounds(), name + ".png"); +} + +void takeScreenshots (std::unique_ptr<ChowtapeModelAudioProcessor> plugin) +{ + processAudio (plugin.get()); + std::unique_ptr<AudioProcessorEditor> editor (plugin->createEditor()); + + // full screenshot + screenshotForBounds (editor.get(), editor->getLocalBounds(), "full_gui.png"); + + // get tabbed components + Array<foleys::Container*> tabbedComps; + findTabbedComponents (editor.get(), tabbedComps); + + for (auto c : tabbedComps) + for (int i = 0; i < c->tabbedButtons->getNumTabs(); ++i) + screenshotTab (c, i); +} + +File getScreenshotFolder() +{ + return File ("D:/Documents/CCRMA/Music 420/AnalogTapeModel/Plugin/Screenshots"); +} + +void screenshotForBounds (Component* editor, Rectangle<int> bounds, const String& filename) +{ + auto screenshot = editor->createComponentSnapshot (bounds); + + File pngFile = getScreenshotFolder().getChildFile (filename); + pngFile.deleteFile(); + pngFile.create(); + auto pngStream = pngFile.createOutputStream(); + + if (pngStream->openedOk()) + { + PNGImageFormat pngImage; + pngImage.writeImageToStream (screenshot, *pngStream.get()); + } +} + +} // ScreenshotHelper + +#endif // TAKE_SCREENSHOTS diff --git a/Plugin/Source/GUI/ScreenshotHelper.h b/Plugin/Source/GUI/ScreenshotHelper.h @@ -0,0 +1,27 @@ +#ifndef SCREENSHOTHELPER_H_INCLUDED +#define SCREENSHOTHELPER_H_INCLUDED + +// #define TAKE_SCREENSHOTS + +#ifdef TAKE_SCREENSHOTS + +// weird hack, but I need acces to some private +// member variables from foleys::Container +#define _XKEYCHECK_H +#define private public +#include "../PluginProcessor.h" +#define private private + +namespace ScreenshotHelper +{ + /** Take a series of screenshots used for the plugin documentation */ + void takeScreenshots (std::unique_ptr<ChowtapeModelAudioProcessor> plugin); + + /** Take a single screenshot for a given rectangle */ + void screenshotForBounds (Component* editor, Rectangle<int> bounds, const String& filename); + +} // ScreenshotHelper + +#endif // TAKE_SCREENSHOTS + +#endif // SCREENSHOTHELPER_H_INCLUDED diff --git a/Plugin/Source/PluginProcessor.cpp b/Plugin/Source/PluginProcessor.cpp @@ -13,6 +13,7 @@ #include "GUI/TitleComp.h" #include "GUI/TooltipComp.h" #include "GUI/MixGroupViz.h" +#include "GUI/ScreenshotHelper.h" namespace { @@ -321,5 +322,9 @@ void ChowtapeModelAudioProcessor::setStateInformation (const void* data, int siz // This creates new instances of the plugin.. AudioProcessor* JUCE_CALLTYPE createPluginFilter() { +#ifdef TAKE_SCREENSHOTS + ScreenshotHelper::takeScreenshots (std::make_unique<ChowtapeModelAudioProcessor>()); +#endif + return new ChowtapeModelAudioProcessor(); } diff --git a/Plugin/screenshot.png b/Plugin/screenshot.png Binary files differ. diff --git a/Simulations/Hysteresis/bias.png b/Simulations/Hysteresis/bias.png Binary files differ. diff --git a/Simulations/Hysteresis/drive.png b/Simulations/Hysteresis/drive.png Binary files differ. diff --git a/Simulations/Hysteresis/hysteresis2.py b/Simulations/Hysteresis/hysteresis2.py @@ -0,0 +1,57 @@ +# %% +from audio_dspy.hysteresis import Hysteresis +import numpy as np +import matplotlib.pyplot as plt +import audio_dspy as adsp + +FS = 96000 + +# %% +# drive plot +WIDTH = 1.0 +SAT = 0.5 + +legend = [] +for DRIVE in [0.0, 0.25, 1.0]: + hyst = adsp.Hysteresis(DRIVE, SAT, WIDTH, FS, mode='NR4') + adsp.plot_dynamic_curve(hyst.process_block, freq=10, fs=FS, gain=3, num=10000) + legend.append(f'Drive = {DRIVE}') + +plt.legend(legend) +plt.grid() +plt.title('Hysteresis Drive') +plt.tight_layout() +plt.savefig('drive.png') +# %% +# saturation plot +WIDTH = 1.0 +DRIVE= 1.0 + +legend = [] +for SAT in [0.0, 0.4, 0.8]: + hyst = adsp.Hysteresis(DRIVE, SAT, WIDTH, FS, mode='NR4') + adsp.plot_dynamic_curve(hyst.process_block, freq=10, fs=FS, gain=3, num=10000) + legend.append(f'Sat. = {SAT}') + +plt.legend(legend) +plt.grid() +plt.title('Hysteresis Saturation') +plt.tight_layout() +plt.savefig('sat.png') +# %% +# width plot +SAT = 0.9 +DRIVE= 1.0 + +legend = [] +for WIDTH in [0.0, 0.67, 1.0]: + hyst = adsp.Hysteresis(DRIVE, SAT, WIDTH, FS, mode='NR4') + adsp.plot_dynamic_curve(hyst.process_block, freq=10, fs=FS, gain=1, num=10000) + legend.append(f'Bias = {1-WIDTH:.2f}') + +plt.legend(legend) +plt.grid() +plt.title('Hysteresis Bias') +plt.tight_layout() +plt.savefig('bias.png') +# %% diff --git a/Simulations/Hysteresis/sat.png b/Simulations/Hysteresis/sat.png Binary files differ. diff --git a/Simulations/Hysteresis/space_loss.png b/Simulations/Hysteresis/space_loss.png Binary files differ. diff --git a/Simulations/Hysteresis/speed_thickness.png b/Simulations/Hysteresis/speed_thickness.png Binary files differ. diff --git a/Simulations/LossEffects/loss_effects2.py b/Simulations/LossEffects/loss_effects2.py @@ -4,7 +4,7 @@ import matplotlib.pyplot as plt from scipy import signal # %% -FREQS = np.logspace(1.3, 4.3, 50) +FREQS = np.logspace(1.3, 4.3, 200) N = 128 FS = 48000.0 f = np.linspace (0, FS, N) @@ -56,27 +56,38 @@ def spacing_loss(tape_speed_ips, dist_meter, freqs): for dist in [1.0e-6, 5e-6, 10e-6]: for SPEED in [7.5]: #, 15, 30]: space_loss = spacing_loss(SPEED, dist, FREQS) - plt.semilogx(FREQS, gain_to_db(space_loss), label=f'{SPEED}, {dist}') - plot_test(SPEED, lambda k : np.exp(-k * dist)) - -# plt.ylim(-6, 0) -# plt.ylim(0, 3.5) -plt.legend() -plt.title('Spacing Loss') + plt.semilogx(FREQS, gain_to_db(space_loss), label=f'{dist*1.0e6:.1f} microns') + # plot_test(SPEED, lambda k : np.exp(-k * dist)) + +plt.ylim(-5, 0.5) +plt.xlim(20, 20.e3) +plt.xlabel('Frequency [Hz]') +plt.ylabel('Magnitude [db]') +plt.legend(loc='lower left') +plt.grid() +plt.title('Spacing Loss, 7.5 ips') +plt.tight_layout() +plt.savefig('space_loss.png') # %% def thickness_loss(tape_speed_ips, thick_meter): K = freq_to_k(tape_speed_ips, FREQS) return (1 - np.exp(-1 * K * thick_meter)) / (K * thick_meter) -for thick in [1.0e-6, 10.e-6]: - for SPEED in [7.5, 15, 30]: +for thick in [5.0e-6]: # [1.0e-6, 5.0e-6, 10.e-6, 15.0e-6]: + for SPEED in [3.75, 7.5, 15, 30]: loss = thickness_loss(SPEED, thick) - plt.semilogx(FREQS, gain_to_db(loss), label=f'{SPEED}, {thick}') - -plt.ylim(-6, 1) -plt.legend() -plt.title('Thickness Loss') + plt.semilogx(FREQS, gain_to_db(loss), label=f'{SPEED:.2f} ips') + +plt.ylim(-3, 0.5) +plt.xlim(20, 20.e3) +plt.xlabel('Frequency [Hz]') +plt.ylabel('Magnitude [db]') +plt.legend(loc='lower left') +plt.grid() +plt.title('Thickness Loss, 5 microns') +plt.tight_layout() +plt.savefig('speed_thickness.png') # %% def gap_loss(tape_speed_ips, gap_meter): K = freq_to_k(tape_speed_ips, FREQS) @@ -96,7 +107,7 @@ def head_bump(tape_speed_ips, gap_meter): bump_freq = tape_speed_ips * 0.0254 / (gap_meter * 5e2) print(bump_freq) width = bump_freq * 0.4 - gain = 1.5 * (2e3 - abs(bump_freq - 100)) / 2e3 + gain = 1.1 * (2e3 - abs(bump_freq - 100)) / 2e3 A = -(gain - 1) / (width/ 2)**2 H = np.zeros_like(FREQS) for i, f in enumerate(FREQS): @@ -106,13 +117,16 @@ def head_bump(tape_speed_ips, gap_meter): H[i] = max(A * (f - bump_freq)**2 + gain, 1) return H +# %% for gap in [5.0e-6, 10.0e-6, 20.e-6]: - for SPEED in [7.5, 15, 30]: - loss = head_bump(SPEED, gap) - plt.semilogx(FREQS, gain_to_db(loss), label=f'{SPEED}, {gap}') - -# plt.ylim(-6, 0) -plt.legend() -plt.title('Head Bump') + for SPEED in [15]: #, 15, 30]: + loss = head_bump(SPEED, gap) * gap_loss(SPEED, gap) + plt.semilogx(FREQS, gain_to_db(loss), label=f'{gap*1.0e6:.1f} microns') + +plt.ylim(-6, 2.0) +plt.xlim(20, 20.e3) +plt.legend(loc='lower left') +plt.grid() +plt.title('Gap Loss') # %% diff --git a/Simulations/LossEffects/space_loss.png b/Simulations/LossEffects/space_loss.png Binary files differ. diff --git a/Simulations/LossEffects/speed_thickness.png b/Simulations/LossEffects/speed_thickness.png Binary files differ.