<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Richard Strange</title>
    <description>The latest articles on DEV Community by Richard Strange (@rstrange).</description>
    <link>https://dev.to/rstrange</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F223715%2F5d2491bc-3031-487c-b1f4-f8b52c17b431.png</url>
      <title>DEV Community: Richard Strange</title>
      <link>https://dev.to/rstrange</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rstrange"/>
    <language>en</language>
    <item>
      <title>Agile development in academia: how do you teach a dinosaur new tricks?</title>
      <dc:creator>Richard Strange</dc:creator>
      <pubDate>Wed, 11 Sep 2019 16:52:55 +0000</pubDate>
      <link>https://dev.to/rstrange/agile-development-in-academia-how-do-you-teach-a-dinosaur-new-tricks-5fjb</link>
      <guid>https://dev.to/rstrange/agile-development-in-academia-how-do-you-teach-a-dinosaur-new-tricks-5fjb</guid>
      <description>&lt;p&gt;One of the most significant challenges I faced when switching back into academia wasn't living on a stipend, or volume of papers I had to read. It was trying to apply my working practices into a workplace that had no understanding or compatibility with an agile way of working. It was, for lack of a better analogy, like trying to change gears on a car without using a clutch. &lt;/p&gt;

&lt;p&gt;Parts of the academic process can date back to the early Royal Society. While there are still areas of industry that are slow to adopt agile practices, academia is almost devoid of project management. Instead of team effort and defined scopes of work, solo heroics and gut instinct are the de facto standard. That is slowly changing, however. &lt;/p&gt;

&lt;p&gt;I was inspired to write this post when I saw a recent &lt;a href="https://www.nature.com/articles/d41586-019-02620-6"&gt;&lt;em&gt;nature&lt;/em&gt; article&lt;/a&gt; looking at how scrum and agile methodology are slowly bleeding into some research teams. I had two conflicting reactions to the piece.&lt;/p&gt;

&lt;p&gt;Firstly, that this seemed like a cargo cult - with the teams simply mimicking the methodologies, rather than grokking them. When I read the testimonies, it appeared that stand-ups were used well to improve cross-team communication. However, sprints weren't really accepted, and there was no sign of any Kanban or any workload management.&lt;/p&gt;

&lt;p&gt;But the longer I thought over it, the more I realised that perhaps the shoe simply doesn't fit that easily. Often, researchers produce knowledge, not products. Breakthroughs are sporadic, not predictable. &lt;/p&gt;

&lt;p&gt;So, would I agree that the methodologies were implemented well in an academic setting? Probably not. But conversely, I wouldn't say that the techniques are totally unfit for purpose. Rather, there is space in the sector for some fundamental changes in their way of working. But these practices have to be a form of Agile/Kanban/Scrum/... that suits researchers and professors, not programmers and project managers.&lt;/p&gt;

&lt;p&gt;So, my question to the community is this. What do you guys think are the most valuable practices or philosophies in an agile way of working? What sections of the process are essential to generalised project success? And what loses relevance and we step away from software development?&lt;/p&gt;

&lt;p&gt;Personally, I suspect there's a lot of value in looking into writing requirements in an academic setting, but what are your thoughts?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Image rights:&lt;br&gt;
"DSCN2607" by &lt;a href="http://www.flickr.com/photos/99175152@N00"&gt;heyjupiter&lt;/a&gt; is licensed under &lt;a href="https://creativecommons.org/licenses/by-nc-sa/2.0/?ref=ccsearch&amp;amp;atype=html"&gt;CC BY-NC-SA 2.0&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>discuss</category>
      <category>agile</category>
      <category>research</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How to turn volcanic earthquakes into meaningful data with a little Python</title>
      <dc:creator>Richard Strange</dc:creator>
      <pubDate>Thu, 05 Sep 2019 17:47:39 +0000</pubDate>
      <link>https://dev.to/rstrange/visualising-volcanoseismic-events-an-exercise-in-signal-processing-5gal</link>
      <guid>https://dev.to/rstrange/visualising-volcanoseismic-events-an-exercise-in-signal-processing-5gal</guid>
      <description>&lt;h1&gt;
  
  
  tl;dr
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;I'm not a good programmer but I think I do interesting things. One of those things is researching volcanic eruptivity. Magma pushing up creates earthquakes and I use sensor readings of those earthquakes to do my research.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;the code I need extract the features I need is:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;libraries&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;#read in the raw data
&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;../Data/Specimen_Event.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index_col&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;#The output from the raw data isn't too useful, so let's look at the constituent frequencies
&lt;/span&gt;
&lt;span class="n"&gt;fft_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;y_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amplitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;time_interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt; 

