3 # Copyright (C) 2010 Kipp Cannon
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 # Public License for more details.
15 # You should have received a copy of the GNU General Public License along
16 # with this program; if not, write to the Free Software Foundation, Inc.,
17 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 # A program to make a movie of power spectral densities taken over time
23 # =============================================================================
27 # =============================================================================
31 from optparse
import OptionParser
40 from gstlal
import simplehandler
41 from gstlal
import pipeparts
42 from gstlal
import datasource
45 from glue
import segments
46 from pylal.datatypes
import LIGOTimeGPS
50 # =============================================================================
54 # =============================================================================
58 def parse_command_line():
59 parser = OptionParser(
60 description =
"%prog generates an animated view of the PSD measured from h(t). The video can be shown on the screen or saved to a OGG Theora movie file. Example:\n\n%prog \\\n\t--frame-cache \"/home/kipp/scratch_local/874100000-20000/cache/874100000-20000.cache\" \\\n\t--instrument \"H1\" \\\n\t--channel-name \"LSC-STRAIN\" \\\n\t--gps-start-time 874100000.0 \\\n\t--gps-end-time 874120000.0 \\\n\t--psd-fft-length 8.0 \\\n\t--psd-zero-pad-length 0.0 \\\n\t--average-length 64.0 \\\n\t--median-samples 3 \\\n\t--frame-rate 10/1 \\\n\t--output spectrum_movie.ogm \\\n\t--verbose"
62 # generic
"source" options
64 parser.add_option(
"--sample-rate", metavar =
"Hz", type =
"float", default = 8192.0, help =
"Downsample the data to this sample rate. Default = 8192 Hz.")
65 parser.add_option(
"--psd-fft-length", metavar =
"seconds", type =
"float", default = 8.0, help =
"Set the length of the FFT windows used to measure the PSD (optional).")
66 parser.add_option(
"--psd-zero-pad-length", metavar =
"seconds", type =
"float", default = 0.0, help =
"Set the length of zero-padding in the FFT windows used to measure the PSD (optional).")
67 parser.add_option(
"--average-length", metavar =
"seconds", type =
"float", default = 64.0, help =
"Set the time scale for the running mean (optional). Default = 64.0.")
68 parser.add_option(
"--median-samples", metavar =
"samples", type =
"int", default = 5, help =
"Set the number of samples in the median history (optional). Default = 5.")
69 parser.add_option(
"--f-min", metavar =
"Hz", type =
"float", default = 10.0, help =
"Set the lower bound of the spectrum plot's horizontal axis. Default = 10.0.")
70 parser.add_option(
"--f-max", metavar =
"Hz", type =
"float", default = 4000.0, help =
"Set the upper bound of the spectrum plot's horizontal axis. Default = 4000.0.")
71 parser.add_option(
"--output", metavar =
"filename", help =
"Set the name of the movie file to write (optional). The default is to display the video on screen.")
72 parser.add_option(
"-v",
"--verbose", action =
"store_true", help =
"Be verbose (optional).")
74 options, filenames = parser.parse_args()
76 if options.f_max <= options.f_min:
77 raise ValueError,
"--f-max must be >= --f-min"
79 return options, filenames
83 # =============================================================================
87 # =============================================================================
96 options, filenames = parse_command_line()
100 # parse the generic
"source" options, check for inconsistencies is done inside
101 # the class init method
105 gw_data_source_info = datasource.GWDataSourceInfo(options)
106 if len(gw_data_source_info.channel_dict) != 1:
107 raise ValueError(
"can only specify one channel, one instrument")
108 instrument, = gw_data_source_info.channel_dict.keys()
116 def build_pipeline(pipeline, head, sample_rate, psd_fft_length, psd_zero_pad_length, average_length, median_samples, (f_min, f_max), verbose = False):
117 head = pipeparts.
mkresample(pipeline, head, quality = 9)
118 head = pipeparts.
mkcapsfilter(pipeline, head,
"audio/x-raw-float, rate=%d" % sample_rate)
119 head = pipeparts.
mkwhiten(pipeline, head, fft_length = psd_fft_length, zero_pad = psd_zero_pad_length, average_samples = int(round(average_length / (psd_fft_length / 2) - 1)), median_samples = median_samples)
121 head = pipeparts.
mkqueue(pipeline, head.get_pad(
"mean-psd"), max_size_buffers = 4)
123 head = pipeparts.mkspectrumplot(pipeline, head, f_min = f_min, f_max = f_max)
124 head = pipeparts.
mkcapsfilter(pipeline, head,
"video/x-raw-rgb, width=768, height=320")
129 # construct and run pipeline
133 mainloop = gobject.MainLoop()
134 pipeline = gst.Pipeline(
"spectrum-movie")
135 handler = simplehandler.Handler(mainloop, pipeline)
138 head = datasource.
mkbasicsrc(pipeline, gw_data_source_info, instrument, verbose = options.verbose)
139 head = build_pipeline(
143 options.psd_fft_length,
144 options.psd_zero_pad_length,
145 options.average_length,
146 options.median_samples,
147 (options.f_min, options.f_max),
148 verbose = options.verbose
150 if options.output is not None:
151 pipeparts.mkogmvideosink(pipeline, head, options.output, verbose = options.verbose)
153 pipeparts.mkvideosink(pipeline, pipeparts.mkcolorspace(pipeline, head))
161 if pipeline.set_state(gst.STATE_PLAYING) == gst.STATE_CHANGE_FAILURE:
162 raise RuntimeError(
"pipeline failed to enter PLAYING state")