How can I get the Stockwell transform of an earthquake data in MATLAB?
10 views (last 30 days)
Show older comments
Dear, I was wondering does MATLAB have any tool to calculate the Stockwell transform ? If it exists in MATLAB library, can you please provide me a script code so I can get S-tranform of an earthquake data. Thanks for your help. Regards
0 Comments
Accepted Answer
dpb
on 19 Mar 2025
See if one of the following File Exchange submittals suits...
2 Comments
dpb
on 19 Mar 2025
Edited: dpb
on 22 Mar 2025
The code for the last above does run, albeit it is pretty lacking in style and formatting that could make it much easier to read. I did take the time to insert the missing end statements at the end of the various functions; there should be one for st at about line 145 (just after a return statement) that isn't needed.
Then another for function strans about 235; there's a comment about "end strans function".
About line 263 for function g_window
About line 305 for function check_input (comment about "bloody odd how you don't end function" shows lack of MATLAB expertise by the original author)
Last for function st_help at the very end of the file.
Not mandatory, but a lot cleaner code that way...the one thing is if add one, must add them all; can't mix metaphors in style within on m file.
More Answers (1)
dpb
on 19 Mar 2025
Edited: dpb
on 20 Mar 2025
What errors?
I have none of these downloaded and don't know of any specific others...and, personally, am not familiar with the Stockwell transform.
Well, I downloaded the last of the above but used the original st function directly rather than the poster's version that uses imcomplement on the output as I didn't see the purpose.
I then used the quake.mat file distributed with MATLAB and ran the E-W acceleration through it ---
>> EQ=load('quake');
>> [ST,t,f]=st(EQ.e,0,100,1/200);
Minfreq = 0
Maxfreq = 100
Sampling Rate (time domain) = 5.000000e-03
Sampling Rate (freq. domain) = 1
The length of the timeseries is 10001 points
The number of frequency voices is 101
Calculating analytic signal (using Hilbert transform)
Estimated time is 0.078174Calculating S transform...
Finished Calculation
>> imagesc(t,f,abs(ST))
>> xlabel('Frequency, Hz')
>> ylabel('Time (s)')
>> title('Oct17, 1989 Loma Prieta earthquake E-W ground motion')
>>
with the result attached...looks as though it worked to me, albeit I've never used the transform so don't really know anything about it other than it is another of the time-frequency separation tools.
ADDENDUM
Above with the suggested change to use
analytic_signal=isreal(timeseries);
instead of the hardcoded FALSE and the correct Nyquist frequency for the actual input timeseries. You'll observe the image is the same other than the y axis labels...
12 Comments
dpb
on 22 Mar 2025
Edited: dpb
on 22 Mar 2025
%% Main RUN
load ImperialValley.txt; %% the data is attached below (at the bottom of this email)
EQ=Imperial(:,2);
time=Imperial(:,1);
dt = mean(diff(time));
minfreq=-10;
maxfreq=10 ;
samplingrate=1/dt ;
[ST,t,f]=stockwell_transform_st(EQ,minfreq,maxfreq,samplingrate);
I'd probably do the initial something like
tIV=readtable('ImperialValley.txt'); % tables are convenient for viewing as well as using...
tIV.Properties.VariableNames={'Time','Accel'}; % add convenient names
head(tIV) % take a look at what we have...
dt=mean(diff(tIV.Time)); % now use the table variables
plot(tIV.Time,tIV.Accel) % look at the time trace
...
That's just convenient way to have the data; has no bearing on the actual calculations other than what choice make in how to read/handle it...
As to the transform, as noted before I have never used the Stockman transform (hadn't actually even heard of it before), so I'm certainly not well versed in it or its application and all I can do is presume Stockman knew how to implement what he intended.
That said, there are some things in the code that seem peculiar but I don't have the time to try to research the topic sufficiently to fully understand -- the foremost of those is his use of the FREQSAMPLINGRATE input and resultant calculation of the returned frequency vector; you'll need to dig into that and understand what is being done there.
minfreq=-10;
There is no such thing as a negative frequency here; there is in a two-sided FFT, but not here. It appears you've taken the exponent of the lower limit of the log range of the sample figure here instead; if you note the output of the function, it caught the negative Minfreq and set it to zero.
maxfreq=10 ;
samplingrate=1/dt ;
The sampling rate input is documented in the usage as
"SAMPLINGRATE - the time interval between successive data points"
so it should be dt, not 1/dt. Changing that will make the time axis of the plot look as you expect. It looks like you again copied my prior code where I used 1/Fs, but Fs was the sampling RATE of the signal, 200 Hz, so 1/FS --> dt.
There is an issue in the way Mr/Dr? Stockwell wrote this code in that one cannot use fractional frequencies such as 0.1 for minFreq or maxFreq; the code uses an internal colon operation between the two that breaks if the difference isn't an integer.
I suspect one could figure out and modify this code base to handle the binning more elegantly and with investigation of the internal width factor on the gaussian window to get what appears to be finer resolution in the time domain in the reference; as noted above, those details between this code and that author's are all pieces that will take researching to be able to duplicate one from the other.
As noted, there are other implementations of what appear to be the same idea on the File Exchange, there's also a C version of the algorithm I found in a google search that can be turned into a mex file and called from MATLAB.
I'm sorry, but I simply don't have the time to spare to investigate more fully; if you need something like this and don't feel you have the programming skills to do so yourself, you might try contacting the author of the other paper and see if they have supporting code available.
ERRATUM:
The output display of the version I uploaded will be much more readable if you will search for each line containing fprintf and add a \n to the end of the format string; one cleanup I did was to use the MATLAB suggestion to fix the use of the disp(sprintf(...)) idiom automatically; the problem is their builtin fix doesn't add the trailing newline into the format string that disp() inserts automagically so those lines run on instead of showing as separate lines...at some point I'll upload a new version with that correction, but there are <10 lines and it's a trivial edit to make.
Good luck...
See Also
Categories
Find more on Audio Toolbox in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!