&lt;span class="n"&gt;yf_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_values&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;x_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fftfreq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;time_interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;xf_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fftfreq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;time_interval&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="c1"&gt;#The frequency data is useful, but we've lost all temporal information - let's just take time slices and transform those, and glue it back together like a histogram - aka a seismogram
&lt;/span&gt;
&lt;span class="n"&gt;window_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;

&lt;span class="n"&gt;recording_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amplitudes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spectrogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amplitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recording_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hanning&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nperseg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noverlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detrend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scaling&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spectrum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;decibels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amplitudes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pcolormesh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decibels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viridis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;This shows me both events, and a hidden pattern at 38Hz. This can be used to conjecture that we have a magma chamber of around ~150 metres.&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Where do I start?
&lt;/h1&gt;

&lt;p&gt;I'll try to start this post like I try to start my work - by managing expectations and being honest about my capabilities. I'm not a 10x engineer &lt;em&gt;(&lt;a href="https://dev.to/pbeekums/the-problem-with-heroes-in-software-development"&gt;if you believe in that myth&lt;/a&gt;)&lt;/em&gt; or anything near it, nor am I a laser-focused senior dev with years of open-source contributions. I won't change the way you code or the way you approach your work.&lt;/p&gt;

&lt;p&gt;What I am, instead is a fence-sitter with a habit of flip-flopping between industry and academia; enough experience to know when I'm writing honkingly bad code (even if I can't stop myself from doing it the first place), but enough time in research to get to apply my mediocre skills onto something a bit different - in particular, volcanoes!&lt;/p&gt;

&lt;p&gt;So, how exactly does volcanology dip into programming? Well, over the years, there have been breakthroughs in how we observe volcanic unrest - and more than that, changes in how we &lt;em&gt;measure&lt;/em&gt; it too, and that's the crucial part. to misquote Arnie: &lt;em&gt;"If it quantifies, we can analyse it"&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/eNr0WXQ3Ho4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;So, what are we measuring? It's hard to peer inside a volcano, and we can't drill into an active volcano to get sample data. But we do have some proxies we can measure instead that give us hints, and one of the best ones is something called seismicity - the earthquake activity from the volcano. We can't have an eruption without magma getting to the surface (or at least somewhat close), but there are no nice easy pre-drilled pipes for them to follow. Every inch of vent has to be split from the surrounding rock, sometimes for kilometres.&lt;/p&gt;

&lt;p&gt;This injection of magma is quite an energetic and noisy affair and one we can pick up. These small fractures create very shallow, distinct, localised earthquakes that we can pick up with seismometers - tilt/accelerometers measuring movement in the ±x, ±y, and ±z axes.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cut the crap, show me the code
&lt;/h1&gt;

&lt;p&gt;So, what's the point of this post? Well, it's all very well knowing that these earthquakes are happening, but how do we understand them?&lt;/p&gt;

&lt;p&gt;We start where we always do, by looking at the data, but first, let's get the libraries we'll need in.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;pandas&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;numpy&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;matplotlib.pyplot&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;numpy.fft&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="c1"&gt;# a library for carrying out Fourier Transforms
&lt;/span&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;scipy&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt; &lt;span class="c1"&gt;# further FFT functionality
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;for those of you who want to code along at home, I've included pointers to the specimen data and a notebook at the bottom&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, we need to get our data in. It's available as a simple time-series csv, which makes ingestion very easy, and as we're only loading in one example we're not worried about scaling this up, so we have no reason not to use &lt;code&gt;pandas&lt;/code&gt; and make our lives easier.&lt;/p&gt;

&lt;p&gt;Once we have our data loaded, we'll plot the raw data quickly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;input_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;../Data/Specimen_Event.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;index_col&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Seconds&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;lw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which gives us&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fraw_seismic_plot.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fraw_seismic_plot.png%3Fraw%3Dtrue" title="Plot of a single volcanic earthquake event" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We seem to be lucky enough to have two events in the same 300-second window; you can see one smaller event, followed by a larger one. But it's difficult to tell more than that for sure. We need a better way to understand the sensor readings. &lt;/p&gt;

&lt;p&gt;What we saw in the plot was amplitude against time. When we treat the same data as a sound file and listen to it, we wouldn't just hear a rumble, but we'd be able to pick out deeper and higher frequency parts to it too. Thankfully, there is a way to mathematically pick out frequencies - the Fourier Transformations.&lt;/p&gt;

&lt;p&gt;I'll leave the detailed explanation for a later post, but suffice to say that we can turn an &lt;em&gt;amplitude vs. time&lt;/em&gt;  plot, where we see the amount of energy recorded once per 0.01 seconds, to an &lt;em&gt;amplitude vs. frequency&lt;/em&gt; plot, where we see the amount of energy across the datafile &lt;em&gt;per frequency&lt;/em&gt;. You usually hear people refer to these as being in either the &lt;em&gt;temporal-&lt;/em&gt; or &lt;em&gt;time-domain&lt;/em&gt; and the &lt;em&gt;frequential-&lt;/em&gt; or &lt;em&gt;frequency-domain&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We're using the &lt;code&gt;SciPy/NumPy&lt;/code&gt; library's fast Fourier transform functions to convert our event into the frequency domain.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;fft_df&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;y_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fft&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amplitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;time_interval&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.01&lt;/span&gt; &lt;span class="c1"&gt;#the seismometers for this recording sample 100 times a second
&lt;/span&gt;
&lt;span class="n"&gt;yf_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;abs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;y_values&lt;/span&gt;&lt;span class="p"&gt;[:&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;span class="n"&gt;x_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fftfreq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;time_interval&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;xf_values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;fftfreq&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;time_interval&lt;/span&gt;&lt;span class="p"&gt;)[:&lt;/span&gt;&lt;span class="n"&gt;no_of_datapoints&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;xf_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;yf_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;lw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Frequency [Hz]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Amplitude&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fast Fourier Transform for Specimen event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We'll go through the steps here in detail in a later post, but in essence, we are calculating the amplitude by an arbitrary periodicity, but we need to independently work out the actual frequencies we're seeing (our x-axis, the frequencies all dependent on the number of data points and the rate of recording) using the &lt;code&gt;fftfreq&lt;/code&gt; function. There's a little juggling of having to feed in a halved, even-length range. Again, more on this in a later post.&lt;/p&gt;

&lt;p&gt;This leaves us with this plot:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Ffft_seismic_plot.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Ffft_seismic_plot.png%3Fraw%3Dtrue" title="Fourier plot of the event" alt="alt-text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can now see the distribution of frequencies in the event. There is a lot of low frequency rumbling between the 1 - 30 Hz region. The human hearing range starts at around 20Hz, so this is relatively low. But there is a trend. &lt;/p&gt;

&lt;p&gt;The only problem now is that by moving the data into the frequency domain, we've lost any information about how the event changes over time. The answer to this is to slice the event up into narrow, slightly overlapping windows, and running the same Fourier transformations over these windows individually. We can then stack these together as a form of a histogram with both frequency and time information, known as a &lt;em&gt;spectrogram&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;There is a pay-off though - the shorter a sample, the less accurate and sensitive a Fourier transform is, but longer samples leave us with a poorer time resolution. One other thing we need to keep in mind is that it's computationally more efficient to use 2^n window sizes.&lt;/p&gt;

&lt;p&gt;We could do this manually with the same code we ran before, but we'll use a short-cut: a prebuilt SciPy library that will run the transforms and prep them for us to visualise.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;window_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;256&lt;/span&gt;

&lt;span class="n"&gt;recording_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;

&lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;amplitudes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;signal&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;spectrogram&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;input_df&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Amplitude&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;recording_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;window&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;hanning&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;nperseg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;noverlap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;window_size&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;detrend&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;scaling&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;spectrum&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;decibels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log10&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;amplitudes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subplots&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pcolormesh&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;frequencies&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;decibels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cmap&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;viridis&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_ylabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Frequency $kHz$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_xlabel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Time $s$&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Fast Fourier Transform for Specimen event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fseismogram_plot.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fseismogram_plot.png%3Fraw%3Dtrue" title="seismogram of the volcanic event" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  So what?
&lt;/h2&gt;

&lt;p&gt;Well, the effort of recapturing the time trends of the data in the frequency domain paid off. What we can see in the last graph, is time progressing as you move right, and the recording getting higher in frequency as you go up - the brighter the colour, the more energy. We can see both events quite clearly, but there's one pattern that's less obvious, but more exciting. &lt;/p&gt;

&lt;p&gt;If you haven't spotted it, there is a band of information at around ~38Hz that gets quite active after 150 seconds. It's difficult to be confident of what we're seeing, but we have two possibilities. The more mundane answer is that there is some background noise - like storms in the ocean, that has resonated up into this band - a frequency-echo. A signal sitting so consistently at ~38Hz would support this mechanism. &lt;/p&gt;

&lt;p&gt;However, ocean noise is usually no higher than ~0.14Hz. Finding it as high as 38Hz is unlikely. While there are many other sources of noise, there aren't many that are &lt;strong&gt;that&lt;/strong&gt; consistent as to stay at precisely that frequency range.&lt;/p&gt;

&lt;p&gt;The other answer is that after these more significant events, magma often resettles and moves into spaces in the new cracks, and the pressure in the chamber resettles. As the signal appears more after the events and it's quite continuous, it's more likely to be the sloshing of magma than to be a single brittle failure.&lt;/p&gt;

&lt;p&gt;Let's go on a last flight of fancy. I am not claiming that this last part is anything but conjecture, so sceptics avert your eyes!&lt;/p&gt;

&lt;p&gt;Oddly, the signal is so consistent in frequency, so it might be that it's acting like the wind across a beer bottle. When the speed of the wind is fast enough across the aperture it whistles and resonates. In our case, it might be the other way around - that the aperture is the right size for the pressure waves.&lt;/p&gt;

&lt;p&gt;So perhaps we can derive something about the shape of the magma chamber? If the chamber is a particular length or breadth, it'll resonate at a specific frequency related to its wavelength.&lt;/p&gt;

&lt;p&gt;We know that the frequency &lt;em&gt;f&lt;/em&gt;, and we want the wavelength &lt;em&gt;lambda&lt;/em&gt;. The last thing we need to know is the speed of sound through magma - and while it's a varying number, for a back of the envelope calculation let's say 5km per second.&lt;/p&gt;

&lt;p&gt;Let's do the maths:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fmaths.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2FR-Strange%2FDEV-TO-posts%2Fblob%2Fmaster%2F190904_VisualisingVolcanoseismicEvents%2FImages%2Fmaths.png%3Fraw%3Dtrue" title="mathematical steps for finding a 131m chamber" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So to round it off, we can estimate that some dimension of the chamber or vent or pipe that was fracturing, was around 131 metres in dimension - all from an audio clip!&lt;/p&gt;

&lt;h1&gt;
  
  
  Resources
&lt;/h1&gt;

&lt;p&gt;For those of you wanting to play along at home, you can find the data &lt;a href="https://github.com/R-Strange/DEV-TO-posts/blob/master/190904_VisualisingVolcanoseismicEvents/Data/Specimen_Event.csv" rel="noopener noreferrer"&gt;here&lt;/a&gt; and a notebook &lt;a href="https://github.com/R-Strange/DEV-TO-posts/blob/master/190904_VisualisingVolcanoseismicEvents/Code/Example%20Notebook.ipynb" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>research</category>
    </item>
  </channel>
</rss>
